Skip to content

v19.0.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 10:57
· 58 commits to main since this release
Immutable release. Only release title and notes can be modified.

A major release. Assistants replace prompts: one harness answers messages from brain-owned channel commands in their thread, reviews on named schedules or after a sensor changes and fans its saved answer out to several channels, while a durable local queue keeps every accepted message, answer and delivery. The brain format moves to version: 8: bf.yaml renames prompts: to assistants:, replaces their refresh and lookback with named schedules and adds channels:. Search and read replies name an assistant's attention entry assistant instead of prompt and gain the optional silent flag that home attention entries already carried, and the search cache rebuilds once. Follow the upgrade steps below before collecting again; they include this release's skill, example, AGENTS.md and Claude Code command updates.

Breaking changes

  • Assistants replace prompts. prompts: becomes assistants:, and refresh and lookback fail validation. There is no default schedule: an assistant runs on its own only through schedules, inputs or triggers, so a v18 prompt without refresh, which ran every 30 minutes, runs only with bf run until you give it a schedule.
  • Failed runs wait for you. A harness run that fails, times out or is interrupted, whether a schedule, a message or bf run started it, stays failed or uncertain in bf queue, blocks the later work of its schedule or conversation and makes bf status --check exit 1 until bf queue ID --retry or --cancel resolves it. A run killed outright, as by the out-of-memory killer, shows running until a running watch records it within about a minute, the next bf update does or bf queue ID --retry or --cancel names it. v18 retried a failed scheduled prompt after a backoff and only logged a failed direct run.
  • Evidence windows. {{start}} and {{end}} depend on the kind of run: a schedule covers the time since its own last run, a message the moments between its sending and its admission, and bf run the 24 hours before it. In v18, a direct run, such as a chat bridge's, also covered everything since the last scheduled run.
  • BF delivers answers. A run's answer goes to the assistant's outputs; bf run sends it to every output without when or with manual in it. A harness or bridge that still posts the answer itself sends it twice.
  • Run records. attributes.trigger names the kind of run, input, schedule, trigger or manual, instead of schedule or run; elapsed_seconds is gone; job and, for a message, channel, sender and conversation are added; a record's id and time follow its window's end instead of the run's start.
  • Commands and replies. --assistant replaces --prompt on update, watch and schedule, and --kind assistant replaces --kind prompt. run and update replies list assistants entries named by assistant, home and status attention entries name assistant, and bf watch --json reports assisting instead of prompting. The update reply's manual names enabled assistants without schedules, inputs or triggers, which only bf run starts, instead of prompts with refresh: 0. A native schedule generated with --prompt exits 2 until you regenerate it.
  • Status. An assistant's status entry drops last_run and failures, adds schedules and inputs, reports manual freshness without a schedule and is failed while one of its jobs is failed or uncertain, as is its source in sources and in search and read coverage, even once disabled. attention also names an assistant with failed or uncertain jobs, whatever its schedules, as on the home page; status alone also names an assistant whose schedules or triggers cannot start, and a channel with an unresolved delivery that failed or is uncertain or a stream or read error, as {"channel":NAME,"freshness":"unknown","failed":true}. A brain with an assistant queue gains messaging, which holds the details; healthy follows problems, attention and the cache alone.
  • Run history. Assistant run counters live in assistants.json in the local state directory: runs restarts at 0, and v18's prompts.json is no longer read.

