Repository navigation
v19.0.0
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:becomesassistants:, andrefreshandlookbackfail validation. There is no default schedule: an assistant runs on its own only throughschedules,inputsortriggers, so a v18 prompt withoutrefresh, which ran every 30 minutes, runs only withbf rununtil 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 runstarted it, staysfailedoruncertaininbf queue, blocks the later work of its schedule or conversation and makesbf status --checkexit 1 untilbf queue ID --retryor--cancelresolves it. A run killed outright, as by the out-of-memory killer, showsrunninguntil a running watch records it within about a minute, the nextbf updatedoes orbf queue ID --retryor--cancelnames 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, andbf runthe 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 runsends it to every output withoutwhenor withmanualin it. A harness or bridge that still posts the answer itself sends it twice. - Run records.
attributes.triggernames the kind of run,input,schedule,triggerormanual, instead ofscheduleorrun;elapsed_secondsis gone;joband, for a message,channel,senderandconversationare added; a record'sidandtimefollow its window's end instead of the run's start. - Commands and replies.
--assistantreplaces--promptonupdate,watchandschedule, and--kind assistantreplaces--kind prompt.runandupdatereplies listassistantsentries named byassistant, home and statusattentionentries nameassistant, andbf watch --jsonreportsassistinginstead ofprompting. Theupdatereply'smanualnames enabled assistants without schedules, inputs or triggers, which onlybf runstarts, instead of prompts withrefresh: 0. A native schedule generated with--promptexits 2 until you regenerate it. - Status. An assistant's status entry drops
last_runandfailures, addsschedulesandinputs, reportsmanualfreshness without a schedule and isfailedwhile one of its jobs is failed or uncertain, as is its source insourcesand in search and read coverage, even once disabled.attentionalso 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 gainsmessaging, which holds the details;healthyfollows problems,attentionand the cache alone. - Run history. Assistant run counters live in
assistants.jsonin the local state directory:runsrestarts at 0, and v18'sprompts.jsonis no longer read.
Upgrade from v18
- Before upgrading, note what each prompt does under v18: its
refresh(1800 when omitted,0for manual runs only) andlookbackinbf.yaml, itslast_successinbf 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 intobf run PROMPT --stdinand posts the reply'stext. - Stop every execution owner:
bf watch, the native schedule jobs (with theremovecommandsbf schedulereturned) 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. - 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 underruntime/. If you ran a pre-release v19 build on this brain, first resolve with that build every pending, failed or uncertain job and delivery itsbf queuelists, usingbf queue ID --retryorbf queue ID --cancel, then move itsqueue.sqlite3out of the state directory: it is in theruntime/folder thatstat -c %d-%i ~/brainnames (stat -f %d-%i ~/brainon macOS), and this release refuses a queue a pre-release build created withunexpected assistant queue schema; preserve it and repair it. - Upgrade with
uv tool upgrade brain-framework, or update a pinned brain's pin to the published v19 release, and checkbf --version. - Change
version: 7toversion: 8inbf.yamland everyevals/*.yaml. Records and notes keep their format. - Rename
prompts:toassistants:, keeping each entry'sprompt,command,text,enabled,timeout,max_bytesandkeep. A Claude Codecommandthat came from the 18.5.0 prompt guide orbf-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. - Give each prompt that ran on its own a schedule: replace
refresh: Nwithschedules: {review: {every: N}}, withevery: 1800whererefreshwas omitted, and move itslookback: Linto that schedule, asschedules: {review: {every: N, lookback: L}}. Deleterefresh: 0and itslookbackwithout adding a schedule:bf runnow always covers the 24 hours before it, so give such an assistant a schedule if it needs a longer window. A schedule'slookback, 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 thelast_successyou noted to the first v19 run, such aslookback: 7200for 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: 1800makes about 1,440 a month. - Review each prompt file: a message or
bf runno longer covers the time since the last review, so wording such asThis 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 asbf read memories/NAME/24h; Assistants gives each window. - Replace model-owned sends with outputs. Declare each destination as a channel whose
sendcommand is a script underchannels/holding the provider access, then list it under the assistant'soutputs, or addreply: {}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. Declareidempotent: trueonly when the provider drops a repeated delivery ID. - Replace an external chat bridge with a channel
streamorreadcommand and an assistantinputsentry, 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. - Update what consumes BF: replace
--promptwith--assistantand--kind promptwith--kind assistantin scripts and host configuration, readassistants,assistantandassistingfrom replies, filter records on the newtriggervalues, acceptchannelentries in statusattentionand readmessagingfor the queue's details. Regenerate native schedules withbf schedule, naming--assistant NAMEwhere you named--prompt NAME; a job of their own, such asbf schedule --assistant NAME --name assistants, keeps a long run from delaying collection. Theremovecommands delete only the installed copies: before regenerating a job under the same--nameand--output, delete its old generated files there (normally~/.config/bf-schedules/bf-BRAIN-HASH-NAME.*), orbf schedulerefuses withFILE already exists with different content. - Run
bf skills DIRfor each skills folder to updatebf-use,bf-actionandbf-maintain, and copy the updated exampleweekly-reviewroutine,session-contextandprompt-contexthooks andgit-history,github-history,gmail-headers,google-calendarandgoogle-drive-folderssensors from the release tag, preserving local adaptations: the routine and the session hook read assistantattentionentries. - Merge the new
AGENTS.mdlines into each brain, as Refresh brain instructions shows: they name thechannels/folder, andbf channeland deliverybf queue ID --retryamong the commands that need explicit authority. - Check before restarting: run
bf validate,bf evalandbf 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 startbf watch, which streams need, or install the regenerated schedules, and checkbf status --check.
Added
- Optional
send, boundedreadand persistentstreamchannel 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 thecursorof the last admitted message, while itssincestays 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 andsensor.changedtriggers. 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 orbf updateadmits their jobs from the currentbf.yaml: a full queue, a missing prompt or abf.yamledit never blocks collection, a trigger that cannot start yet stayspendingwith its reason, and one whose assistant or trigger was removed or changed isdropped. 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 queueinspects, retries and cancels jobs, deliveries and sensor triggers, and a triggered job has an ID of its own;bf channel read|senduses an endpoint directly. - Interrupted work is recorded even without watch: Ctrl-C or SIGTERM records a harness attempt or send before
bfexits, andbf queue ID --retryor--cancelrecords one killed outright, refusing while its process still runs.bf statusnames a queue write a killed process interrupted, whichbf queuerolls back, and a queue another build created.bf validatereports 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 updatereports 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 failedbf channel sendwaits forbf 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 initnameschannels/besidesensors/,routines/andprompts/in the brain'sAGENTS.mdand listsbf channeland deliverybf queue ID --retryamong the commands that need explicit authority, asbf-use,bf-actionand Concepts now do; Configuration and troubleshooting countchannelandqueueamong the commands that act on one brain.- Unscoped and identity searches,
memoriespages 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/gmialandbf search … --scope memories/gmialend withdid 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.lockuses lockfile revision 3, which needs mise 2026.9.16 or later, and the workflows pin mise 2026.10.12,jdx/mise-actionv5.2.0,actions/upload-artifactv7.0.2 andactions/download-artifactv8.0.2..python-versionnames 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,
exportlines,watch --jsonsnapshots, diagnostics and MCP errors escape the line and paragraph separators U+2028 and U+2029, and so dobf-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 secondbf:line, for readers that break lines there, such as Python'sstr.splitlines(). bf watchfindsnotify-send,gdbusandosascriptfor desktop alerts only through absolutePATHentries, like the programs it runs: with.onPATH, a watcher started in the brain root used to run anotify-sendthe brain supplied on every alert.- The example Calendar, Drive and Gmail sensors start
gwsfrom/, so a.envfile in the brain or a parent folder, whichgwsloads, no longer switches the account they collect from. The Git and GitHub history sensors startgitandghthere too, andgit-history.pyresolves a relativeROOTagainst the brain folder, where BF runs it. - Programs no longer inherit
R_PROFILE,R_ENVIRON,R_ENVIRON_USERor theCORECLR_*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.yamledit 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 itstale. - A search cache build that publishes while the home page is being read no longer fails: the page's
attentionopened the cache a second time, behind the publish, so the read waited 30 seconds and the build failed withreaders kept the search cache open; retry bf build. A first build no longer creates an empty.bf/index.sqlitewith 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/SOURCEis seen at the next search or read instead of only afterbf build, and spellingsuggestionsno longer depend on the order files were indexed in, where a refresh could suggestpolicyand a full build of the same filespolicies. - A brain whose
.bfdirectory is read-only fails withthe search cache needs write access to the brain's .bf directory, also frombf status,bf exportandbf build, instead of naming search and read. - A link, and a file standing where
projects/,concepts/,actions/ormemories/belongs, name their cause and repair alike in search, reads,bf statusandbf validate: a link says to replace it with the file or folder itself, where a linkedmemories/or syncedconcepts/folder was told to become a regular file, and such a file saysexpected a folder; replace the file with a folder, where search reported a misnamed record andbf validatea special file. A link, special file or unreadable folder named*.jsonreports its own problem instead ofexpected memories/<source>/<sha256-id>.json, even inprojects/. - 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 assymlinks and special files are not listed, the wrong cause for an unreadable folder. Replies count a single skipped file beyond the first 200 as1 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 answeringreference 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'soutputSchema, describes the"silent": truethat homeattentionentries carry, which clients validating replies rejected. bf statusand thememoriespages state a source'schangedwith your local offset, to the second, likelatestandlast_collected: as a UTC instant with microseconds, it misordered them when compared as text.- Source period,
undatedand record-file pages give the source's coverage, asmemories/SOURCEdoes, 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
problemsandstale, 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 saiduse a ref returned by the read tool tags;bf read bf://brain/tags/a%2Fbstates the label rule (invalid tag address; tag must be 1-128 characters …) instead of a section or relation it does not have; andbf read tags/C#points to thebf://ref thatbf read tagsreturns for a label holding#, instead of advising to drop the fragment, which reads the labelC. - A claim to a note section, such as
bf://brain/projects/new-website.md#decision, names that note astarget_refwith itstarget_title, as the linking guide shows, while itstargetkeeps 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 asbf 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: 1instead of1 aliases are …, and an identity that several notes or records hold says to read an owner'sbf://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 asWe choose selected captures t, and read as complete, and backlink excerpts cut mid-word at 160. The tasks page and each claim'starget_titlecut 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 watchandbf validate. - Body links to records of sources named
file,data,javascriptorvbscript, 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 frontmatterlinkscounted. - 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 collectorbf updatecannot apply an interrupted write's journal, the error namesmemories/.pending, and an unexpected file there by name: a manifest that is not JSON readinvalid JSON document, as a sensor's bad output does, and a missing backup an inaccessible file. Troubleshooting andbf-maintainsay how to recover when the journal itself is refused. bf registertakes over a name whose registered folder no longer holds abf.yaml, as after a move or over an unmounted share, instead of advising you to rename one of the brains, and search, read andbf statusreport such a folder asbf.yaml is missing, which troubleshooting andbf-maintaincover. Registering again where nothing moved keeps the entry as written,~paths included, even with a home folder reached through a link, such as/hometo/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, saysanother process is reading or changing this brain's recordsinstead of naming a writer that does not exist, and abf registerwaiting for another registration saysanother bf register is updating the registry. bf collect,bf runandbf updateno longer stop with a traceback when no home directory resolves, as for a container user withoutHOMEor a passwd entry: programs that do not use{{home}}run, and one that does fails withcannot 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 launchdand a bare~path, such asbf schedule's default~/.config/bf-schedules, also say to setHOME.keepnever 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 andbf statusthen named an action or assistant record that no longer existed. A routine whosekeepcannot read or remove an older action, such as one in a read-only folder, still succeeds andlogs/NAME.lognames the folder it kept, as for a link or unreadable folder inactions/, which pauses removal, instead of failing and retrying; an assistant'skeepprunes 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 statusreply. - After a clock correction, an assistant schedule whose last success lies in the future runs at once, as
bf statusand dry runs report, instead of skipping for up to one refresh. bf schedulenames the existing file that differs from what it would generate, instead ofschedule file already exists with different content, so you know which one to review.bf watchstops 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 isCheck: 90sand a 5,400-second refreshRefresh: 90m, not1mand1h. - The watch dashboard reads
1 program,1 needs attentionandSearch cache skipped 1 filefor one, showsChecks pausedwhile paused instead of a countdown stuck at0s, and saysNothing needs attentionwhen Tab's attention filter hides every healthy program, instead of asking you to add one tobf.yaml. - Watch details name the command that runs the selected program now,
bf collect NAMEfor a sensor andbf run NAMEfor a routine or assistant, and none for a disabled program or in an observer: they suggestedbf collectfor routines as well as sensors, and a command for disabled programs and in an observer. A secondbf watchthat falls back to observing no longer warns that its own unused interval runs programs late, and a busybf watch --jsonreports only that another watcher owns the brain. bf update --kindchecks 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 runrefuses 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 twobf initruns on one empty directory, the second fails instead of replacing the first one's files.- Help matches behavior:
bf --helpsaysregisterselects a brain by name outside its folder andvalidatealso checks program files;status --checknames an unavailable cache and sources that fell silent;collect --allow-removalstates the snapshot guard's 10-record floor; every--notifymode exceptoffalerts on recovery;bf skillsnever overwrites edits without--force; andcollect --untilandregister PATHstate their default once. bf evalignores an editor's.#NAMElock 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 inevals/fails with validation's reason. A folder without suites is named in the advice, as inprojects holds no .yaml or .yml suites; add one, such as projects/retrieval.yaml, …, and a--pathnaming neither a folder of suites nor a.yamlor.ymlsuite, even below a note, says so instead of suggestingevals/retrieval.yamlor replacing the note with a folder.- A whole-note
expectorforbidref matches the sections of a note whose file name holds#, such asprojects/C# guide.md, and a read case can expect thebf://address of a record whose id holds#, such asbf://NAME/issues:item%23comment: such an expectation failed with anullrank, and a forbidden note passed. bf statusoutside a brain reports a registered brain whosebf.yamlcannot load beside one that is unavailable, exiting 0 (1 with--check), instead of failing with the bare file error. A brain'suv.locknested 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 comparecompares a record'stimeas an instant, so a read made in another time zone, such as a teammate's, no longer reports an unchanged record aschanged;captureandcomparetake up to 19 MiB of standard input per reply or capture, instead of 9 MiB in all, and name the bound beyond it; andguarded-write.pyrefuses 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'snew-action.pyaccepts topics that start with a digit, such as3d-printing, asbf validatedoes, says when--brainis not a brain directory instead of hinting at permissions, and prints compact JSON, likebfand the other helpers.- The Claude Code command of the assistant guide and
bf-maintain's assistant example keeps the harness to theRead,Grep,GlobandBashtools, allows onlybf readandbf searchcommands and, with--permission-mode dontAsk, refuses any other call, even when your settings accept edits: the skill's--tools "Read,Grep,Glob"left outBash, so the harness could not run thebf readandbf searchits prompt asks for and answered without reading the brain, and the guide's command left every other built-in tool, such asEdit, to your settings' permission mode while its prompt reads untrusted evidence. The skill, the assistant guide and troubleshooting say a--toolslist must keepBashfor such rules, Add a sensor restricts its meeting-notes agent the same way, and the skill's sensor example declares thekindfield it maps, which a brain created withbf initlacks. bf-use's concept template names every relationbf initdeclares,author,owner,depends-onandrelated-to: declaringownerordepends-onagain, as it advised, failedbf validateon a duplicate key. Its retrieval guide reads a section theoutlinelists, or redirectsevidence.py readto 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 asksbf statusfor when the home page lists brains declared underbrains:, so theirweekly-reviewstays listed. It counts as recent only actions begun in the last seven days, up to today, names thebf readpage holding the rest when a preview is full, says why it lists a silent source, writes1 open taskand1 notein the singular and namesbf read projectsamong its sources. - The example session hook labels a source that fell silent
silentinstead offresh, while a failed oroverdueone 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, asbf searchdoes: pasted text with decomposed accents searched fragments such ascideinstead ofdécidé. - The example Gmail headers sensor keeps at most 1,000
from_refs, liketo_refsandcc_refs: a message with more senders failed every collection that mapped them, and its window never advanced. - Release tooling:
scripts/verify-release.shaccepts 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 relativeXDG_CACHE_HOME, as bf does; release notes stop at the next level-2 heading, so an## Unreleasedplaced below a release no longer publishes its draft entries;scripts/push-and-tag.shexits 1 withpushing main failed; nothing taggedwhen pushingmainfails; 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_RICHand_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 configurationoneOfalternative accepts more than its release;check:linkschecks anchors in repository Markdown; a workflow step that pipes commands must setshell: 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 relativeXDG_CACHE_HOME.
Documentation
- The
bf-useandbf-maintainskills, Search and read, the retrieval reference, troubleshooting and the hooks guide cover silent sources: such a source may lack evidence while looking fresh, joinsattentionand the home page and failsbf status --check. The retrieval reference explains thechangedandsilentcoverage fields ofmemoriespages and that only thememoriesoverview gives each source'spage. - Editor and reply schemas describe more: a registry entry, a field's
descriptionandtype, an evaluation suite'scases, thechangedandsilentcoverage 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/andchannels/, which the brain's assistants run, any.envfile, which a provider CLI such asgwsloads 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--printruns without a trust dialog, and.mcp.json; Assistants shows how--setting-sources userkeeps the brain's settings files out of a run. The team guide adds that a clone'sbf status --checkfails on scheduled sources it did not collect, which showneverunderattention. - Assistants explains that a native schedule runs assistants in the same
bf updatejob, so under systemd or launchd a long agent run delays the next collection, and how to give assistants a job of their own, asbf-maintainnow 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 copyXDG_CONFIG_HOMEandXDG_STATE_HOMEwhen 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 repeatbf skillsfor each folder you installed the skills into, such as~/.claude/skills. The 18.5.0 notes now say to merge theAGENTS.mdline namingprompts/, 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%8Bstill fails, and only a record whose aliases hold an invisible character or exceed 1,000 stops loading. Only an OKFsourcesresource written as a link, without spaces, cites and is checked, so write./brief.txtfor a sibling file; the 8,192-character bound covers BF links and frontmatterlinks, which the note field table now lists; listings show single-value relations too; and a note'sentitymay be any explicit identity, usually abf://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/nulland 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 rootinputs/andoriginals/go unscanned, and the*_truncatedflags of validation'sunresolvedtargets and reprojectionproblems. 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 orbf build. - The format and retrieval references match behavior:
True,TRUE,FalseandFALSEare booleans and017is decimal; a stored revision whoseupdatedis later than itsobserved, as from a clock in the future, never freezes a record; only the Markdown files of an action'sinputs/andoutputs/are searchable; a record file edited by hand waits forbf build; andtodayandyesterdayname theirpreviousandnextdays, while projects list newestupdatedfirst. - Commands, Configuration and the MCP contract match behavior: a
bf statusbrain listsroutinesandassistantsonly when it declares any, and the status example shows a source'schangedand everylast_runcounter; 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 MCPinvalid input:error can nameoffsettoo. - 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'slimit(1–50, default 10) and whenmrrappears, and says a window sensor needs a backfill to clear record-link and case-variant warnings. Troubleshooting coversbf.yaml is missing,… not foundandunknown sourcesuggestions and a file in a folder's place; its[cat]check dry-runs a temporary assistant withouttext, 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 skillsupdate still listseditedfiles;bf-use's guarded-write guide saysWritten, but its directory could not be syncedexits 1 although the file changed; andbf-actionlists outdated evidence, notstaleevidence, among an action's unknowns, since astalereply calls for a retry. - The example guides match their programs: the Gmail headers guide says to authorize gws with
gmail.readonlyand withoutgmail.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-runtimeout, 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 thebfrelease whose tag the hooks came from; and the GitHub history guide names its lowercaserepo:github.com/OWNER/REPOlink. - 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
bfasuv run --project CHECKOUT bf, and counts Items as the dashboard does; the assistant example no longer claimsbf validatechecks the harness is on PATH; Getting started lists the.gitignorethatbf initwrites; 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:noticesfails 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.yamldeclares, 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 trustandmise install --locked, since tasks never install tools, and notes thatcheck, and so the pre-commit hook, needs network access for its vulnerability scans; the release checklist explains that bash ignoresset -ein any command whose statusif,&&or||tests, as an agent's shell wrapper does; and the pull request template asks a breaking change for its manual upgrade steps underUnreleased.