Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

config.yaml

The configuration is one folder: ~/.config/sandcastle, or $SANDCASTLE_CONFIG, or the folder given with --config DIR.

config.yaml          the general settings and the toolbox
sources/<name>.yaml  one file per source

It holds no secret, so it can be kept in version control. examples/config.yaml and examples/sources/notes.yaml are a complete configuration to start from.

Every problem is reported at once, by check, install and the core when it starts, with the file and the key. A key the program does not know is an error, so a typo is never ignored. A folder with no file in sources/ is an error.

General settings

The keys at the top of config.yaml.

KeyDefaultWhat it sets
data_dir~/.local/share/sandcastle/jobswhere each job’s record is kept; see Files and folders. A folder that holds the secrets folder, or lies inside it, is refused
retention_days30records older than this many days are deleted; at least 1
capabilitiesnoneone block per capability of the toolbox, claude and ocr; see below

Destinations

Each source, and the claude capability, has a destination block: the one place it may reach, and the secret sent there.

destination:
  address: https://notes.example.com/api/worker
  secret: notes
KeyDefaultWhat it sets
destination.addressrequiredhttps:// and a full domain name, with an optional port (443 for https://, 80 for http://) and path. No IP address, wildcard, range, user, password, query or fragment. http:// only with internal
destination.secretrequiredthe name of a secret
destination.internalnoneone ip:port inside your network that the address’s name stands for; see Reach a service inside your network

The gate’s list of names is made from the destinations: nothing else can be reached.

Sources

One file per source, in sources/. Every key is required.

KeyDefaultWhat it sets
namerequiredthe source’s name, and its destination’s. No slashes, dots or spaces, not claude or ocr, and not another source’s
destinationrequiredwhere the source is, and its secret; see Destinations
poll_intervalrequiredhow often the source is asked for jobs; at least 1s
capabilitiesrequiredthe capabilities the source may use, each enabled in config.yaml; a job for another fails
max_jobs_per_hourrequiredhow many jobs of this source run in an hour, at most; at least 1
job_timeoutrequiredhow long one job may run, its box included; at least 1s. Give it a little more than the capability’s timeout

claude

capabilities.claude in config.yaml. What a job sends and gets back is in claude.

KeyDefaultWhat it sets
enabledfalsewhether sources may use it
destinationrequiredthe Claude API, written by hand: https://api.anthropic.com, with the key’s secret
modelrequiredthe model every job asks, such as claude-haiku-5-5
effortlowhow hard the model works: low, medium, high, xhigh or max
max_tokens16000the longest reply; a reply cut off here fails the job
system_prompta fixed, generic onethe system prompt of every request
timeout5mhow long the job’s box may run, the request included
cooldown15mhow long the capability rests after a failure that is not the job’s
max_input256KiBthe largest job input, and the largest prompt sent
max_output1MiBthe largest line the box may write back
box.memory256MiBthe box’s memory, with no swap on top
box.cpus1the box’s processors
box.pids32the box’s processes
box.tmp16MiBthe size of /tmp, the box’s only writable folder

ocr

capabilities.ocr in config.yaml. What a job sends and gets back is in ocr. It reaches nothing outside its box, so a destination is refused.

KeyDefaultWhat it sets
enabledfalsewhether sources may use it
languagespor+engthe Tesseract languages, joined with +; only these go into the image
max_pixels25000000the largest image decoded; a larger one fails the job
max_edge2500the longest side an image is scaled down to before it is read
timeout30show long the job’s box may run
cooldown15mhow long the capability rests after a failure that is not the job’s
max_input16MiBthe largest job input; a larger one fails before a box starts
max_output1MiBthe largest line the box may write back
box.memory1GiBthe box’s memory, with no swap on top
box.cpus1the box’s processors
box.pids64the box’s processes
box.tmp64MiBthe size of /tmp, the box’s only writable folder

The box block of each capability holds its four limits. A limit above its default is allowed, and check warns of it: what the box then spends is outside the promise. No key opens a lock of the box; see How a job is boxed.

Values

  • A duration is a number and a unit: 30s, 15m, 1h30m.
  • A size is a number of bytes, plain or with KiB, MiB or GiB: 1024, 256KiB, 16MiB.
  • box.cpus is a number above 0, such as 1 or 0.5. box.pids is a whole number of at least 1.

Keys that are gone

A file that still has one of these is refused, with what replaces it.

KeyWhat replaces it
sandboxnothing: every job runs in a box of its own
tesseractnothing: Tesseract comes in the ocr box’s image
api_key_filesandcastle secret set claude, named in destination.secret
base_urldestination.address
token_filesandcastle secret set <name>, named in destination.secret