Upgrade from v18

  1. Before upgrading, note what each prompt does under v18: its refresh (1800 when omitted, 0 for manual runs only) and lookback in bf.yaml, its last_success in bf status, and where its answers go, such as a harness told to post them through a chat CLI or MCP tool, or a bridge that pipes messages into bf run PROMPT --stdin and posts the reply's text.
  2. Stop every execution owner: bf watch, the native schedule jobs (with the remove commands bf schedule returned) and any external chat bridge or listener. Let a bridge finish the messages it accepted, or note them to send again, then stop its service.
  3. Back up the idle brain and its local state directory, $XDG_STATE_HOME/bf/ (normally ~/.local/state/bf/), which holds run history and, from v19 on, the durable assistant queue under runtime/. If you ran a pre-release v19 build on this brain, first resolve with that build every pending, failed or uncertain job and delivery its bf queue lists, using bf queue ID --retry or bf queue ID --cancel, then move its queue.sqlite3 out of the state directory: it is in the runtime/ folder that stat -c %d-%i ~/brain names (stat -f %d-%i ~/brain on macOS), and this release refuses a queue a pre-release build created with unexpected assistant queue schema; preserve it and repair it.
  4. Upgrade with uv tool upgrade brain-framework, or update a pinned brain's pin to the published v19 release, and check bf --version.
  5. Change version: 7 to version: 8 in bf.yaml and every evals/*.yaml. Records and notes keep their format.
  6. Rename prompts: to assistants:, keeping each entry's prompt, command, text, enabled, timeout, max_bytes and keep. A Claude Code command that came from the 18.5.0 prompt guide or bf-maintain's example becomes [claude, --print, --output-format, json, --tools, "Read,Grep,Glob,Bash", --allowedTools, "Bash(bf read *),Bash(bf search *)", --permission-mode, dontAsk], keeping any options you added.
  7. Give each prompt that ran on its own a schedule: replace refresh: N with schedules: {review: {every: N}}, with every: 1800 where refresh was omitted, and move its lookback: L into that schedule, as schedules: {review: {every: N, lookback: L}}. Delete refresh: 0 and its lookback without adding a schedule: bf run now always covers the 24 hours before it, so give such an assistant a schedule if it needs a longer window. A schedule's lookback, 86400 by default, only sets its first window, and v19 does not carry v18's progress over: to keep the first review from covering again what v18 reviewed, set it to just over the time from the last_success you noted to the first v19 run, such as lookback: 7200 for a first run two hours after it. Every run calls your harness's model, so keep v18's interval unless you accept the cost of more runs: every: 1800 makes about 1,440 a month.
  8. Review each prompt file: a message or bf run no longer covers the time since the last review, so wording such as This run covers {{start}} to {{end}} describes moments or the past day there. Keep window wording for schedules and triggers, and let message answers read what they need, such as bf read memories/NAME/24h; Assistants gives each window.
  9. Replace model-owned sends with outputs. Declare each destination as a channel whose send command is a script under channels/ holding the provider access, then list it under the assistant's outputs, or add reply: {} to answer incoming messages in their thread. Remove the posting instructions from the prompt and the posting tool from the harness's allowed commands, such as its --allowedTools: BF delivers the saved answer, and a harness that still posts sends it twice. Declare idempotent: true only when the provider drops a repeated delivery ID.
  10. Replace an external chat bridge with a channel stream or read command and an assistant inputs entry, reusing its provider access and sender admission, and never run the old listener beside the new stream on one provider subscription. Review each adapter's sender admission and destination restrictions, as Channels describes.
  11. Update what consumes BF: replace --prompt with --assistant and --kind prompt with --kind assistant in scripts and host configuration, read assistants, assistant and assisting from replies, filter records on the new trigger values, accept channel entries in status attention and read messaging for the queue's details. Regenerate native schedules with bf schedule, naming --assistant NAME where you named --prompt NAME; a job of their own, such as bf schedule --assistant NAME --name assistants, keeps a long run from delaying collection. The remove commands delete only the installed copies: before regenerating a job under the same --name and --output, delete its old generated files there (normally ~/.config/bf-schedules/bf-BRAIN-HASH-NAME.*), or bf schedule refuses with FILE already exists with different content.
  12. Run bf skills DIR for each skills folder to update bf-use, bf-action and bf-maintain, and copy the updated example weekly-review routine, session-context and prompt-context hooks and git-history, github-history, gmail-headers, google-calendar and google-drive-folders sensors from the release tag, preserving local adaptations: the routine and the session hook read assistant attention entries.
  13. Merge the new AGENTS.md lines into each brain, as Refresh brain instructions shows: they name the channels/ folder, and bf channel and delivery bf queue ID --retry among the commands that need explicit authority.
  14. Check before restarting: run bf validate, bf eval and bf update --dry-run, which lists each due schedule and its window. To see what a harness receives, dry-run a temporary [cat] assistant, as troubleshooting shows. Try each new channel in a disposable copy of the brain, which gets a queue of its own, as the messaging example does. Then start bf watch, which streams need, or install the regenerated schedules, and check bf status --check.

Added

  • Optional send, bounded read and persistent stream channel commands, each with an argv contract and no provider dependencies. Stream acknowledgements follow durable admission for every configured subscriber; execution remains selected. A stream resumes from the cursor of the last admitted message, while its since stays its first start, and clears its transport error once it stays up 5 seconds, though not a refused admission; a read input catches up on a window holding more than 1,000 messages in parts.
  • Assistant fan-in, fan-out, threaded reply: {}, named schedules and sensor.changed triggers. Inputs and outputs live at the same level; channels own transport, assistants own calling policy, and the owner chooses the harness. A sensor change records only the names of the triggers naming its sensor, and watch or bf update admits their jobs from the current bf.yaml: a full queue, a missing prompt or a bf.yaml edit never blocks collection, a trigger that cannot start yet stays pending with its reason, and one whose assistant or trigger was removed or changed is dropped. A native schedule naming a trigger-only assistant admits its triggers.
  • Durable local work and delivery queues outside .bf/, with saved answers, stable delivery IDs, explicit retry/cancel, per-conversation ordering, bounded retention and backpressure. Each commit is durable when it returns; a job reserves its answer space only when it starts, so admission holds hundreds of jobs and a full read batch, and a batch that does not fit admits its longest prefix; identity tombstones and send receipts last 35 days. A drained queue follows a renamed brain or one moved within its filesystem, and search, read and status open it read-only. bf queue inspects, retries and cancels jobs, deliveries and sensor triggers, and a triggered job has an ID of its own; bf channel read|send uses an endpoint directly.
  • Interrupted work is recorded even without watch: Ctrl-C or SIGTERM records a harness attempt or send before bf exits, and bf queue ID --retry or --cancel records one killed outright, refusing while its process still runs. bf status names a queue write a killed process interrupted, which bf queue rolls back, and a queue another build created. bf validate reports an assistant whose answer needs more queue space than one job may reserve, counting each delivery it makes.
  • Watch supervises streams beside collection, with reserved reactive and proactive capacity and up to four independent channel deliveries. Assistant work that cannot start never stops it: watch shows why, including a failing read, stream or delivery, and checks again about once a second, while busy work and a failing assistant's schedules and triggers wait 10 seconds between attempts; it stops only when a stream worker does. bf update reports each failing read, schedule, trigger, job or delivery as its own row while the other assistants run. Failed or interrupted harness attempts require explicit review; only declared idempotent assistant deliveries retry automatically, after 2 to 300 seconds for up to 20 attempts, and a failed bf channel send waits for bf queue ID --retry.
  • The offline messaging example walks through a reply, a scheduled delivery, a direct send and a failed send's retry; fault tests cover redelivery, ACK ordering, cancellation, configuration changes, independent recipients, including stream subscribers a scoped watch does not run, queue recovery and provider-neutral transport boundaries.

Changed

  • bf init names channels/ beside sensors/, routines/ and prompts/ in the brain's AGENTS.md and lists bf channel and delivery bf queue ID --retry among the commands that need explicit authority, as bf-use, bf-action and Concepts now do; Configuration and troubleshooting count channel and queue among the commands that act on one brain.
  • Unscoped and identity searches, memories pages and the home page read each source's record count, latest event and latest change from one index instead of every record's row. On the benchmark's 20,000 records, a selective search takes about 16 ms instead of 42 ms and the home page 14 ms instead of 48 ms (median in-process timings on one Linux machine).
  • A mistyped source suggests close ones, as a mistyped page or note does: bf read memories/gmial and bf search … --scope memories/gmial end with did you mean memories/gmail?.
  • Development tools: uv 0.13.1, with the build requirement widened to uv_build>=0.12.10,<0.14; dprint 0.63.0 with the JSON 0.25.2, Markdown 0.26.0 and TOML 0.9.0 plugins; lefthook 2.2.2; trivy 0.76.0; and no jq, which no task, hook or test runs. mise.lock uses lockfile revision 3, which needs mise 2026.9.16 or later, and the workflows pin mise 2026.10.12, jdx/mise-action v5.2.0, actions/upload-artifact v7.0.2 and actions/download-artifact v8.0.2. .python-version names Python 3.14.8, the mise pin, which stays below 3.15 while PyYAML ships no cp315 wheels.
  • The locked environment moves to mcp 2.3.0, pydantic 2.14.1 with pydantic-core 2.50.1, typer 0.27.3, starlette 1.8.0, truststore 0.10.5, opentelemetry-api 1.45.1, rpds-py 2026.9.1 and pycparser 3.11, and for development to zensical 0.0.71, ruff 0.17.1, ty 0.0.89, pymdown-extensions 12.3, markdown 3.11.1, markupsafe 3.0.4, pluggy 1.7.0, iniconfig 2.3.1 and tomli 2.5.0; the package's dependency ranges are unchanged.

Fixed

  • Replies, export lines, watch --json snapshots, diagnostics and MCP errors escape the line and paragraph separators U+2028 and U+2029, and so do bf-use's evidence helper, the example hooks and the weekly review: a file name in a shared brain can no longer split a JSON or context line, or forge a second bf: line, for readers that break lines there, such as Python's str.splitlines().
  • bf watch finds notify-send, gdbus and osascript for desktop alerts only through absolute PATH entries, like the programs it runs: with . on PATH, a watcher started in the brain root used to run a notify-send the brain supplied on every alert.
  • The example Calendar, Drive and Gmail sensors start gws from /, so a .env file in the brain or a parent folder, which gws loads, no longer switches the account they collect from. The Git and GitHub history sensors start git and gh there too, and git-history.py resolves a relative ROOT against the brain folder, where BF runs it.
  • Programs no longer inherit R_PROFILE, R_ENVIRON, R_ENVIRON_USER or the CORECLR_* profiler variables, which make R or .NET load code before the program starts. Limits names them, instead of claiming every .NET startup option is removed, and shows how a program sets one on purpose in its own command, such as [env, R_ENVIRON_USER=/path/to/Renviron, Rscript, sensors/example.R].
  • A search or read that builds a missing cache, as after an upgrade, a structural bf.yaml edit or a damaged cache, compares the new cache with the brain once more before answering: a collection committing during that build used to leave the reply holding records it had removed and missing those it added, without marking it stale.
  • A search cache build that publishes while the home page is being read no longer fails: the page's attention opened the cache a second time, behind the publish, so the read waited 30 seconds and the build failed with readers kept the search cache open; retry bf build. A first build no longer creates an empty .bf/index.sqlite with default permissions just before publishing, which a build interrupted then left behind.
  • A refreshed cache matches a full build: restoring the permissions of an unreadable folder inside memories/SOURCE is seen at the next search or read instead of only after bf build, and spelling suggestions no longer depend on the order files were indexed in, where a refresh could suggest policy and a full build of the same files policies.
  • A brain whose .bf directory is read-only fails with the search cache needs write access to the brain's .bf directory, also from bf status, bf export and bf build, instead of naming search and read.
  • A link, and a file standing where projects/, concepts/, actions/ or memories/ belongs, name their cause and repair alike in search, reads, bf status and bf validate: a link says to replace it with the file or folder itself, where a linked memories/ or synced concepts/ folder was told to become a regular file, and such a file says expected a folder; replace the file with a folder, where search reported a misnamed record and bf validate a special file. A link, special file or unreadable folder named *.json reports its own problem instead of expected memories/<source>/<sha256-id>.json, even in projects/.
  • An action read names each skipped file in its folder once, with its real cause, such as symlinks are not followed, even past the cache's first 200 problems: it repeated each as symlinks and special files are not listed, the wrong cause for an unreadable folder. Replies count a single skipped file beyond the first 200 as 1 more file was skipped.
  • Reading a linked or special folder below an authored root, or a folder below one, such as projects/shared/sub, names that entry (projects/shared: expected a directory; symlinks and special files are not followed) instead of answering reference not found; a selected brain that holds a real folder there still answers.
  • Search coverage keeps a source that fell silent, marked "silent": true, beside failed, overdue and never-collected ones: an empty search used to describe a scheduled source that stopped bringing evidence as fresh. The read reply schema, and with it MCP's outputSchema, describes the "silent": true that home attention entries carry, which clients validating replies rejected.
  • bf status and the memories pages state a source's changed with your local offset, to the second, like latest and last_collected: as a UTC instant with microseconds, it misordered them when compared as text.
  • Source period, undated and record-file pages give the source's coverage, as memories/SOURCE does, so an empty day no longer reads as absence without saying whether the source was collected. Tag scopes and tag searches, which hold only notes, no longer list collected sources.
  • Later text pages of a large exact read carry only the read's own problems and stale, as documented, even when the graph context alone made the reply page: a note just under 32 KiB used to repeat its context's problems on every page.
  • Tag errors name the mistake: an invalid label reads invalid tag label; read the tags page and use one of its refs, in MCP too, which said use a ref returned by the read tool tags; bf read bf://brain/tags/a%2Fb states the label rule (invalid tag address; tag must be 1-128 characters …) instead of a section or relation it does not have; and bf read tags/C# points to the bf:// ref that bf read tags returns for a label holding #, instead of advising to drop the fragment, which reads the label C.
  • A claim to a note section, such as bf://brain/projects/new-website.md#decision, names that note as target_ref with its target_title, as the linking guide shows, while its target keeps the section; a target that is both a record's ref and another note's alias names no item instead of the note. A read or search no longer drops an owner's aliases and reports a false conflict when another process, such as bf watch, re-indexes the owner's note at that moment.
  • Identity problems read correctly: one shared alias reports aliases also claimed elsewhere were not expanded: 1 instead of 1 aliases are …, and an identity that several notes or records hold says to read an owner's bf://NAME/... address, since the owners may be records, such as one record two brains collect.
  • Previews end in … where they cut, at a word when one is near: excerpts in listings, relation pages and identity searches stopped mid-word at 320 characters without a mark, such as We choose selected captures t, and read as complete, and backlink excerpts cut mid-word at 160. The tasks page and each claim's target_title cut titles to 200 characters, like other listings: a note titled with a whole message fit only 7 tasks on a page, and claims naming such targets could push a small note's exact read past 32 KiB.
  • A note holding one long line dense in punctuation, such as pasted minified JSON, parses in linear time: a 4 MiB note took minutes, stalling search refreshes, bf watch and bf validate.
  • Body links to records of sources named file, data, javascript or vbscript, such as [Notes](file:notes.txt), count as links: markdown-it's HTML filter dropped them silently, with no claim, backlink or validation, while the same ref in frontmatter links counted.
  • Footnote syntax shown in an indented code block, or an underline right below a definition, even in a block quote, no longer creates sections: a code line could become a searchable heading whose links failed bf validate, and --- or === turned the definition into a heading. As on GitHub, --- there is a rule that ends the footnote, and a definition indented four columns or more, as in a nested list item, continues on lines indented four more.
  • Replies state an instant from before its timezone adopted standard time, such as an 1850 archive record, in UTC (+00:00): its local mean time offset, such as New York's -04:56:02, has seconds, which RFC 3339 date-times and the reply schemas reject.
  • When bf build, bf collect or bf update cannot apply an interrupted write's journal, the error names memories/.pending, and an unexpected file there by name: a manifest that is not JSON read invalid JSON document, as a sensor's bad output does, and a missing backup an inaccessible file. Troubleshooting and bf-maintain say how to recover when the journal itself is refused.
  • bf register takes over a name whose registered folder no longer holds a bf.yaml, as after a move or over an unmounted share, instead of advising you to rename one of the brains, and search, read and bf status report such a folder as bf.yaml is missing, which troubleshooting and bf-maintain cover. Registering again where nothing moved keeps the entry as written, ~ paths included, even with a home folder reached through a link, such as /home to /var/home; the registry keeps every paragraph of its leading comments, and a new one starts with the configuration page's URL, as documented.
  • A collection or build that readers block, such as during a long bf validate, says another process is reading or changing this brain's records instead of naming a writer that does not exist, and a bf register waiting for another registration says another bf register is updating the registry.
  • bf collect, bf run and bf update no longer stop with a traceback when no home directory resolves, as for a container user without HOME or a passwd entry: programs that do not use {{home}} run, and one that does fails with cannot find the home directory for {{home}}; set HOME, which a sensor's run history records with the failure backoff, as for routines. bf schedule --backend launchd and a bare ~ path, such as bf schedule's default ~/.config/bf-schedules, also say to set HOME.
  • keep never removes the output of the run that just wrote it, even when another clone in a time zone ahead dated an action later or a clock that ran ahead dated older assistant runs later: the reply, run history and bf status then named an action or assistant record that no longer existed. A routine whose keep cannot read or remove an older action, such as one in a read-only folder, still succeeds and logs/NAME.log names the folder it kept, as for a link or unreadable folder in actions/, which pauses removal, instead of failing and retrying; an assistant's keep prunes past a run record it cannot read, which stopped all pruning.
  • A routine's broken-link error quotes at most 200 characters of the link, as Limits now lists: a long target taken from evidence no longer fills run history and every bf status reply.
  • After a clock correction, an assistant schedule whose last success lies in the future runs at once, as bf status and dry runs report, instead of skipping for up to one refresh.
  • bf schedule names the existing file that differs from what it would generate, instead of schedule file already exists with different content, so you know which one to review.
  • bf watch stops its collection updates within one 60-second bound in total and says so once, instead of 60 seconds and a notice for each. A second Ctrl-C, or the hangup of a closing terminal, no longer skips the wait and kill: watch exits 130 once every update has stopped or been killed.
  • The watch dashboard keeps interval too slow, press ? whole in its header at the documented 80 by 24 minimum, where the summary cut it off below about 90 columns, and its guide keeps its control and freshness lines instead of repeating the footer's keys. The selected row stays readable on light terminal themes, and configured periods read exactly: a 90-second interval is Check: 90s and a 5,400-second refresh Refresh: 90m, not 1m and 1h.
  • The watch dashboard reads 1 program, 1 needs attention and Search cache skipped 1 file for one, shows Checks paused while paused instead of a countdown stuck at 0s, and says Nothing needs attention when Tab's attention filter hides every healthy program, instead of asking you to add one to bf.yaml.
  • Watch details name the command that runs the selected program now, bf collect NAME for a sensor and bf run NAME for a routine or assistant, and none for a disabled program or in an observer: they suggested bf collect for routines as well as sensors, and a command for disabled programs and in an observer. A second bf watch that falls back to observing no longer warns that its own unused interval runs programs late, and a busy bf watch --json reports only that another watcher owns the brain.
  • bf update --kind checks its value before selecting a brain and quotes it like other choices: --kind "" reads '' is not one of 'sensor', 'routine', 'assistant' (exit 2) instead of a blank name or a brain selection failure. bf run refuses a program name that is not UTF-8 as invalid input (exit 2), while the arguments after it, such as a hook's Git arguments, reach the routine byte for byte. Of two bf init runs on one empty directory, the second fails instead of replacing the first one's files.
  • Help matches behavior: bf --help says register selects a brain by name outside its folder and validate also checks program files; status --check names an unavailable cache and sources that fell silent; collect --allow-removal states the snapshot guard's 10-record floor; every --notify mode except off alerts on recovery; bf skills never overwrites edits without --force; and collect --until and register PATH state their default once.
  • bf eval ignores an editor's .#NAME lock beside a suite, as validation and search do beside notes, so a suite open with unsaved edits in Emacs no longer fails every run, and another link in evals/ fails with validation's reason. A folder without suites is named in the advice, as in projects holds no .yaml or .yml suites; add one, such as projects/retrieval.yaml, …, and a --path naming neither a folder of suites nor a .yaml or .yml suite, even below a note, says so instead of suggesting evals/retrieval.yaml or replacing the note with a folder.
  • A whole-note expect or forbid ref matches the sections of a note whose file name holds #, such as projects/C# guide.md, and a read case can expect the bf:// address of a record whose id holds #, such as bf://NAME/issues:item%23comment: such an expectation failed with a null rank, and a forbidden note passed.
  • bf status outside a brain reports a registered brain whose bf.yaml cannot load beside one that is unavailable, exiting 0 (1 with --check), instead of failing with the bare file error. A brain's uv.lock nested past Python's recursion limit or holding an integer over 4,300 digits pins nothing, like any lock that does not parse, instead of failing every selected brain with a traceback.
  • bf-use's helpers: evidence.py compare compares a record's time as an instant, so a read made in another time zone, such as a teammate's, no longer reports an unchanged record as changed; capture and compare take up to 19 MiB of standard input per reply or capture, instead of 9 MiB in all, and name the bound beyond it; and guarded-write.py refuses content above 4 MiB, the largest note bf reads, instead of writing up to 16 MiB, which left a note that every search reported as a problem.
  • bf-action's new-action.py accepts topics that start with a digit, such as 3d-printing, as bf validate does, says when --brain is not a brain directory instead of hinting at permissions, and prints compact JSON, like bf and the other helpers.
  • The Claude Code command of the assistant guide and bf-maintain's assistant example keeps the harness to the Read, Grep, Glob and Bash tools, allows only bf read and bf search commands and, with --permission-mode dontAsk, refuses any other call, even when your settings accept edits: the skill's --tools "Read,Grep,Glob" left out Bash, so the harness could not run the bf read and bf search its prompt asks for and answered without reading the brain, and the guide's command left every other built-in tool, such as Edit, to your settings' permission mode while its prompt reads untrusted evidence. The skill, the assistant guide and troubleshooting say a --tools list must keep Bash for such rules, Add a sensor restricts its meeting-notes agent the same way, and the skill's sensor example declares the kind field it maps, which a brain created with bf init lacks.
  • bf-use's concept template names every relation bf init declares, author, owner, depends-on and related-to: declaring owner or depends-on again, as it advised, failed bf validate on a duplicate key. Its retrieval guide reads a section the outline lists, or redirects evidence.py read to an owner-only file or a pipe: run bare, that printed a large note's whole text past the 32 KiB page budget.
  • The example weekly review no longer lists itself as needing attention on its first run, after its own failure or after a long pause, a line that alone wrote an action on an otherwise empty brain: BF records a run only after it exits, and the review recognizes its own by file name, so keep it named weekly-review, and by its brain's name, which it asks bf status for when the home page lists brains declared under brains:, so their weekly-review stays listed. It counts as recent only actions begun in the last seven days, up to today, names the bf read page holding the rest when a preview is full, says why it lists a silent source, writes 1 open task and 1 note in the singular and names bf read projects among its sources.
  • The example session hook labels a source that fell silent silent instead of fresh, while a failed or overdue one keeps that state, since a stopped sensor falls silent too, and lists a note linking the project with several relations once among the three newest linking notes. The example prompt hook reads prompts in NFKC form, as bf search does: pasted text with decomposed accents searched fragments such as cide instead of décidé.
  • The example Gmail headers sensor keeps at most 1,000 from_refs, like to_refs and cc_refs: a message with more senders failed every collection that mapped them, and its window never advanced.
  • Release tooling: scripts/verify-release.sh accepts only build attestations that CD signed for the release tag and its commit, where one from any workflow or ref of the repository passed, and ignores a relative XDG_CACHE_HOME, as bf does; release notes stop at the next level-2 heading, so an ## Unreleased placed below a release no longer publishes its draft entries; scripts/push-and-tag.sh exits 1 with pushing main failed; nothing tagged when pushing main fails; and CD fails at the hash extraction, with jq's error, when PyPI's release metadata cannot be read, instead of reporting a hash mismatch.
  • Contributor checks: tests validate each search or read reply against the schema of its own kind, ignore the host's TERMINAL_WIDTH, PY_COLORS, TYPER_USE_RICH and _TYPER_FORCE_DISABLE_TERMINAL, give cold starts and the MCP handshake the documented 120-second deadline and cover more release-script failures; the contract check fails when a configuration oneOf alternative accepts more than its release; check:links checks anchors in repository Markdown; a workflow step that pipes commands must set shell: bash; the README test checks its images and badge against the checkout; and the scale benchmark times a misspelled word, rejects more records than one collection commits, writes its corpus under the writer lock and ignores a relative XDG_CACHE_HOME.

Documentation

  • The bf-use and bf-maintain skills, Search and read, the retrieval reference, troubleshooting and the hooks guide cover silent sources: such a source may lack evidence while looking fresh, joins attention and the home page and fails bf status --check. The retrieval reference explains the changed and silent coverage fields of memories pages and that only the memories overview gives each source's page.
  • Editor and reply schemas describe more: a registry entry, a field's description and type, an evaluation suite's cases, the changed and silent coverage fields, and that routine names must differ from assistants as well as sensors.
  • The hooks guide, agent workflows, privacy page and team guide say to copy host hooks into a folder only you write and never register one from a brain others can push to: the host runs a registered hook at every session or prompt, so a pulled change would run unreviewed. Before running a shared brain or a clone, also review prompts/ and channels/, which the brain's assistants run, any .env file, which a provider CLI such as gws loads from the brain's folder and which can switch its account, and the agent configuration an assistant's harness loads there, such as Claude Code's .claude/, whose hooks --print runs without a trust dialog, and .mcp.json; Assistants shows how --setting-sources user keeps the brain's settings files out of a run. The team guide adds that a clone's bf status --check fails on scheduled sources it did not collect, which show never under attention.
  • Assistants explains that a native schedule runs assistants in the same bf update job, so under systemd or launchd a long agent run delays the next collection, and how to give assistants a job of their own, as bf-maintain now advises. Assistants and Privacy warn that a {{prompt}} argument shows the expanded prompt, a piped message included, to local process listings while the harness runs, and Watch and schedule says generated schedules also copy XDG_CONFIG_HOME and XDG_STATE_HOME when set.
  • Install and update covers every release since your previous version: apply each release's upgrade steps oldest first, copy the examples it names from the tag matching bf --version, and repeat bf skills for each folder you installed the skills into, such as ~/.claude/skills. The 18.5.0 notes now say to merge the AGENTS.md line naming prompts/, and the 14.0.0 notes give the upgrade steps from 13.
  • The link reference corrects its recovery advice: a BF address decodes its percent-encoding, so %E2%80%8B still fails, and only a record whose aliases hold an invisible character or exceed 1,000 stops loading. Only an OKF sources resource written as a link, without spaces, cites and is checked, so write ./brief.txt for a sibling file; the 8,192-character bound covers BF links and frontmatter links, which the note field table now lists; listings show single-value relations too; and a note's entity may be any explicit identity, usually a bf:// name.
  • Limits states that every run ends by killing the program's process group, so background helpers end with it unless they start their own session, that standard input is /dev/null and only a helper holding standard output open fails a finished run, that a folder nested deeper than 64 levels fails the scan, that only the brain's root inputs/ and originals/ go unscanned, and the *_truncated flags of validation's unresolved targets and reprojection problems. The retrieval reference adds that a note saved in place twice at the same size within one timestamp tick, with a search in between, stays unseen until it changes again or bf build.
  • The format and retrieval references match behavior: True, TRUE, False and FALSE are booleans and 017 is decimal; a stored revision whose updated is later than its observed, as from a clock in the future, never freezes a record; only the Markdown files of an action's inputs/ and outputs/ are searchable; a record file edited by hand waits for bf build; and today and yesterday name their previous and next days, while projects list newest updated first.
  • Commands, Configuration and the MCP contract match behavior: a bf status brain lists routines and assistants only when it declares any, and the status example shows a source's changed and every last_run counter; duplicate keys and YAML syntax errors name the line and column; one brain folder cannot serve several accounts, since BF writes owner-only files, so each person uses a Git clone; and an MCP invalid input: error can name offset too.
  • Check your brain lists ambiguous and folder-page identities, unreadable files, a file where a scanned folder belongs, the action-folder rule, the 120,000-byte prompt bound, unresolved_truncated, a case's limit (1–50, default 10) and when mrr appears, and says a window sensor needs a backfill to clear record-link and case-variant warnings. Troubleshooting covers bf.yaml is missing, … not found and unknown source suggestions and a file in a folder's place; its [cat] check dry-runs a temporary assistant without text, instead of swapping a live assistant's command, which fails its queued work, and pipes a message with --stdin, its Updates do not run section links the scheduler's host lifecycle, and recovery no longer promises to take about a second.
  • Agent workflows describe Context as a standard section of every action and say a forced bf skills update still lists edited files; bf-use's guarded-write guide says Written, but its directory could not be synced exits 1 although the file changed; and bf-action lists outdated evidence, not stale evidence, among an action's unknowns, since a stale reply calls for a retry.
  • The example guides match their programs: the Gmail headers guide says to authorize gws with gmail.readonly and without gmail.metadata, since Gmail rejects the sensor's search for a token holding that scope, and names its typed-relation attributes and label ids; the sensors guide gives each sensor's time limit per provider call beside the whole-run timeout, lists the supported document formats by suffix and says a symbolic link or special file fails the snapshot whatever its suffix; the hooks guide asks for the bf release whose tag the hooks came from; and the GitHub history guide names its lowercase repo:github.com/OWNER/REPO link.
  • The walkthroughs match their output, and tests check more of what they state: the weekly review walkthrough shows the action's seven open tasks with their section refs and its records by source; the offline watch demo prints its directory before the dashboard covers the terminal, runs its other commands in a second terminal and a checkout's bf as uv run --project CHECKOUT bf, and counts Items as the dashboard does; the assistant example no longer claims bf validate checks the harness is on PATH; Getting started lists the .gitignore that bf init writes; Search and read continues a listing on the Getting started brain; and the four-tool, team, retrieval and example-brain walkthroughs state their trimmed replies, action suffixes and counts as their brains hold them.
  • The documentation site builds with Zensical 0.0.71, whose search dialog's close button screen readers announce as "Close search" instead of "Search", and its third-party notices link the license texts of Preact, Preact Signals, clsx, usehooks-ts and lodash.debounce, which Zensical's search client bundles but its license file omits; check:notices fails when one of those copies or a Zensical version row goes missing or changes. In light mode, links and accents use the logo's blue and the Fmind palette's purple.
  • The README and the loop diagram include assistants and channels in what bf.yaml declares, the README's figures for the author's brain follow the count of 2026-10-16 (more than 80 sensors and about 50,000 records), and the PyPI page links the changelog.
  • Contributing starts setup with mise trust and mise install --locked, since tasks never install tools, and notes that check, and so the pre-commit hook, needs network access for its vulnerability scans; the release checklist explains that bash ignores set -e in any command whose status if, && or || tests, as an agent's shell wrapper does; and the pull request template asks a breaking change for its manual upgrade steps under Unreleased.