Skip to content

Limits and safeguards

Look up exact limits for a skipped file, a partial reply or a stopped program. For recovery steps, start with Troubleshooting; for what to review before collecting or sharing, see Privacy.

Size bounds

Resource Limit
bf.yaml, machine registry, eval suite 1 MiB each
YAML structure, including frontmatter 32 nesting levels and 20,000 parser events; integers up to 4,300 decimal digits in any base
Authored note 4 MiB
Note or record title 4,096 characters; listings show 200, then …
Note aliases, links, tags 1,000 each
Search or page reply Items end early near 32 KiB and continue at next_offset; home lists as many projects as fit the reply as printed, with projects_total
Any search or read reply 4 MiB; a larger one fails with response exceeds its byte limit; narrow the request
Exact read Text pages near 32 KiB; the first page adds all other fields, such as attributes
Paged note divided by headings Opens with 4 KiB of text; its outline lists up to 200 sections
Backlink previews 5 newest items per relation, excerpts of 160 characters; 64 relation groups, then backlinks_omitted
Source folder settle time 5 seconds: a memories/SOURCE folder changed more recently is listed again at each search or read
Claims of a subject 20 per relation and 50 in all
Record file 16 MiB
Record fields other than text 2 MiB as UTF-8 JSON, so an exact read's first page stays within the reply limit
Record id 1–4,096 characters and 7,988 once percent-encoded
Record text 4,194,304 characters
Record links, aliases, field names 1,000 each
Record URL, link, field value 8,192 characters
Listed field value 200 characters; longer values stay in the exact read
Listed fields of one item 2 KiB of JSON, in field-name order; later fields stay in the exact read
Entries per record source or authored folder 100,000
Folder depth 64 levels below a scanned folder
Note path 7,988 characters once percent-encoded
Search query 4,096 characters; the first 32 distinct words match
Search results per page 50
Page sizes Folders and tags 200; memories/SOURCE 20; other pages 50
Offsets 2^53−1
Skipped files per brain 200 listed in problems, each error cut to 1 KiB with …, then a count
Validation problems, warnings 200 each, then a *_truncated flag; 20 spellings per warning
Reasons named by one diagnostic The first 5 distinct reasons, then and N more
Relation targets 64 prefixes of at most 1,024 characters
Retrieval suites 100 suites per run, 200 cases per suite
Records changed by one collection 99,999; narrow the window or split the source
Reprojection 1,000 changed records per transaction; 200 failed records listed
Sensor output 64 MiB by default, up to 256 MiB
Action routine output 1 MiB by default, up to 4 MiB; a log routine's output only feeds its log
Routine or prompt input from bf run 1 MiB, ending within 10 seconds when piped
Prompt output 1 MiB by default, up to 4 MiB
Prompt file, expanded prompt 120,000 bytes each, as an argument or on standard input; below Linux's 128 KiB bound on one argument
Program name 64 characters
Program command The program and up to 127 arguments of at most 16,384 characters each
Routine hooks 16 events
Program timeout 1–3,600 seconds
refresh, lookback, overlap, reconcile, silent_after up to 365 days
keep 1–10,000 routine actions; 1–50,000 prompt records
Program log 1 MiB per logs/NAME.log; per run, the last 256 KiB of stderr and of a log routine's stdout

Each record takes one folder entry. bf status warns above 80,000 entries without failing --check; a tree over the limit fails the scan and names the folder. Split a crowded source's sensor or archive its older records, and keep bulky imports in inputs/ or originals/, which are not scanned. A long pasted question matches only its first 32 distinct words after function words are dropped: keep the distinctive terms.

Page sizes bound one reply, not the result: follow next_offset. SQLite still ranks every match up to a deep offset, so very deep pages take longer.

Processes and logs

Sensors, routines and prompts run from the brain folder with direct arguments, without a shell. Their standard input is closed, except for what a hook or bf run --stdin pipes to a routine and the expanded prompt of a prompt command without {{prompt}}. They receive BF_BRAIN set to that brain, so a nested bf call reads the brain running it.

BF removes environment variables that could load code before your program starts, such as BASH_ENV or PYTHONPATH:

Removed Reason
LD_*, DYLD_*, GCONV_PATH Can inject loader libraries or conversion modules.
BASH_ENV, ENV, BASH_FUNC_*, SHELLOPTS, BASHOPTS, PS4, ZDOTDIR Can supply shell startup code, options or functions.
PYTHON*, Java, Node, Ruby, Perl, PHP and .NET startup options, R_PROFILE_USER, LUA_INIT*, LUA_PATH*, LUA_CPATH* Can alter interpreter startup or module loading.
Relative or empty PATH entries Could run an unexpected program from the brain folder.

Other variables, including provider credentials and absolute PATH entries, remain. The list is best effort, not a sandbox. When a program needs dependencies, use an explicit runtime such as uv run --no-project sensors/example.py.

A timeout, cancellation or closed terminal kills the program's whole process group, as does output beyond max_bytes from a sensor or action routine; partial output never replaces stored records. Cancellation during startup waits until BF owns the new process, then kills its group too. A program that another process kills, such as the out-of-memory killer, fails naming the signal: program was killed by SIGKILL. A run ends when the program exits and its output closes. A background helper that keeps output open more than a second after the exit fails the run: redirect its output, for example to /dev/null. Watch and generated schedules allow 60 seconds after a stop request, so an interrupted record write can roll back.

Each run appends entries to the program's logs/NAME.log in the brain: a == TIME OUTCOME == heading when the program exits, followed by its stderr and a log routine's stdout, then another heading with the run's result, such as the records collected or the failure. The log keeps its newest whole entries within 1 MiB. Errors and run history name the log without quoting provider output. bf init ignores logs/ in Git and search never reads it, but a log can hold provider output: keep it private and never paste it into a public issue. Search and read keep a local usage.jsonl with the time, operation and result count, never queries or refs. Beyond 1 MiB, BF drops events older than 30 days, then the oldest ones beyond 768 KiB. bf status summarizes 7 and 30 days and marks a window this cut shortened.