Changelog¶
All notable changes to Brain Framework (formerly FKF) are documented here. This project follows Semantic Versioning from its first public release.
Unreleased¶
v21.1.0 - 2026-11-04¶
A minor release. The brain format (version: 8), the reply schemas, the queue format and the search cache are unchanged; bf.yaml accepts one more form, so no upgrade step is needed.
Added¶
- Retries by run kind. An assistant's
idempotentaccepts a list of run kinds besidestrueandfalse, such as[schedule, wake]: a failed or interrupted attempt of a listed kind retries by itself with backoff, while other runs, such as an answer to a message that may have acted, wait forbf queue ID --retryor--cancel(what a run records).
v21.0.1 - 2026-11-04¶
A patch release. The brain format (version: 8), bf.yaml, the reply schemas, the queue format and the search cache are unchanged; no upgrade step is needed, except to recover a queue that a device renumbering already stranded (below).
Fixed¶
- A new device number no longer starts an empty assistant queue. BF names a brain's queue and program-state folders by its device and inode numbers, and btrfs can number a device anew at boot: the queue then looked empty, stranding unresolved work, and window sensors restarted from
lookback. When the folder for the brain's current identity is missing, BF now renames the folder with the same inode whose queue is bound to the brain's path, together with its program state; a brain without a queue still restarts its window sensors fromlookback. Several matching folders, or one that cannot be read, such as after an interrupted write, make assistant commands fail withseveral assistant queues in the state folder runtime/ are bound to this brain (…)orassistant queue in the state folder runtime/ (NAMES) may belong to this brain but cannot be readinstead of choosing; collection and watch keep running (move or rename a brain). - Recovering an already stranded queue (manual). A brain that already ran after a renumbering has a new, possibly empty folder, which this release keeps. To recover the old queue: stop
bf watch, check thatbf queueshows no work you need, moveruntime/NEW(named bystat -L -c %d-%i BRAIN, orstat -L -f %d-%i BRAINon macOS) out of the state folder, rename the oldruntime/OLD-INODEfolder toNEW(andprograms/OLD-INODElikewise), then runbf queue.
v21.0.0 - 2026-11-04¶
A major release that makes assistants event-driven and lets them choose when to speak. A structured reply replaces answer pointers and status checks, a gate decides whether a scheduled run needs the model, an assistant can schedule its own next run, and one post channel replaces output routing. The brain format (version: 8), records, notes, the search cache and the queue format are unchanged; bf.yaml assistants need manual edits. Follow the upgrade steps below.
Breaking changes¶
replyreplacestextandstatus. An assistant withreply: {path: POINTER}reads a structured{say, wake}object from its harness's JSON stdout, such as/structured_output, and{{schema}}passes the harness that schema. Output that is not a JSON object, a missing reply or one that does not match the schema fails the attempt like a nonzero exit, which also catches a harness that exits 0 after a model error or its own timeout.nullor blanksaystays silent, except in answer to a message, where it fails as an empty answer did.bf validatereportsassistants.NAME.text: Extra inputs are not permittedand the same forstatus(structured replies). Withoutreply, stdout is still the plain message.postreplacesoutputs. A message is answered in its own conversation, asreply: {}did, and every other run, manual ones included, posts to the one channelpostnames.outputs,reply: {}andwhenare gone:bf validatereportsassistants.NAME.outputs: Extra inputs are not permitted. One answer makes at most one delivery; to notify a second channel, declare a second assistant or let the channel's script fan out.- Input channels need
send. Every channel an assistant reads must declaresend, so its messages can be answered:assistants.NAME.inputs: channel X requires send to answer its messages. - Runs of kind
wake.BF_TRIGGER,{{context}}'skind, a record'sattributes.triggerandbf update --dry-runrows may now bewake, and records may carryattributes.wake. Scripts that match the run kinds need the new value.
Added¶
- Gates. A schedule's optional
gate: {command: [...]}runs a deterministic program before the harness. It prints{"events": [...]}, at most 64 events and 64 KiB; no event completes the job without starting the model, and events reach the prompt in{{context}}. A failed gate retries by itself, since no harness ran, and a retried job reuses the events its gate saved, so a gate can keep "already reported" state inBF_STATE_DIR(gates). - Wakes. With
wake: {min, max}, a structured reply'swake: {in, reason}schedules one later run, clamped to those bounds. A newer request replaces the pending one, a failed run asks for none, and the wake run receives its reason in{{context}}.bf queuelistswakesby assistant, due time and the job running it (wakes). bf schema --kind assistant-replyprints the reply schema, for a harness that reads it from a file, such ascodex exec --output-schema FILE; it is published asassistant-reply.schema.json.
Changed¶
- Literal
}}in arguments. A command argument may hold}}, such as the end of inline JSON settings; only an unknown{{…}}placeholder fails. Before,}}had to be written} }. - Assistant safety. Keep prompts safe now states that an assistant with a shell or write tools can be steered by the mail, chat or web content it reads, whatever BF labels as data.
bf validateno longer checks an assistant's queue space per answer: with one delivery per answer and the 4 MiBmax_bytesbound, every answer fits.
Fixed¶
- The assistant guide stated that an
idempotentassistant retries up to 5 attempts after5 × 2^(n−1)seconds; it retries after 2, 4, … up to 300 seconds, for up to 20 attempts, as the code always did.
Upgrade from v20¶
- With v20 still installed, stop
bf watch, its service or timers and any script callingbf run,bf channelorbf queue. - Drain the assistant queue: run
bf update --kind assistant, then retry or cancel each pending, failed or uncertain job untilbf queuecountsshow onlycompleteandcancelled. A job v20 queued snapshots its old settings, which v21 cannot run: after upgrading, cancel any you missed withbf queue ID --cancel. - Upgrade with
uv tool upgrade brain-framework, or update a pinned brain's pin, and checkbf --version. - In
bf.yaml, for each assistant: - Replace
outputswithpost: CHANNEL, naming the channel its scheduled runs posted to, and deletereply: {}andwhen. Manual runs now post there too. - Add
sendto each channel listed ininputsthat lacks it. - Either switch to a structured reply: pass the schema, such as
--json-schema "{{schema}}"for Claude Code or Antigravity, setreply: {path: /structured_output}and deletetextandstatus; or keep a plain answer: deletetextandstatusand make the harness print plain text, since its whole stdout becomes the message. - Replace
} }workarounds in arguments with}}if you like; both work. - With a structured reply, rewrite each prompt's answer section: fill
say, ornullwhen nothing needs the owner. Delete rules such as "answer exactly-", answer marker lines and wrapper scripts that strip harness chatter. Move deduplication and threshold rules into a schedule'sgate, and addwake: {min, max}where the assistant should schedule its own follow-up. - Update scripts and prompts that match
BF_TRIGGER,attributes.triggeror{{context}}'skindfor the newwakekind. - Run
bf validate,bf skills DIRfor each skills folder,bf run NAMEonce per assistant andbf status --check, then restart watch.
v20.1.0 - 2026-11-01¶
A feature release for integrations and evidence hygiene. The brain format (version: 8), existing bf.yaml files, the search and read reply schemas and the search cache are unchanged. Upgrade steps: run bf skills DIR to update the packaged skills, and check that no sensor relies on the silent cut of record text above 4 MiB fixed below: set truncate_text: true on such a sensor. A new brain from bf init declares the standard vocabulary; an existing brain keeps its fields.
Added¶
- Skill behavior eval.
mise run eval:skillsruns five cases in headless Claude Code against a fresh copy of the example brain, isolated from user settings and provider tools, and grades the skill used, the cited ref, forbidden commands and written files. It needs a Claude login and spends tokens, so it stays out ofmise run all(contributing). - Sensor kit and standard vocabulary.
examples/sensors/_sensor.pyis a standard-library helper file to copy next to your sensors: window and state from the environment, bounded provider CLI calls and HTTPS fetches, identities, credential masking and records within BF's bounds;github-issues.pyshows a sensor built on it.bf initnow declares the standard vocabulary with default paths, so a sensor printingauthor_refs,sender_refs,statusand the like needs nofields:mapping in a new brain. The Gmail example printssender_refsandrecipient_refsinstead offrom_refsandto_refs, and the GitHub history examplestatusinstead ofstate: update a mapping copied from them. - Check saved sensor output.
bf collect SENSOR --input FILE(or-for stdin) validates and projects saved output with the brain's current mappings without running the sensor or saving anything, even for a disabled sensor: a contract test for sensors (check saved output). - Program environment. Sensors and routines receive
BF_PROGRAM, their window asBF_STARTandBF_END, andBF_STATE_DIR, a private directory on this machine for cursors and tokens kept between runs (what a program receives). - Forget and expire records.
bf forget REF...removes collected records and lists their digests inmemories/SOURCE/.forgotten, so collection never stores them again; a sensor'sexpire_afterremoves records older than its retention and skips older ones it prints again. Runs reportforgottenandexpiredcounts (keep, forget and expire records). - Retired sources. A sensor or routine with
enabled: falsemay omitcommand, so a retired source keeps its records searchable without a placeholder command. - Period plus scope. A search scope can combine a period with one other scope, such as
--scope "7d repo:github.com/owner/name"for the records naming a repository this week (scopes). - Text export.
bf export --kind itemsprints every note and record with its metadata, fields and text as JSON Lines, for retrievers outside BF such as embedding or multilingual search. - Assistant trigger and harness status. A harness learns why it runs from
BF_TRIGGER(input,scheduleormanual),BF_SCHEDULEand itsBF_START/BF_ENDwindow, so a wrapper no longer parses the prompt. The optionalstatus: {path, success}setting turns a failure the harness reports in its JSON output while exiting 0, such as a model API error, into a failed attempt with the usual uncertain or idempotent retry rules; the error names at most a one-word status, never the output (assistants).
Fixed¶
- Oversized record text. A record whose text exceeds 4,194,304 characters now fails its collection, as documented, unless the sensor sets
truncate_textormax_text_bytes; it was cut silently. The sensor settings now state the actual 4 MiB default and 1–4,194,304 byte range ofmax_text_bytes.
Changed¶
- Usage counts.
bf statususage covers the full 7 and 30 days on busy brains: rotation sums each past UTC day into one line instead of dropping the oldest events;sinceremains only while a cut made by an earlier release falls inside a window. Each window addskinds, the searches by scope kind and reads by page kind, andempty_kinds, the scope kinds of zero-result searches; the log still keeps no query text, refs or paths (limits). Windows now count today and the 6 or 29 UTC days before it, instead of the last 168 or 720 hours. - Packaged skills.
bf-useandbf-actioncheck thebfversion once per session instead of before every task, and askbf statusabout a pinned runtime only in a brain with auv.lock. Helpers run by their literal path (python3 SKILL_DIR/scripts/NAME.pywith the absolute folder) and take multi-line text from files, because hosts with strict permissions refused the$SKILL_DIRvariable and$'…'quoting, which blocked saving a decision and starting an action.bf-actionresumes only an action whose folder topic matches, not one that mentions the subject, andbf-maintain's description leaves choosing sources tobf-setup. Runbf skills DIRafter upgrading. - README. About half as long, with a quickstart after the first figure and each point made once; details moved to the linked documentation.
- Documentation. Every page reads faster with the same content: guides open with the main path, edge cases sit in reference sections or collapsed blocks, and dense paragraphs became tables and lists. Sentences over 40 words dropped from 84 to 30. Page paths, heading anchors and examples are unchanged.
- Major releases. A breaking change ships in a major release whenever the design needs it, instead of waiting for a quarterly window; related breaks still batch where practical (Contributing).
AGENTS.mdis about half as long and names the current scope: no model inference, provider SDKs or record sync in the core, integration helpers as a copy-in kit, and assistants, channels, watch and multi-brain retrieval open to improvements backed by real use. - Release tooling.
scripts/release.pyprepares a release in a clean clone that ships only the named paths, runs the gate, publishes after CI and CD, verifies the artifacts and syncs the primary checkout only when no other session changed a released path. The release checklist keeps only the judgment steps.
v20.0.2 - 2026-10-31¶
A maintenance release for repository tooling and contributor checks. The package behavior, the brain format (version: 8), bf.yaml, the reply schemas, the packaged skills, the assistant queue and the search cache are unchanged; no upgrade step is needed.
Changed¶
- Repository checks and workflow tools. Secret scanning uses Betterleaks 1.9.0 (
.betterleaks.toml), workflow linting uses jactionlint 2.4.0 and zizmor 1.31.1 with$/self-repository reusable workflow references, and dprint's Markdown plugin is updated to 0.28.0. - Linter, hook and task hardening.
pyproject.tomladds Ruff'sBLE,PLEandPLWrule families and rejects blankettyignore comments;lefthook.ymluses sequentialjobs;mise.tomlenforcesmin_version = "2026.10.21"andUV_MALWARE_CHECK=1oninstallandupgrade; andAGENTS.mdandbf-contributeformat rules with scannable lead-ins.
v20.0.1 - 2026-10-31¶
A documentation release that aligns the guides and packaged skills with v20. The brain format (version: 8), bf.yaml, the reply schemas, the assistant queue and the search cache are unchanged. Upgrade with uv tool upgrade brain-framework (or update a brain's pin), run bf skills DIR for each skills folder, and compare a brain's AGENTS.md with a scratch bf init copy to adopt the starter's new first line.
Fixed¶
- Guides match v20. Checks describes the
validate:policy shapesbf validateaccepts:index_notenames one index note,required_statuslists statuses andforbid_patternsholds up to 64 regular expressions.{{lines:FILE}}arguments document their real bounds: a file of at most 4 MiB, lines of at most 16,384 characters and at most 128 command items in all. Pages no longer mention the removedbf scheduleor queued trigger events, and the queue folder command follows a symlinked brain (stat -L). - Upgrades and recovery. Install and update runs the steps that need the previous release, such as draining the assistant queue, before upgrading, and ends with
bf status --check; its libyaml reinstall names'brain-framework[mcp]'so MCP users keep the extra. Troubleshooting no longer sendsunexpected assistant queue schemato the v19 steps. - Packaged skills.
bf-maintainfollows the same upgrade order, installs themcpextra when a host startsbf mcp, updates the watch service or timer you wrote instead of regenerating schedules and explainsassistant queue predates this release.bf-useand the starterAGENTS.mdthatbf initwrites search the brain before querying a source tool.bf-use,bf-actionandbf-setuppoint agents to the Markdown documentation at llms.txt, andbf-setupwarns that aCLAUDE.mdin a parent folder also replacesAGENTS.md.
v20.0.0 - 2026-10-31¶
A major release that trims BF's surface and settles deferred input rules. bf schedule and assistant triggers are removed, MCP becomes an optional extra (13 runtime packages instead of 36 on Linux and macOS), disabled programs stop reporting failures, and six ambiguous inputs that loaded before now fail with a message naming the fix. The brain format (version: 8), records and notes are unchanged; the assistant queue needs one manual SQL statement and the search cache rebuilds once. From this release on, breaking changes ship together in at most one major release per quarter. Follow the upgrade steps below.
Breaking changes¶
bf scheduleis removed. BF no longer writes systemd, launchd or cron files. To run unattended, keepbf watch --json --brain BRAINrunning as a user service you write yourself, as Watch and schedule updates shows for systemd and launchd. A timer that runsbf update --brain BRAINalso still works.- MCP is an optional extra.
uv tool install brain-frameworkno longer installs the MCP SDK, which cuts the base install from 36 to 13 runtime packages on Linux and macOS. Without the extra,bf mcpexits 1 and namesuv tool install --python 3.14 'brain-framework[mcp]'.uv tool upgradekeeps the extra once it is installed. - Assistant triggers are removed.
triggers, thesensor.changedevent and thetriggerkind of run are gone:bf validatereportsassistants.NAME.triggers: Extra inputs are not permittedand rejectstriggerin an output'swhen. Sensor changes start no assistant and record writes never touch the queue, so a collection can no longer fail after saving withSOURCE records were committed but their assistant event is not queued. - Queue format 2. The assistant queue drops its
triggerstable. Execution andbf statusrefuse a v19 queue withassistant queue predates this release; preserve it and follow the upgrade steps in the changelog. - Assistant replies and runs.
bf queueand statusmessagingdroptriggersandtrigger_counts, andbf updaterows no longer name atrigger. A record'sattributes.triggerisinput,scheduleormanual. Neither records nor{{context}}carryevent, and harnesses no longer receiveBF_ASSISTANT_RUN. - No program is named
bf. A sensor, routine, channel or assistant namedbfstopsbf.yamlfrom loading withsensors.bf: the name bf is reserved for BF addresses; rename the sensor and move memories/bf/ to its new name, because its records'bf:IDrefs read as BF addresses. Records left inmemories/bf/are skipped and reported until moved. - A BF address ending in a bare
#is invalid.bf read,bf searchand the MCP tools rejectbf://brain/projects/plan.md#as invalid input (exit 2), as they have rejected a plain ref ending in#since 18.5.0; before, it read and scoped the whole note. A note writing one in a link, frontmatterlinks,sources,entityoraliasesis invalid and unsearchable, and a record holding one in itslinksoraliasesis skipped and reported. A relative link such asplan.md#still links the whole file. - Search scopes take no section.
--scope bf://brain/projects/plan.md#decisionand--scope memories/SOURCE#xare invalid input (exit 2) in the CLI, the MCPsearchtool and eval suites, like a section's path. A suite holding one fails to load and names the field, such ascases.1.scope. bf init --name ""is invalid. An empty or blank name exits 2 and creates nothing. Omit--nameto derive the name from the folder.- libyaml is required. Without it, every command that reads YAML exits 1 and names the fix,
uv tool install --reinstall --python 3.14 brain-framework. BF used to fall back to PyYAML's slower pure-Python parser, which rejects some YAML that libyaml accepts. - OKF
sourcesresources hold at most 8,192 characters, like frontmatterlinks. A longer one fails asinvalid frontmatter: sources: reference exceeds 8192 characters.
Changed¶
- Disabled programs report no failure. A disabled sensor, routine or assistant shows no
failed,error,failuresorlogin status, coverage or watch, adds noattentionentry and never failsbf status --check. Its unresolved jobs stay inbf queueandmessaging, and count again once re-enabled; a removed assistant's jobs still fail the check. This reverses v19's "even once disabled". - One breaking window per quarter. Breaking changes now wait for one batched major release, at most once a quarter, and a new rule that rejects input loading today warns first where it can (Contributing). The
bf watchterminal dashboard is frozen: it gets fixes only, and new run information goes tobf watch --jsonandbf status. - The search cache rebuilds once on first search or read.
Upgrade from v19¶
- With v19 still installed, stop
bf watch, its service or timers and any script callingbf run,bf channelorbf queue, including jobsbf scheduleinstalled: they runbf updateand keep working after the upgrade, so re-enable them at the end or replace them with a watch service. Already upgraded? Reinstall the previous release withuv tool install --python 3.14 'brain-framework==19.1.0', do steps 1 and 2, then upgrade again: v20 cannot drain a v19 queue or recover a v19memories/.pendingjournal. - Drain the assistant queue: run
bf update --kind assistant, then retry or cancel each pending, failed or uncertain job, including those of disabled assistants, untilbf queuecountsshow onlycompleteandcancelled; deliveries may stay. Ifmemories/.pendingexists, run v19'sbf build. - Back up the brain and the state directory's
runtime/folder, then upgrade withuv tool upgrade brain-framework, or update a pinned brain's pin, and checkbf --version. If an agent host startsbf mcp, installuv tool install --python 3.14 'brain-framework[mcp]'instead and check thatuv tool list --show-extrasshows[extras: mcp]. If a command reportsreading YAML needs PyYAML built with libyaml, runuv tool install --reinstall --python 3.14 brain-framework, or'brain-framework[mcp]'when you use MCP: a reinstall without the extra drops it. - Update the queue in place; never delete it. It lives under
$XDG_STATE_HOME/bf/runtime/(normally~/.local/state/bf/runtime/), in the folderstat -L -c %d-%i ~/brainnames (stat -L -f %d-%i ~/brainon macOS). Skip this step when that folder holds noqueue.sqlite3: runningsqlite3would create an empty file BF then refuses.
queue=~/.local/state/bf/runtime/"$(stat -L -c %d-%i ~/brain)"/queue.sqlite3
[ -s "$queue" ] && sqlite3 -bail "$queue" "BEGIN; CREATE TEMP TABLE drained(n INTEGER CHECK (n = 0)); INSERT INTO drained SELECT count(*) FROM jobs WHERE state NOT IN ('complete','cancelled'); DROP TABLE triggers; PRAGMA user_version=2; COMMIT;"
The statement refuses a queue that still holds unresolved jobs, and a rerun exits 1; both change nothing. Python's sqlite3 module can run the same statements.
1. In bf.yaml, delete triggers: and trigger from each output's when. Give a trigger-only assistant a schedule, such as schedules: {review: {every: 3600}}, with a prompt that reads bf read memories/SENSOR/24h. Rename any program named bf, also in the inputs, outputs and --sensor, --routine or --assistant selectors that name it, and move its records with mv memories/bf memories/NEW, renaming any memories/bf exception in .gitignore; its log and run history start again under the new name.
1. Run bf validate: it names each note holding a BF address that ends in a bare # or an OKF sources resource over 8,192 characters, and each record whose links or aliases hold such an address. Remove each # or name the section, shorten the resource, and fix the sensor that printed the record before collecting it again.
1. In scripts, host configuration and evals/*.yaml, scope the whole note and expect the section, drop the #… from memories/SOURCE#… scopes and set or omit bf init --name. Update prompts and scripts that read event, attributes.trigger == "trigger", messaging.triggers, trigger_counts or BF_ASSISTANT_RUN.
1. To run unattended, re-enable the jobs you stopped in step 1, or replace them with the user service from Run watch as a service. Never run both on one brain.
1. Run bf skills DIR for each skills folder, then bf validate, bf eval and bf status --check, and restart watch.
v19.1.0 - 2026-10-29¶
A feature and fix release. The brain format (version: 8) and the reply schemas are unchanged; the search cache rebuilds once on first search or read. Upgrade with uv tool upgrade brain-framework (or update a brain's pin) and run bf skills DIR to refresh installed skills.
Added¶
- Assistant schedules accept wall-clock
at: "HH:MM"times with optional IANAtimezoneanddays(mon–sun) alongside intervaleveryschedules, passcontext.schedulein{{context}}for scheduled runs, and treat an empty scheduled or triggered reply without output metadata as a silent no-op that advances the schedule without writing an empty record. - Assistants with read-only harnesses can set
idempotent: trueto automatically retry pre-delivery harness failures and interruptions up to 5 attempts with exponential backoff (5sto300s), andbf queue ID --retryresets the retry budget. - Top-level
fields.<name>declarations inbf.yamlaccept an optional default JSON Pointerpath, used when a sensor does not specify an override insensors.<sensor>.fields.<name>. - Sensor, routine, assistant and channel
commandarguments support{{lines:relative/path.txt}}, expanding non-blank, non-#lines from a brain-relative UTF-8 file (up to 64 KiB and 500 lines) into separate arguments and checking the file duringbf validate. - Sensors can set
truncate_text: true(and optionalmax_text_bytesup to 1 MiB) to truncate oversizedrecord.texton a valid UTF-8 codepoint boundary, stampattributes.truncated: trueand log the record ID instead of failing the whole batch. bf.yamlaccepts a top-levelvalidate:policy (max_stale_days,warn_stale_days,index_note,required_statusandforbid_patterns) enforced bybf validate.bf updateruns up to four due sensors concurrently while returningwindowsin configuration order.- Section search passages include the note's filename stem (when distinct from its H1 title) and declared
aliasesin their lexical context, so multi-word queries combining a note's stem or alias with a section's body terms match that section directly. - Zero-result searches record up to 8 unmatched query tokens (up to 64 characters each) in local
usage.jsonl, andbf statussurfaces the top 10 recurringempty_termsin each usage window.
Fixed¶
- A channel input no longer stops when a provider edits a message it already admitted: the edit keeps the admitted version and starts no job, and the messages after it are admitted. Before, every poll failed with
a channel reused an event id with different contentuntil the edited event expired 35 days later. - Editing an assistant's
schedules,triggers,inputsorkeepno longer fails its queued jobs withassistant configuration changed, and once a harness has answered, only removing or disabling its assistant or changing an output channel stops its saved answer from being recorded. - A harness or channel
sendcommand that never started, such as one not onPATHunder a timer's shorterPATH, leaves its jobfailedinstead ofuncertain, and its delivery retries like an idempotent one instead of waiting asuncertain: nothing ran, so retrying is safe. - An unresolved
bf runno longer holds back the saved answer of a laterbf runof the same assistant: each manual run is its own slot. - With several brains selected, a read's
outlinerefs and a claim'starget_refarebf://addresses, likesections, so reading them no longer fails withreference exists in several brains. - A sensor or routine run that waited 120 seconds for a busy brain no longer waits another 120 seconds to record that failure.
bf registerleaves the registry file, and its inline comments, unchanged when the brain is already registered at the same path.bf channelrejects invalid arguments with exit code 2 before selecting a brain, as every other command does, andbf skillsreports its destination as an absolute path.- The example Calendar, Drive, Gmail, Git and GitHub sensors ignore a Git hook's repository variables, such as
GIT_DIR: started from a hook, the Git history sensor saved the hook's repository commits under every repository's name. - Search, the retrieval example and the link reference say that tags weigh more than body text and less than headings, as ranking does.
Changed¶
bf-use's guarded-write helper replaces a whole note only from--new-file FILEgiven alone and never reads standard input, which an agent's shell may hold open; its guide writes--old=TEXT --new=TEXTso a passage starting with-stays an argument. Runbf skills DIRto update installed skills.- The Assistants guide's complete example runs Claude Code with the prompt on standard input, as the page recommends for private messages, and Core concepts lists channels among a brain's programs.
- Development tools: uv 0.13.6, dprint 0.64.3 with the Markdown 0.27.1 plugin, trivy 0.76.1, ruff 0.17.3, ty 0.0.94, pytest 9.2.0, zensical 0.0.73, and the workflows pin mise 2026.10.21,
jdx/mise-actionv5.2.4 andpypa/gh-action-pypi-publishv1.14.3. The locked environment moves to starlette 1.10.0, sse-starlette 3.6.0, httpx2 and httpcore2 2.16.0 and pycparser 3.12.
v19.0.1 - 2026-10-20¶
A fix release. The brain format (version: 8), bf.yaml, the reply schemas and the search cache are unchanged. Upgrade with uv tool upgrade brain-framework (or update a brain's pin); bf skills DIR refreshes the bf-maintain operations guide, whose only change is naming assistants where it still said prompts.
Fixed¶
bf updateandbf build --reprojectno longer wait for the brain's exclusive writer lock when the search cache is current: they check the cache's pages (PRAGMA quick_check(1), with a 64 MiB page cache) and compare file fingerprints under the shared reader lock, so a refresh with nothing to index runs beside searches and long reads and commits nothing. A refresh that finds changes still takes the writer lock and checks the pages again if another refresh replaced or changed the cache meanwhile.- The privacy page, the
bf-maintainoperations guide and the exampleprompts/.gitignorename an assistant's harness and runs where they still said prompt, as 19.0.0 renamed them.
v19.0.0 - 2026-10-17¶
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.
v18.5.0 - 2026-10-14¶
A feature and review release. The brain format (version: 7) is unchanged; bf.yaml gains the optional silent_after and keep settings, which an older bf rejects; the reply schemas only gain optional fields, and the search cache rebuilds once. Upgrade with uv tool upgrade brain-framework (or update a brain's pin), run bf skills DIR to update all four skills, copy the updated example weekly-review routine and gmail-headers sensor into your brain, preserving local adaptations, and merge the AGENTS.md line that now names prompts/.
Added¶
- A sensor's
silent_after(seconds) reports a scheduled source that keeps succeeding without a new or changed record:bf statusmarks it"silent": true, andattention, the home page andbf status --checklist it. Freshness proves a successful run, not new evidence: a filter or account drift used to look healthy.bf statusand thememoriespage give each source'schanged, the newest time this brain gained a new or changed record of it. keepbounds generated output. An action routine'skeep: Nremoves its actions older than the newest N while they still hold only theACTION.mdthis machine wrote: an edited report, a folder holding another file and an action written beforekeepstay. A prompt'skeep: Nremoves its oldest run records after each run, never another file of its folder, and never fails a recorded run. Replies count them asremoved.bf statusnames each brain'sruntime: theinstalledbf version and, read as data from the brain'suv.lock, thepinnedone. Agents compare their major versions instead of parsing the lock.bf validatereports an enabled prompt file above the 120,000-byte limit, which every run would reject.- A runnable offline prompt example,
examples/prompts/, usescatas a stand-in harness withrefresh: 0: a piped message becomes a record that search finds. The prompt guide starts with it, and troubleshooting covers failed prompts: JSON output withtext, the 120,000-byte limit on standard input too, skipped scheduled runs, harness sign-in and tool permissions. bf-maintaincovers prompts: declare one with an explicitrefresh(an enabled prompt runs every 30 minutes by default, unlike sensors and routines), atimeoutabove the harness's own limit and atextpointer; test it without a model throughcommand: [cat], then run it once withbf run PROMPT --stdin. It treatsmemories/NAME/records as model output and grants the harness only the tools it needs.- Reads return
backlinks_omitted, the number of relation groups beyond the 64 they preview, counted across the selected brains: more than 64 relations used to drop the rest silently.
Changed¶
- A program another process is running, such as a manual
bf collectduringbf watch, isskippedinbf updateinstead of failed: watch no longer alerts a failure that run history never records. bf runsuggests close prompt names too:unknown routine or prompt asistant; … did you mean assistant?.- A scheduled prompt that is not due when it takes its lock, because another process ran it or it waits to retry a failure, says so instead of claiming another run just succeeded.
- The four skills are 30% shorter (17,009 → 11,919 words) without dropping a procedure or safety rule: each shared rule lives once, references link the documentation for exact contracts, and long steps are split. They compare
runtime.pinnedwithruntime.installedinbf statusinstead of reading a brain'suv.lock. bf-actiondefines when an action is done: its Outcome is filled and its TODO has no open box. Discovery resumes only open actions, closing resolves every open task, and later work starts a new action linking the done one.bf initnamesprompts/besidesensors/androutines/in the brain'sAGENTS.md; merge that line as Refresh brain instructions shows.- The documentation gives each rule one owner: timing and failure backoff in Watch and schedule, program names in the file formats, ranges in Limits, dry runs and status fields in Commands, scopes and incomplete answers in Retrieval. The README's Try it installs BF and links Getting started; the guides run copied example scripts as executables.
- The example weekly review lists scheduled programs that failed or are late, says when an empty week or coming week may come from a sensor needing attention, and writes a review when attention is its only content.
- Searches, reads and each MCP call no longer check every record file: the cache keeps each
memories/SOURCEfolder's fingerprint and lists only folders that changed, so on a brain of about 50,000 files a warm search checks its cache in about 16 ms instead of 170 ms (in-process timings on one Linux machine). Collection renames records into place, which always changes their folder; a record file edited in place, which collection never does, waits forbf build. Authored folders,bf buildandbf validatestill list every file. - The home page lists projects needing review first in the space
changedused to take:changednames only other notes, in brief (ref,kind,title,dateortime,modified,review), and the 32 KiB budget is measured on the reply as printed. A brain whosechangedlist repeated its projects used to show only one of the projects due for review. - Deep listing pages stop at their window: with one selected brain the offset is skipped in SQL, so a source page at offset 8,000 answers in about 65 ms instead of 300 ms on the same machine, and later pages of a large exact read no longer rebuild its backlinks.
Fixed¶
bf watchstops a collection whose start a cancellation interrupted, and signals its collection and prompt workers together, once each, so they stop in parallel.bf updatedates its due list once it holds the cycle lock: waiting for another update no longer leaves newly due programs for the next cycle.- A prompt answering a message and a scheduled run of the same prompt no longer overwrite each other's log entries.
- A prompt file above the limit reports
file exceeds 120000 bytesinstead of 120001. bf build --reproject --dry-runcounts changes without holding every reprojected record, and keeps only the failures its reply shows.- Programs no longer inherit
DOTNET_STARTUP_HOOKS,R_PROFILE_USER,LUA_PATHorLUA_CPATH, which load code before the program starts. - The contract check accepts a configuration value that stops listing its allowed values, which widens what files accept, as a minor change.
- Tests give cold interpreter starts the documented 120-second deadline and cap parallel workers at eight, so a loaded machine no longer fails the gate.
guarded-write.pyserializes the check, write and rename of one file among concurrent helpers with an advisory lock belowXDG_STATE_HOME(or~/.local/state), so of two sessions that read the same digest only one succeeds; before, both could report success while one edit was lost. An editor that takes no lock can still save between the helper's last check and its rename.evidence.py readkeeps thestaleandproblemsof every page of a large exact read, so a capture refuses, and a comparison reportsunknown, when a later page was incomplete.- The example Gmail headers sensor no longer misses messages received in the first or last fraction of a second of its window: it widens Gmail's whole-second search outward and filters exactly.
- The prompt guide's Claude Code command allows the read-only
bf readandbf searchcalls its prompt asks for, and the release checklist reads the workflows' mise pin despite its inline comment. - Documentation matches behavior:
--promptandupdate --kindrepeat, prompts get name suggestions, a prompt dry run appends to its own log, program names are unique across sensors, routines and prompts and neverbf,bf initcreates noprompts/folder, and an exportedBF_BRAINtakes precedence over the working directory. - A read of a note ref ending in a bare
#is invalid input (exit 2), like a scope: it read the whole note under a ref no backlink or reminder matched, so the note listed itself as a backlink and lost its tasks and review signals. An offset on the home page or thememoriesoverview exits 2 too. bf validateresolves an alias that a later note declares before checking links, instead of reporting a missing record that exact reads resolve.- Spelling
suggestionsfold Latin accents as promised (equipe, notéquipe), and a paged read without sections inside it omitsoutlineinstead of returningoutline: [].
v18.4.0 - 2026-10-13¶
A feature release. The brain format (version: 7) and the search cache format are unchanged; bf.yaml gains an optional prompts: section, which an older bf rejects, and the reply schemas only gain optional fields. Upgrade with uv tool upgrade brain-framework (or update a brain's pin), run bf skills DIR to update bf-maintain, which now covers prompts, and the retrieval guide, and copy the updated example hooks and weekly-review routine into your brain, preserving local adaptations.
Added¶
- Prompts run your agent harness over the brain, every 30 minutes by default or now with
bf run PROMPT --stdin. Declare one underprompts:with a Markdownpromptfile inprompts/and a direct-argvcommand: BF expands{{brain}},{{home}},{{start}},{{end}}and{{input}}in the file once, then passes it as the command's{{prompt}}argument or, without one, on standard input. BF never runs a model itself. Each successful run becomes a record inmemories/NAME/with the reply as its text (textselects it in JSON output, such as/response), its input, window, duration and the harness's other output, such as token usage, so later runs,bf searchand your agents read it back; those records rank like a low-priority source, so a summary never outranks its evidence. See Run prompts. bf updateruns due prompts after sensors and routines, outside the update lock;bf watchruns them in a second process beside collection, so a long agent run never delays a sensor, and marks them@with their run counts. A direct run never waits for a scheduled one and leaves the schedule's history unchanged, failures included; a scheduled run checks again under its lock that no other process just ran it.bf update --kind sensor|routine|prompt, repeatable, keeps only those kinds of program;update,watchandscheduleaccept--prompt NAMEselectors.- The example session hook names failing or overdue prompts in its attention line, beside sensors and routines.
bf statusreportspromptswith their state, freshness, runs, last run, latest record and failures;attentionand the home page list failing or overdue prompts, andbf validatechecks that each enabled prompt's file exists.
Changed¶
bf runtakes a routine or a prompt: its argument is namedPROGRAM.- A routine's
{{prompt}}placeholder is invalid, as before; only a prompt's command takes it. - CI and security workflows pin
jdx/mise-actionv5.1.1. The explicit mise2026.10.0pin keeps tool-manager upgrades deliberate; the action's 24-hour release-age default applies only without that pin.
Fixed¶
- Cancellation during sensor or routine startup now kills the newly created process group. Markdown complexity tests compare CPU-time growth, and cancellation tests wait for observed process termination, avoiding fixed-speed assumptions on slow CI runners.
- Period pages and search scopes place records without
timebyattributes.observed, including source counts and ordering across brains. Replies keep observation separate from event time; records with neither timestamp remain outside periods, andundatedstill selects every record without event time. - The
weekly-reviewexample lists projects as plain bullets, with overdue reviews first and earliest deadlines first, and separates the open-task preview from its surrounding paragraphs. Generated reviews no longer create duplicate checkbox tasks; complete work in the owning notes. - The session and prompt hooks keep nonempty stale cache results while collection runs, showing “Index refreshing”. They tolerate only the exact stale-cache identity problem; empty generations, malformed metadata and other problems stay silent.
v18.3.0 - 2026-10-07¶
A review and feature release. The brain format (version: 7) and bf.yaml are unchanged; the reply schemas only gain optional fields and the search cache rebuilds once. Upgrade with uv tool upgrade brain-framework (or update a brain's pin). Run bf skills DIR to update bf-use, and copy the updated example hooks, weekly-review routine and any new sensor into your brain.
Added¶
bf searchsuggests close words the brain holds for each misspelled word:"suggestions":{"retension":["retention"]}besideunmatched.- A claim names the note or record that owns its target, when exactly one item of its brain does, as
target_refandtarget_title: follow it without another search. bf collect --dry-runreports theadded,updated,unchangedandremovedcounts a collection would commit, and"removal_refused": truewhen the snapshot guard would refuse it, before you pass--allow-removal.bf watchwarns, likebf schedule, when its interval is at least the shortest selectedrefresh, which runs that program late and makesbf statusreport it overdue.- A mistyped
--brainname suggests close registered, enclosing or referenced brain names:did you mean work?. - The example
gmail-headers.pysensor collects Gmail senders, recipients, subjects, labels and dates throughgws, never message bodies, withperson:email/links, agmail-thread:link per conversation and an RFC 2392mid:alias.
Changed¶
- Writers also lock the brain folder itself: two processes with different
XDG_STATE_HOMEvalues, or two accounts sharing a brain, used to commit at once, and one's recovery could roll back the other's committed records. A filesystem that cannot lock a folder, such as NFS, keeps the state lock alone. - The
weekly-reviewroutine names the projects to review by ref instead of linking them: its links flagged every listed project with newer evidence, so each later review counted the earlier ones. bf initwrites its starter files from the package'sstarter/folder; the generatedAGENTS.mdnow holds one line per paragraph, so the refresh comparison shows every wrapped line once.- A search scoped to an authored folder no longer counts collected sources, and a cache is checked against the layout bf builds in one comparison. Tests run in parallel.
Fixed¶
bf evalranks expected refs among the first 50 results even when they span several reply pages: a search reply stops at its 32 KiB budget, so a ref at rank 46 among long results read as missing and MRR dropped.- An action's
projectsinclude projects itsACTION.mdlinks by entity, alias or BF address, as each project's backlinks already listed the action; only path links counted. - An identity whose BF address percent-encodes a format character, such as
bf://brain/people/bob%E2%80%8B, is invalid like its raw form: it looked like another subject's address. - A footnote-looking line inside a code fence no longer hides the sections after it: its indented lines closed the fence early.
- Period pages and scopes accept a trailing slash, such as
bf read 2026-09/or--scope 7d/, like folder and tag pages. - A file that failed to read for a reason other than permissions, such as an I/O error on a network mount, is read again on the next refresh instead of staying skipped until it changed; the search cache rebuilds once.
- A cache that another program locks, such as an open
sqlite3shell, names the lock instead of advising to check free space. bf statuslists programs nameddate,time,fieldsorattributeslike any other.bf init,bf skillsand other commands reject an argument that is not UTF-8 as invalid input before writing;initandskillsused to create every file, then fail.- Recovery clears an interrupted record transaction that left one temporary file beside a full journal; every later collection used to fail.
bf watchwaits for and stops its update when the terminal closed while it was stopping, instead of leaving it running.- The bf-use
guarded-write.pyhelper refuses a passage that occurs twice in overlapping positions, as it refuses other repeated passages. - The example hooks and the
weekly-reviewroutine escape control and invisible format characters, asbfreplies do: decoding the JSON restored them, so a shared note's title could reach the agent's context or a review action as hidden text. Copy the updated examples into your brain.
v18.2.0 - 2026-10-06¶
A skill release. The brain format (version: 7), bf.yaml, the reply schemas and the search cache are unchanged. Upgrade with uv tool upgrade brain-framework (or update a brain's pin), then run bf skills DIR to install bf-action and update bf-use.
Added¶
- A fourth packaged skill,
bf-action, starts, resumes, hands off and closes a tracked work session. Invoking it with a topic, such as/bf-action website-reviewin Claude Code, is the request to start that action: the agent resumes an open action on that topic or, when none exists, finds the owning project, createsactions/YYYY-MM-DD_website-review/ACTION.mdand fills its Context, TODO and Resume, with no need for wording such as "start an action". The action guide, the working-context and handoff guides,new-action.py,check-handoff.pyand the action template move frombf-usetobf-action;bf-usekeeps retrieval and writing knowledge back.
Upgrade: run bf skills DIR to install bf-action and update bf-use, which removes the moved files. If you edited any bf-use file, the folder reads modified and stays unchanged: back up your edits, then rerun with --force, which keeps edited files the new version no longer ships. A Claude Code SessionStart hook that runs bf-use/scripts/check-handoff.py must point at bf-action/scripts/check-handoff.py. bf init now names both skills in the brain's AGENTS.md; merge that line as Refresh brain instructions shows.
v18.1.5 - 2026-10-06¶
A search fix. The brain format (version: 7), bf.yaml, the reply schemas, the packaged skills and the search cache are unchanged. Upgrade with uv tool upgrade brain-framework (or update a brain's pin); a copied prompt-context.py hook can take the example's new word list.
Fixed¶
- Search drops
other,othersandanother, and the Frenchautre,autres,maandta, like other function words. In a mostly English brain,Pourquoi Kotlin plutôt qu’un autre langage ?ranked first a short French note that only sharedautreswith the question, a rare word that outweighed the subject; the note about Kotlin now ranks first. A query made only of such words still searches them literally. The exampleprompt-context.pyhook mirrors the list.
v18.1.4 - 2026-10-04¶
A review release of fixes. The brain format (version: 7), bf.yaml, the reply schemas and the packaged skills are unchanged; the search cache rebuilds once. Upgrade with uv tool upgrade brain-framework (or update a brain's pin); no other step is needed.
Fixed¶
- Search no longer lands on a section without the matching text: in a copied document with several H1s, text under a later H1 ranked as the H2 above it, whose exact read stops at that H1. An H1 after the first section is now a section of its own. The search cache rebuilds once.
- A record's fields other than
textare bounded by their encoded size, as the reply limit counts bytes: a record of long non-ASCII links or aliases passed the 2 MiB check, then every exact read of it failed withresponse exceeds its byte limit. Collection now rejects it withfields other than text exceed 2 MiB. - A registered brain whose folder exists but cannot be reached, such as a locked folder, is reported as
registered brain directory exists but cannot be reached; restore access to itby search, read andbf statusinstead of as absent, whose advice to register it againbf registerthen refused. A registered path that became a regular file is absent everywhere, sobf registertakes over its name. - An empty value, as an unset variable gives, is invalid input for
bf collect "",bf run "",--sensor "",--routine "",bf collect SENSOR --since ""andbf build --reproject "": they used to name an unknown program, collect the default window or rebuild the whole cache instead of reprojecting. - A zero-length window such as
0dis an invalid period forbf readand--scopealike; the read used to return an empty page while the scope failed withsince must be earlier than until.bf validatereports a link to such a page as an unresolved BF target. bf mcpno longer writes the MCP SDK's log line for each rejected or failed tool call to stderr; the reply carries the error.- Excerpts of a large passage holding a few characters that folding changes, such as
²or a no-break space, are computed faster.
Documentation¶
- The four-tool guide and the watch example give the working checkout command,
uv run --project CHECKOUT bfinside a copied brain; the README's four-tool reply names what it trims.
Added¶
scripts/verify-release.sh X.Y.Zverifies a published release in one command: the annotated tag on origin, a non-draft GitHub release holding exactly the wheel and source archive, PyPI digests matching them, their build attestations and a clean install of that wheel that initializes, validates, searches and reads a brain. The release checklist now gives the commands for the release worktree, checking tasks with the pinned mise, waiting for CD and syncing the primary checkout, runs the gate withGITHUB_ACTIONS=trueand asks for an independent review before committing. Tests coverscripts/verify-release-tag.sh, the guard CD runs before publishing.
Changed¶
- Development tools: Python 3.14.8, uv 0.12.23, dprint 0.60.1, lefthook 2.1.16, trivy 0.75.0 and mise 2026.10.0 in the workflows. The package smoke test builds its environments in the disk cache instead of
/tmp, and every test subprocess has a timeout.
v18.1.3 - 2026-10-04¶
A documentation release. The package behavior, the brain format (version: 7), bf.yaml, the reply schemas and the search cache are unchanged; no upgrade step is needed.
Documentation¶
- The loop diagram names its five steps (gather, normalize, connect, act and learn), labels the agents' search and read and starts the act arrow from the agents rather than from
bf. - The brain session diagram shows the agent noting its conclusion in the project note, as its "writes the outcome back" claim says, and the review diagram shows the full
bf read project:new-websitecommand. - The watch screenshot shows the log path the dashboard prints,
logs/unavailable.log, instead of an outdated state-directory path, and the README shows it at the same width as the other diagrams. - The logo's title and description describe the picture instead of design notes.
v18.1.2 - 2026-10-04¶
A documentation release. The brain format (version: 7), bf.yaml, the reply schemas and the search cache are unchanged. The packaged bf-setup skill only changes its Claude Code guidance: run bf skills DIR to refresh installed copies.
Documentation¶
- The README presents BF as a second brain on your own computer: agents opened in a brain start from your projects and evidence instead of a blank session. Four diagrams show the gather-to-learn loop, a blank session beside a brain session, how field mappings turn four tools' names into one knowledge graph and how a project is flagged for review when its linked evidence changes. New sections cover the questions a brain answers and the tools behind them, the sources one brain can gather,
bf.yamlas the coordination hub, personal and team brains shared through Git and the trade-offs: local execution, provider setup and the agent harness's data terms. It also points agents tollms.txt. - Claude Code 2.1.277+ loads a brain's
AGENTS.mdon its own, so the guides no longer ask for aCLAUDE.mdholding@AGENTS.md; the agent guide keeps that import as the fallback for older versions, and an existing brain may keep itsCLAUDE.md.
Changed¶
- The release scripts carry a
.shextension:scripts/push-and-tag.sh,scripts/release-notes.shandscripts/verify-release-tag.sh.
v18.1.1 - 2026-10-03¶
A documentation release. The package, the brain format (version: 7), bf.yaml, the reply schemas and the search cache are unchanged; no upgrade step is needed.
Documentation¶
- The documentation site gains offline search (Ctrl+K or
/), header tabs for Start here, Guides, Reference and Privacy and legal, page icons, a light, dark and system color toggle, GitHub repository and edit links, and a footer with privacy, notices and license links. The changelog and license are site pages, so every navigation entry stays on the site. Search keeps the site free of accessibility violations in an axe-core audit: the closed dialog leaves the tab order, its controls are named and its result paths meet contrast. - Agents can read the guides as Markdown through
llms.txt, which summarizes each guide,llms-full.txtorindex.mdbeside each page, which each guide's HTML advertises as its Markdown alternate. The overview now links every guide.
v18.1.0 - 2026-10-03¶
A review release of fixes. The brain format (version: 7), bf.yaml and the reply schemas are unchanged; listed fields are bounded, and the search cache rebuilds once. Upgrade with uv tool upgrade brain-framework (or update a brain's pin), then run bf skills DIR.
Fixed¶
bf skills --forcekeeps a file you edited that the new version no longer ships, as it keeps every other file BF does not ship, instead of deleting it.- A record commit whose completion marker landed before a final directory sync failed reports success instead of "nothing was written".
- A registered brain whose folder exists but cannot be reached fails with
cannot reach the brain registered as NAMEinstead of advice to register it again, whichbf registerthen refused. bf run --hook "", as an unset variable gives it, is invalid input instead of running the first argument as a routine;bf status --check --watchnames--watchin its invalid-input line.bf eval --baseline=~/eval.jsonexpands~, like every other path option. Without a home directory, commands fail with onebf:line namingHOMEinstead of a traceback.bf scheduleinstalls systemd units belowXDG_CONFIG_HOMEwhen it is set, where the user manager reads them.bf watchruns updates for apip install --userinstallation, andbf watch --jsonreports unavailable desktop alerts with abf:line on stderr instead of a JSON object.- A claim footnote's label can no longer change a note's structure:
[^```]or[^<pre>]used to open a block that hid the sections and links after it. Links in a footnote's continuation paragraph, indented by four spaces or a tab, now support the section that cites it, and labels match regardless of case, as on GitHub. - A copied document whose headings repeat an explicit anchor, or whose title's slug another heading anchors, stays searchable: the later heading takes a generated slug. OKF notes still fail
bf validate. - An OKF
sourcesentry whose?rel=names an undeclared relation still cites its target in reads;bf validatestill reports the relation. - Validation messages count only the distinct problems they do not name.
- The example sensor, routine and hook guides make a downloaded script executable with
chmod +xbefore configuring it as a command, since a download drops the executable bit andbf validatethen rejects the program;github-history.mdcopies from the release tag matchingbf --versionand says when to raisetimeoutfor a large backfill. - Programs no longer inherit
ZDOTDIR,PHPRCorPHP_INI_SCAN_DIR, which make zsh or PHP run code before the program starts. - The guarded-write helper follows a linked brain folder and links above it, such as
/homeon Fedora Atomic or/tmpon macOS, as bf does, instead of refusing every absolute path through them; links inside the brain are still refused. bf-useasks before updating the skills for a newerbf, and names the folder to pass tobf skills.- Quitting
bf watchwhile an update is still stopping printsbf: stopping the active update; this can take up to 60 secondsinstead of leaving a silent terminal. - An exact read across several brains returns the brain that holds the ref with a
problemsentry for another brain that fails, such as on a malformed record of a shared source or a busy writer, instead of failing; when no brain holds it, the failure stands. - A page's address as
--scope, such asbf://brain/projects,bf://brain/7dorbf://brain/memories/gmail, is invalid input instead of silently matching nothing; use its brain-relative form. - Listed
fieldsstop at 2 KiB of JSON per item, in field-name order, so a shared brain declaring hundreds of fields cannot push home, a listing or a note's backlinks past the reply limit; exact reads keep every field. - The retrieval reference states that a relation page's
totalincludes the claims of its narrower relations.
v18.0.0 - 2026-10-03¶
A review release. Review signals now follow upstream changes and the evidence a note cites, the home page and exact reads summarize what needs attention, and every interface reports invalid input the same way. The brain format (version: 7) and bf.yaml are unchanged apart from accepting empty sections; stricter identity rules and bounds are listed below. Reply schemas only gain optional fields, and the search cache rebuilds once.
Breaking changes¶
- Invalid input. A usage error prints one stderr line,
bf: invalid input: ARGUMENT: reason (see bf COMMAND -h), with exit 2, instead of Typer's usage text and boxed panel; help is unchanged. MCP clients receive the same rejections asinvalid input: ARGUMENT: reasonnaming the tool argument (query,scope,reforrel), including malformed refs, periods, addresses, scopes and relations that used to return bare messages. - Exit codes. These are invalid input (exit 2) instead of failures (exit 1):
--relon a page written with a trailing slash (projects/) or on an existing folder page,--relwith a#section, a section of a page (bf read tasks#x,bf read bf://NAME/7d#x), an invalid period belowmemories/SOURCE/, a ref that is not UTF-8 andbf watch --poll-interval nan. - Empty values. An explicit empty
--brainis invalid input instead of falling back toBF_BRAIN, the enclosing brain or every registered brain, and so are an emptyPATHforinitandregister,DIRforskillsandschedule --output. - Scopes and retrieval cases. A note or page section as
--scope, such asprojects/atlas.md#next-actions, is invalid input instead of silently matching nothing.bf evalchecksexpectandforbidrefs asbf readchecks a ref, so a malformed or unnormalized ref fails the suite instead of aforbidthat always passed, and a malformed identity query fails when the suite loads. - Identities. An identity holding a Unicode format character (category Cf, such as U+200B, U+200C, U+200D, U+202E, U+FEFF or a soft hyphen) is rejected: two identities that look alike would silently differ. A BF entity, alias or resource must reach its note or record: another brain's namespace, a
#section, a note file path, a page address or aSOURCE:IDaddress failsbf validate, and the note or record leaves the search cache like one with a foreign alias. A malformed BFresourcemakes its note invalid, like a malformed alias. - Bounds. Note frontmatter
aliasesandlinkshold at most 1,000 items, like tags and records, and a record'sfieldsat most 1,000 names. - Routine replies.
bf runrejects a disabled routine before running anything, with a stderr diagnostic and no JSON reply, as it rejects an unknown one. A--dry-runreply no longer names anactionpath, which the real run picks anew, and reportsskippedwhen the real run would skip. - Skills.
bf skillsreportsnewer, exits 1 and leaves the folder when a newerbfinstalled a different copy of a skill, such as a brain's pinned runtime sharing the skills directory;--forceinstalls this version's copy. The packaged skills search, read and check every brain with the installedbf, never through a brain's pinned runtime, which installs and runs code the brain supplies. - Heading slugs. A heading whose title spans several lines, or whose
{#id}sits inside emphasis, a code span, link text or an escape, gets a new slug, such as#title-line-one-line-two;bf validatereports links to the old one.
Upgrade: run uv tool upgrade brain-framework (or update a brain's pin), then bf skills DIR; the skills now require Brain Framework 18. Drop empty --brain "" arguments from scripts and host configurations, and match the new bf: invalid input: line where a script parsed usage errors. Run bf validate: retype the identities it names for invisible characters or unreachable declarations, point links at renamed heading slugs, and fix a sensor whose records it reports, then collect again, since collection replaces its own records. Re-copy the example git-history.py, github-history.py, local-documents.py, prompt-context.py, session-context.py or weekly-review.py if your brain uses one; remove timeout: 3600 from a github-history.py sensor, and note that git-history.py --skip with any worktree's path now skips its whole repository.
Added¶
- Review signals follow evidence that changed: a project linked from a record whose upstream
updatedis after the note's last edit, such as an issue closed or a pull request merged, needs review, and so does a note citing a record that happened or changed since. The optionalnewerfield names up to five of those items, newest first. A future event counts once it happens, and an edit always clears the flag. - Exact reads summarize their note: a section read states the note's
title,type,statusanddate, and a whole read of a project, or of a note withstale_after, carriestasks,nextand its review signals. - The home page reviews every current project, lists those needing review first, ends near the 32 KiB page budget and reports
projects_total. Its actions, changed and upcoming items carry the same review signals, so an action or concept paststale_aftershows there, and deprecated notes leave every home section. bf validatewarns, without failing, about recordlinksthat are neither identities nor URLs and about a temporary file an interrupted write left behind, and checks programs launched through a command, such as[uv, run, ..., sensors/brief.py].bf schedulewarns when its interval is at or above the shortest selectedrefresh;bf statususage windows gainsincewhen heavy use cut them.bf registerat a moved brain's new place replaces the entry whose folder no longer exists, or which reaches the same brain through another path, and reportsreplaced.- A Python whose SQLite is older than 3.35 or lacks FTS5 or JSON functions fails with a message naming the requirement and the fix, instead of a misleading cache error.
Fixed¶
- Search keeps the English word
comment, and a quoted word is always a search term.one,ones,doing,having,ours,yours,theirsandhersdrop like other function words: stemming made them match nearly every passage. - Note leads and task text keep identifiers such as
MAX_FILE_SIZE,deploy_all.sh,2*3and link refs such as_drafts/. - Reading a record, and its relation page, lists links to its
SOURCE:IDfrom other selected brains, as search did; review signals skip names that several items claim, as backlinks do. - A large read's
outlinelists only the headings inside it, so an H1-only note or a section without subsections fills its first page instead of pointing back to itself. With several brains, pages fit their items within the 32 KiB budget once refs are named by address. - A refresh loads
bf.yamlonce: abf.yamlbriefly invalid during an editor save no longer leaves the files indexed meanwhile skipped untilbf build. A killed build's.bf/index.sqlite.newis removed, and each skipped file's error is cut to 1 KiB so a few hostile files cannot push replies past their limit. - Parsing a note with many repeated headings, or a long run of
[^, takes linear time instead of stalling search, validation and section reads. - A heading anchor is read from the heading's source, and generated
-Nslugs skip explicit anchors. An indented OKF footnote definition keeps its link, which supports the section that first cites it. - A link Python cannot parse, such as
http://[your-host]/, or a relative link holding a backslash no longer makes a copied document unsearchable; link errors name the line or frontmatter key. bf validatereports each problem of a note once, names where a link problem first occurs, no longer turns links to a note's entity into false "unresolved BF target" problems, and reports a record link whose scheme case differs from its source, such asMail:m1.- A huge hex or octal YAML integer is invalid YAML instead of a crash of every search over the brain and its references. Validation messages name at most five problems, then how many more, and sensor output is checked record by record, so malformed output or frontmatter cannot build megabytes of error text.
- An unreadable top-level folder is skipped and reported while the rest of the brain answers, Unix sockets are reported as special files, and empty
brains:,fields:,sensors:,routines:orwatch:sections read as empty. - A
--brainpath withoutbf.yamlfails naming the selection before anything runs, a registered brain whose folder is absent fails with the registry's message, andbf registerkeeps a name whose folder exists but cannot be reached. - A window collection that ends before it runs, such as a backfill chunk, extends coverage without counting as a fresh collection. A
logroutine is no longer killed pastmax_bytes; its log keeps the last 256 KiB. - A program ended by a signal fails with
program was killed by SIGKILLinstead ofexited with status -9. An action folder left with only a killed write's temporary file no longer makes the routine skip for the day. - Collection checks projected records against the record bounds and validates each record once.
bf schedulepreviews copy from~/.config/bf-schedules, where its warning suggests writing, and--output DIRno longer fails when DIR holds the state directory.- A disabled program fails with
sensor NAME is disabled in bf.yaml; set enabled: true to run itinstead of suggesting its own name.bf run --hook EVENTreads standard input only when a routine lists the hook, so an unlisted hook succeeds at once in agent shells. - Diagnostics and MCP error text escape control and format characters from file names and keys, and replies escape every Unicode format character, so a shared brain can neither send terminal escape sequences nor hide text. MCP error text hides brain roots, the registry and the home directory.
- A closed or full standard output fails with one line and exit 1 instead of a traceback or exit 120; closing the terminal under
bf watchexits 130. bf watchshows bf's own diagnostic whenbf.yamlbecomes invalid or drops a selected program,notifications: successandallalert while another program keeps failing, and the details panel shows local time.bf skillsfinishes an interrupted install or update instead of reporting its own partial copy asunmanagedor as your edits.- MCP integer arguments accept integral floats such as
5.0;tags/LABEL/andbf eval --path evals/accept a trailing slash; default brain names fold accents (Équipe produitbecomesequipe-produit). - The example
git-history.pycollects repositories whose scanned checkouts are only worktrees, once each;github-history.pypages by modification time and reads merge state from the issue listing, one request per 100 items instead of one more per pull request;local-documents.pyskips Office owner files; the example hooks and weekly review name items bybf://address across brains. - The skills run helpers with an installed Python 3.14 when
python3is older (uv python find --system --no-config --no-project 3.14), never throughuv run, which adopts a.venvabove the working directory, and they review a brain's.venv/,uv.tomland.python-versionbefore running its pin. The guarded-write helper names its temporary file like bf's own writes.
Changed¶
bf mcpvalidates its brain selection at startup, then resolves it again for each call, so registry changes need no restart.- Faster: a full build creates its schema in one transaction, a search after an edit scans the brain once, problem checks use an index, record commits count files without a stat each, home computes review signals in one query, and validation parses each note once.
- Identity search no longer repeats an untyped link beside a typed one from the same origin; usage history keeps 30 days; help and errors name arguments
QUERY,REF,SENSOR,PATHandDIR. - The contract gate checks configuration schemas for narrowing and reply schemas from the reader's side;
mise run checkvalidates the changelog, and a hung test ends the run after 300 seconds. - The documentation, skills and examples describe this release: identity rules, review signals, invalid-input lines, the pinned-runtime review and the new limits. Reference pages own each contract and guides link to them.
v17.0.0 - 2026-10-02¶
A review release. The brain format (version: 7), bf.yaml and the search and read reply schemas are unchanged. The command line is stricter, so input that was silently misread now fails, and failures that took down a whole brain are now contained.
Breaking changes¶
- Routine input.
bf run ROUTINEpasses piped input only with--stdin. It used to read any open standard input and failed after 10 seconds in agent shells that hold it open.bf run --hook EVENTstill passes what Git pipes, such as the refs of a push. - Repeated options. An option that takes one value may appear once:
bf search launch --scope projects --scope concepts, a second--brain,--relor--hookexits 2 naming it. The last value used to win, so the answer silently ignored the others.--sensorand--routinestill repeat to select several programs. - Routine arguments.
bf runrejects an unknown option before--, such as--dryrun, with exit 2. It used to pass it to the routine, which then ran for real. - Read relations.
bf read PAGE --rel RELATIONis invalid input (exit 2), as a page is recognizable before any brain is read. - MCP arguments. Tool arguments are validated strictly: a
limitoftrueor"5"is an error instead of a coerced value. - Retrieval cases. A plain
expectorforbidref inbf evalnames a file of the evaluated brain. A related brain's note at the same path used to satisfy it; name that note by itsbf://NAME/...address.
Upgrade: run uv tool upgrade brain-framework (or update a brain's pin), then bf skills DIR; the skills now require Brain Framework 17. Add --stdin where a script pipes input into a direct bf run ROUTINE, and put -- before routine arguments that start with a dash. Re-copy the example git-history.py, prompt-context.py, session-context.py or weekly-review.py if your brain uses one. Then run bf validate and bf eval.
Added¶
bf statuslists each brain'sattention: the scheduled programs that failed or areoverdueorneversucceeded, as the home page does. A brain reported"healthy": falsewith"problems": []and left the reason to a scan of every source and routine.
Fixed¶
- Search keeps a function word written as an acronym.
EU AI Actsearched onlyact, andAI,ITorUSdropped from any query, because they spell French or English function words. Lowercase function words and the habitualANDandORstill drop. The exampleprompt-context.pyhook mirrors the rule. - Searching a note's title finds the note before a section that mentions it: a section's note title and parents rank below a heading.
Atlas next actionsstill finds that section. - One unreadable folder, such as a source restored with another owner, no longer fails every search, status, validation and build of the brain: it is skipped and reported, and
bf validatenames it as an unreadable folder. - Collection stops below the 100,000-entry scan limit of its source and fails like any other collection, so a growing window source can no longer make every search and read of the brain fail. A commit changing exactly as many records as the limit no longer leaves a pending transaction behind.
- An action routine's relative links and headings are checked before writing, like its metadata and relations: an action that
bf validaterejects, such as one linkingprojects/x.mdinstead of../../projects/x.md, is never written. bf validatereports every problem of a note, and links to a note it cannot parse are no longer reported as unresolved: one invalid date or undeclared relation hid the note's other problems and broke the links of other notes.- A far-future
stale_after, such as9999-12-31T23:00:00Z, no longer crashes the home and projects pages in timezones east of UTC. bf mcpstops at once on SIGTERM or Ctrl-C with exit 130, instead of waiting for another input line.- Reading a note alias named like a source, such as
jira:ATLbeside ajirasource, no longer fails on another malformed record of that source or while a writer holds the brain. - Filesystems reporting 64-bit hashed inode numbers, such as mergerfs, no longer fail every cache refresh with a traceback.
- A query starting with
bf:, such asbf: how to configure sensors, searches its words instead of failing as an invalid address. - The example
git-history.pyskips linked worktrees, which collected their repository's whole history again; records already collected stay. The example routine and session hook read a task's Markdown link as its label. - The meeting-notes recipe has the agent draft GitHub issues for review instead of creating them from calendar text that anyone who invites you can write.
Changed¶
- Packaged skills no longer carry
metadata.version, so a release changes a skill's files only when its content changes;.bf-skill.jsonstill records the installing version. - Adding
broaderortargetsto a relation no longer rebuilds the search cache: relation pages readbroaderat query time, and collection and validation checktargets. - The schedule preview suggests
--output ~/.config/bf-schedules, outside the brain, like the documentation: the generated files hold this machine's paths. - The documentation states exact reads across brains as they behave: while a brain is unavailable, a found ref returns with a
problemsentry and a missing one fails as incomplete.
v16.1.1 - 2026-09-29¶
A patch release from a review of 16.1.0: no format or reply change. Upgrade with uv tool upgrade brain-framework, then bf skills DIR to update unedited skills.
Fixed¶
- A declared
numberfield set to.nanor.infin a note's frontmatter passedbf validateand then failed every search or read reply listing the note with a traceback.bf validatenow reports the frontmatter as invalid, and retrieval skips the note with a problem like any other invalid note. - A path starting with an unknown
~user, such asbf search --brain ~typo/brain,bf init,bf register,bf skillsorbf schedule --output, fails withbf: a path's ~ or ~user home directory cannot be resolvedinstead of a traceback. - An exact read of two records that name each other as aliases no longer recurses when both files disappear between the cache check and the read.
bf skillstreats a file you added at a path a newer version starts shipping asmodifiedand keeps it, instead of overwriting it.- A routine whose action was written but whose run history could not be saved reports
wrote PATH but local run history could not be savedinstead of claiming no action was written.
v16.1.0 - 2026-09-29¶
A review release: no format or reply change is required. It fixes the published reply schemas, which rejected some valid replies, and several failure paths; the skills, examples and documentation are clearer and match the code.
Upgrade: uv tool upgrade brain-framework, then bf skills DIR to update unedited skills. Re-copy the example weekly-review.py, github-history.py, git-history.py or local-documents.py if your brain uses one, and merge the new AGENTS.md guidance as Refresh brain instructions shows. From 15.x, apply the 16.0.1 steps first: bf skills reports skill copies made before 16.0 as unmanaged and leaves them; back up any edits and rerun it with --force.
Fixed¶
- The published reply schemas (
bf schema --kind read-reply, MCPoutputSchema) accept every valid reply: an empty period page, such asbf read 7din a new brain, matched two page shapes, so MCP clients that validate structured output failed the read. Reply shapes are now alternatives (anyOf), and tests validate every reply against the published schemas too. - A record's
attributesandfieldsare returned exactly as stored: replies no longer convert instants inside them to local time or drop an attribute namedtimebesidedate. - A collection that would change more than 100,000 records fails like any other collection error, recorded in history with its backoff, instead of exiting as invalid input and stopping
bf update. - An unrecoverable cache error prints
the search cache is unavailable; run bf buildin the CLI and MCP instead of a traceback. - A read waiting for another writer to build a missing cache fails after one wait, naming the writer, instead of retrying for up to six minutes.
- A program that cannot start is reported as such even when its log cannot be written.
- YAML files other than UTF-8, such as UTF-16 with a byte-order mark, are rejected naming the file.
bf skills --checkreported a skill with a deleted file ascurrent: it is nowmodifiedand lists the file underedited;--forcerestores it.- A reply names an unavailable brain once, worded as its pages report it.
bf searchandbf readreject--offsetabove 2^53−1 as invalid input (exit 2), like the MCP tools.
Changed¶
bf update --sensorand--routinesuggest close names for an unknown program.bf initwrites the sameAGENTS.mdfor every brain (bf://NAME/...), so comparing it with a scratch brain shows only template changes. It asks agents to update notes when the user asks or the task authorizes it, and never to editmemories/.- Help text states that
watchoptions overridebf.yaml, thatstatus --checkalso fails on programs that never succeeded and which itemsexport --kind identitieslists. - Skills: helpers run from any directory as
python3 "$SKILL_DIR/scripts/NAME.py", and throughuv run --project PATH --lockedin a brain that pins its runtime. Version checks follow each skill'scompatibilityinstead of a written version.guarded-write.pyrefuses a symbolic link anywhere in the note's path; run it from inside the brain with a relative path.new-action.pyremoves what it created when its write fails.bf-maintainexplains eachbf statusfield, and duplicated rules now live in one guide each. - Examples:
weekly-review.pyshows times with their offset instead of labelling local times as UTC.github-history.pyskips a pull request updated during its run, which the next window collects.git-history.pyrequires Git 2.37 and says so.local-documents.pykeeps the text read before an Office part's element or nesting limit and marks the recordpartialinstead of failing the snapshot. The sensors README adds a Calendar agenda configuration, and example brains ignorelogs/. - Documentation: Install and update and the four-tool walkthrough move to Start here, Troubleshooting to Reference. The upgrade steps separate the version upgrade from the manual steps of a major release and explain
modifiedandunmanagedskills. The docs now say thatoverduemeans no success within twice the refresh, that a statuscacheofstaleormissingawaits recovery, and that an exact read across brains fails while one of them is unavailable. They also document the state-directory symlink error and the corrected page sizes, log limits and missed-schedule behavior.
Development¶
scripts/push-and-tag X.Y.Zpushesmain, waits for CI on that commit and tags it only after success, whatever shell runs it;tests/test_release.pycovers the release scripts, and CI validates the release notes on every push.- The weekly security workflow also installs the package on the next Python release, and scans through the gate's tasks without caches.
- Dependency updates: uv 0.12.20, zensical 0.0.66, sse-starlette 3.5.0, pyjwt 2.15.1.
v16.0.1 - 2026-09-29¶
First published 16.0 release. The v16.0.0 tag stopped at verification before publication and remains unchanged: two cache-recovery tests expected a rebuilt cache to get a new inode number, which Linux CI filesystems reuse; they now check the rebuilt cache's integrity instead.
Brain Framework 16 settles the contract so that later releases only add to it. One brain format number covers bf.yaml and evaluation suites, one word names each concept, dates and datetimes are separate, routines become general brain programs with hooks and logs, the agent skills ship with the package, and published reply schemas accept added fields while a release gate rejects anything else. Search, the graph, validation and interrupted writes are also more robust.
Breaking changes¶
- Brain format 7.
bf.yamland everyevals/*.yamldeclareversion: 7. Theschema:key ofbf.yamlis nowfields::fields:declares shared fields and relations, a sensor'sfields:maps them, a record stores them and a note sets them. - Dates and datetimes. A note states its
updatedday asdate(2026-09-29), never as the UTC instant of its local midnight; claims, exports and backlinks asserted by notes carrydatetoo, andreview_dueis a date. - OKF review deadline. Note frontmatter
review_dueandreview_afterare replaced by OKF'sstale_after, an instant with its timezone: a note is due for review once it is stale. Without it, projects fall due 14 days after their last edit, as before; replies name the deadline's origin asreview_source: stale_afterormodified. An OKF note'sresourceURI is one of its identities, like an alias. Every datetime in a reply shows the local offset, to the second (2026-09-29T09:00:00+02:00); files, run history and the cache keep UTC. - Routines. A routine is any deterministic brain program declared under
routines:.output: log(the default) keeps its stdout in its log;output: actionturns its Markdown into a dated action as before.hooks: [pre-push]letsbf run --hook pre-pushrun it, andbf run ROUTINE [ARGS]...runs one now; both pass arguments and piped input through. Action folders written by routines end in an 8-character suffix. - Logs. Sensors and routines log each run to
logs/NAME.login the brain, newest last and bounded to 1 MiB;bf initignores/logs/in Git and retrieval never reads it. Status and errors name these brain-relative logs. - Freshness. A scheduled program late by more than twice its refresh is
overdue(wasstale); status no longer repeats it as astaleboolean.stalenow only marks results served from a cache a writer is updating. Status reports that cache asbusy, and an interrupted transaction aspending_transactionwith its recovery command, instead of failing. - Search. Quoted phrases and
word*prefixes are honored; results matching more of the query rank higher; tags rank like headings; a nested section's title readsNote — Parent — Child; equal scores list the newest first. Replies addunmatched(words found nowhere) andsections(other matching sections of a note). Periods accept2026-09-21..2026-09-25as a scope and a page. The search cache rebuilds itself once. - Reads. A note above 32 KiB opens with its outline, graph context and first 4 KiB; read its sections by ref or follow
next_offset. Task text keeps its links as[label](ref)with brain-relative refs. Listed items and backlink previews show declared single-valuefields, such as a status, and backlink previews add anexcerptof at most 160 characters. Outgoing claims keep up to 20 per relation and 50 in all, so a crowded relation never hides another. - Export.
bf exportprints edges;bf export --kind identitieslists each note or record that declares names beyond its own address, with every name it answers to. Theedgespositional argument is gone. - Skills. Seven skills become three and ship inside the package:
bf-use(find, write and track work),bf-setup(onboarding, discovery and imports) andbf-maintain(integrations and operations).bf skills DIRinstalls or updates them without overwriting edited copies;--checkreports drift. Helper scripts use paths relative to their skill. - Initialization.
bf initno longer createstests/,--fullno longer createssettings/, and the generatedAGENTS.mdteaches the new search syntax,date/timeandbf run. - Limits. Continuation offsets stop at 2^53−1, the largest integer every JSON client represents exactly.
Upgrade: stop the watcher, rename schema: to fields: and set version: 7 in bf.yaml and each evals/*.yaml, replace note review_due/review_after with stale_after, add output: action to routines that write actions, add /logs/ to .gitignore, replace bf export edges with bf export, read freshness: overdue and a note's date in scripts, reinstall skills with bf skills DIR after removing bf-learn, bf-action, bf-scan and bf-import, regenerate native schedules with bf schedule, then run bf validate and bf eval.
Added¶
bf runand routinehooksfor Git and other event hooks;bf updatenames the manual programs it skipped.- Typed note claims: an OKF note's
fields:sets declared fields, such asowner: [person:email/bob@example.test], validated like a record's. bf skills DIR [--check] [--force].bf export --kind identities.- Published reply schemas accept added fields, and
tests/contract/keeps each schema of the major release: any other change fails the gate. - MCP tools publish their reply schemas as
outputSchema; errors name thesearchandreadtools. bf validatechecks that each enabled program insensors/orroutines/is an executable file, that declared relations are not written at the top level of frontmatter, and that?rel=appears only onbf://links.- Lookup errors name what exists: a missing section lists the note's sections, and a mistyped page, note, sensor or routine suggests close names.
- Status reports each source's
bytes.
Changed¶
- A link naming an undeclared relation keeps its note or record searchable as an untyped link;
bf validatenames the relation. bf validateaccepts a record's provider alias as a link target, checks a relation'stargetsagainst every identity the target's owner declares, and accepts OKFsourceswhoseresourcedescribes a population.- Record commits back up replaced files with hard links and roll back only the files they changed, so an interrupted commit recovers in about a second; commits need about half the fsyncs.
- Exact reads during a commit return within about 3 seconds, marked
stale, instead of waiting up to 2 minutes; a waiting cache rebuild is no longer starved by readers; a damaged cache is discarded and rebuilt; watch and generated schedules allow 60 seconds to stop. bf evalranks each case among the first 50 results, even below its limit.bf --helplists commands from setup to repair.
Fixed¶
- A note dated in a timezone east of UTC no longer shows the previous day.
- An unwritable state directory is named, with
XDG_STATE_HOME, instead of blaming the brain. - A completed commit whose cleanup was interrupted no longer blocks reads.
v15.0.0 - 2026-09-29¶
Brain Framework 15 reshapes replies for agents: smaller, bounded, described by published JSON Schemas and easier to continue. It ranks sections by their note, collapses duplicate records across sources, pages relationships, adds graph settings and exports, and hardens collection and cache rebuilds. The brain storage format remains version: 6; the search cache rebuilds once after the upgrade.
Breaking changes¶
- Watch preferences now live in the optional
watchmapping inbf.yaml.settings/watch.yamlis no longer read, andbf schema --kind watchandwatch.schema.jsonare removed;bf schemaincludes watch preferences. Defaults and CLI precedence are unchanged. All commands loadingbf.yamlvalidate the section, even when CLI options override it. - Exact reads above 32 KiB return their note or record text in pages (
textorrecord.text, withoffset,next_offsetandtotal_characters; the first page adds the sectionoutlineand the graph context) instead of JSONchunkstrings. Every exact read addssha256(of the whole file) andmodified. - Backlink groups always name their
relation(linksfor untyped links) and preview their 5 newest items withref,title,time,kindandsource,statusortypeonly.bf read REF --rel ROLElists a whole group. - OKF
sourcesentries now claim the built-incitesrelationship instead of an untyped link: backlinks list them undercites.linksandcitesjointagged-withas reserved schema names. - With one selected brain, result and listing entries omit
brainanduri; records omittype, whichkindalready states. - Search
sourceslists the sources of returned records and those needing attention (failed,staleornever), withsources_omittedcounting the rest; replies without items andmemoriesscopes keep the full list. - Search shows one result per URL when several sources hold it, such as a Drive file and its catalog entry; the result's
alsolists up to five other refs, asbf://addresses when several brains are selected. One source's records, such as highlights of one document, stay separate. - Pages and searches end early near 32 KiB instead of 2 MiB, counting a page's summaries such as
changed; follownext_offset. Result and listing titles are previews of at most 200 characters ending in…, and homechangedandupcomingpreviews omit excerpts. - Period pages (
today,7d, dates) and homeupcomingomit records ofpriority: lowsources;sourcesandactivitykeep their counts, marked"priority":"low", with the page listing them. - Collection rejects a record whose fields other than
textexceed 2 MiB serialized, andbf validatereports such stored files, so every record reads back; keep bulky content intext. bf initwrites a much shorterAGENTS.md(about 280 words instead of about 960); authoring rules live in thebf-learnskill.- The
bf-actionhandoff check reportscharactersinstead ofreply_characters.
Manual upgrade:
- Stop the watcher, move the keys from
settings/watch.yamlbeneathwatch:in your existingbf.yaml(indent them two spaces), remove the old file, runbf validateand restart the watcher. Remove the emptysettings/directory only if nothing else uses it. Brains without custom watch preferences need no change. - Rename any
schemafield namedlinksorcites, then runbf validate. - Update scripts that parse replies: concatenate exact-read text pages while
next_offsetis present and require an unchangedsha256; list a backlink group withbf read REF --rel ROLEand explain a link withbf search 'IDENTITY'; read OKF sources undercites; buildbf://NAME/REFfrom the reply's brain when you need an address with one brain selected; followalsowhere you expected every copy of a URL; readmemories/SOURCE/PERIODto list a low-priority source's records. Validate parsed replies withbf schema --kind search-replyandbf schema --kind read-reply. - Re-copy the upstream
bf-use,bf-learnandbf-actionskills and any copied hook (examples/hooks/session-context.py), which read the new replies. - Optionally compare your brain's
AGENTS.mdwith a scratchbf initand keep what your brain still needs.
# https://fmind.github.io/brain-framework/docs/schedule/#watch-preferences
watch:
interval: 300
notifications: off
Added¶
- Role pages:
bf read REF --rel ROLE [--offset N]and MCPread(ref, rel, offset)list every item linking to a note, record or identity through one relationship, 50 per page; an undeclared role exits 2 naming the declared ones, and abf://address with an undeclared?rel=reports a problem. broader: ROLEon a relation field: the parent's role page also lists its narrower roles' items, each keeping its ownrelation.targets: [PREFIX, …]on a relation field: collection rejects mapped values and typed record links outside them without changing evidence, andbf validatereports stored records and note links outside them.bf validatelists non-failingwarningsfor identities that differ only by letter case;bf statuslistswarningsfor a record source or authored folder above 80% of the scan limit. Neither changes the exit code.bf build --reproject SENSOR [--dry-run]re-applies a sensor's current mappings to its stored records without running it or removing records.bf export edgesprints every claim of the selected brains as JSON Lines, offline, for DuckDB or networkx.sensors.NAME.priority: normal|lowinbf.yaml: low ranks a source at half weight in search and keeps its records out of period and home lists; applied at query time withoutbf build.bf evalreports each search case'srankand the run'smrr;bf eval --baseline FILElistsregressionsandimprovementsagainst a saved reply.- Published JSON Schemas for
bf searchandbf readreplies:bf schema --kind search-reply|read-reply,docs/search-reply.schema.jsonanddocs/read-reply.schema.json. The test suite validates every reply against them. - Typed claims carry the asserting item's
time. - MCP tools gain titles, and the server sends a title and instructions with the orient, find, verify and answer loop, role pages and completeness checks.
- Opt-in
examples/hooks/prompt-context.pyfor Claude Code and Codex lists up to three matching note refs per prompt, counts records without quoting them, and stays silent after 2 seconds or on incomplete retrieval. - The
bf-learnscripts/guarded-write.pyhelper replaces a note from stdin only while it still has thesha256of the agent's read. - Add an explicit
frefresh shortcut tobf watch(uremains an alias): reload configured sources and check due work now, retaining one follow-up request during an active update while respecting pause, selectors and retry timing. - Add a reviewed GitHub history sensor and backfill walkthrough: selected-branch commits (one year of
mainby example), all-age issues and pull requests, incremental refresh and bounded pagination that preserves evidence on failure.
Changed¶
- The 100,000-entry scan limit applies per source directory under
memories/and per authored folder, and its error names the crowded directory with a remedy. bf buildand automatic rebuilds fill.bf/index.sqlite.newbeside the live cache and replace it atomically: searches and collections continue meanwhile, and an interrupted build leaves the live cache intact. Readers hold a brief cache lock while connected, so a replaced cache never attaches the new one's write-ahead log.bf updateandbf watchrecover an interrupted record transaction before refreshing the cache; reads still refuse and namebf buildorbf update.- Rewording a schema field's
descriptionorexamplesno longer rebuilds the cache; addingbroaderortargetsdoes. - Rolling back an interrupted transaction syncs the source directory once instead of once per record.
- Mapping errors at collection name the record's zero-based position.
- The skills describe the new replies, role pages, low-priority sources, rank-aware evaluations, scan warnings and graph settings.
- Synchronize the project description across the README, documentation, package metadata, CLI help and GitHub About to “🧠 Brain Framework: from information to informed actions.”
Fixed¶
- A section now ranks under its note's title as well as its heading, so "Atlas next actions" finds Atlas's own Next actions before other notes that mention Atlas; a query matching only a note's title still returns the whole note.
- The snapshot shrink guard counted the catalog left by an interrupted commit, letting a truncated listing remove most records; recovery now runs first.
- A routine retried after its run history failed to save no longer writes a second action for the same day.
- Temporary
.write-*files left by killed writes are removed by the next transaction or recovery of their source. - Reject ambiguous GitHub pagination and PR details that move outside the requested window, preserving saved evidence instead of accepting an incomplete or out-of-scope collection.
v14.0.0 - 2026-09-28¶
Brain Framework 14 is the first stable release. It settles the brain format, the CLI and MCP reply contracts and the execution boundaries so that later releases can extend them without breaking them. Collection only runs in one explicitly selected brain, stored evidence resists partial provider failures, retrieval replies share one shape, and the guides, skills and examples are tested against the release they document.
Breaking changes¶
- Formats:
bf.yaml(format 6) and evaluation suites (format 5) requireversion. YAML follows the 1.2 core schema:yes,no,onandoffare strings,017is decimal and1:30is text. - Notes: in projects, concepts and
ACTION.mdnotes, onlydeprecatedcloses a note: it ranks last and leaves home, tasks and review reminders. Aliases must be namespaced identities such asrepo:github.com/owner/name, titles are limited to 4,096 characters, and page paths (home, folder roots,tasks, periods,tags/*,memories/*) cannot be entities or aliases. Other Markdown, such as action inputs and outputs, is ordinary: only validtitle,type,status,updated,summaryanddescriptionapply, and it declares no entity, alias, tag, frontmatter link or review date. - Links and identities: body links keep their written form, so BF links must percent-encode spaces and
%. A note alias equal to a record ref is an ambiguous identity, an entity or alias whose first path segment contains:is invalid,tagged-withis reserved for tag membership, and periods accept ASCII digits only.bf://NAME/source:idalways names a record. - Records: aliases must be namespaced identities, ids must fit a BF address (7,988 characters once percent-encoded), URLs are limited to 8,192 characters without control characters, and lone surrogates are rejected.
bf validatereports stray files and hidden.jsonfiles undermemories/. - Selection and execution: a bare
--brain NAMEorBF_BRAIN=NAMEresolves through your registry first and fails when the enclosing brain or its references claim that name for another directory.update,collect,watchandscheduleact on exactly one brain (--brain,BF_BRAINor the enclosing brain) and never fall back to all registered brains; outside a brain they fail. For them, a name must be registered or be the enclosing brain's own: a referenced brain or a directory below the working directory fails withneither registered nor the enclosing brain. An enclosingbf.yamlmust be a regular file owned by you, and the user registry~/.config/bf/config.yamlmust be a regular file. Program executables must be bare command names or normalizedsensors/orroutines/paths. - Collection: a snapshot that would remove more than half of an existing catalog and more than 10 records fails without changing evidence, like an empty snapshot;
bf collect SENSOR --allow-removalaccepts one such run. Failed sensors and routines retry after 1, 2, 4… minutes, capped at theirrefresh, instead of every cycle;bf collectretries a sensor at once. A concurrentbf updateof the same brain waits up to 10 minutes before failing, and a program whose background process keeps its stdout open fails one second after it exits. - Replies:
problemsis always a list of objects witherrorand optionalbrainandfile.bf buildandbf updatereport skipped files asskippedand exit 1 when files were skipped;bf statusreports its cache ascache, and its source and routine entries usestate,last_collected,window,last_run,last_success,failed,failuresandloginstead of the removedenabled,configured,run,success,startandendkeys.bf updatereplies with one brain object whosesensorsandroutineslists are always present. Search no longer returnsmore;next_offsetalone signals continuation. All instants are canonical UTC ending inZ; absent ones are omitted, except inbf watch --jsonrows, wheresuccessandnext_dueare then empty strings. A source without dated records has nolatest.bf watch --jsonno longer emitsobserving. - Reads and searches: exact replies longer than 65,536 characters are JSON chunks from offset 0, and a non-zero offset on a smaller reply fails. The MCP
readtool has nobrainargument; use abf://NAME/...address. Both MCP tools reject unknown arguments, such as thatbrainor a misspelledscope, instead of ignoring them. Identity scopes include the identity's owning note. An unknownmemories/SOURCEscope is not found, and a segment below it other than a period,undatedor a record file is invalid. Malformed refs,bf://NAMEwithout its trailing slash and queries without any word exit 2, including a search query shaped like a malformed BF address. Retrieval needs write access to.bfand rejects a.bfthat is a symlink, not a directory or owned by someone else. - Evaluation:
bf evalvalidates every case while loading, including scopes (a0dwindow is invalid), read refs,bf://addresses and query words, and fails the whole run on an invalid suite. - Scheduling: a relative
bf schedule --outputresolves against the brain, and generated systemd units no longer cap the whole update at 45 minutes. - Removed legacy: JSON Lines record storage handling, the
active,paused,blocked,doneandarchivedstatuses, the/logs/entry in new brains'.gitignoreand the hand-written systemd example.
Upgrade from 13: stop collection and back up the brain, then upgrade. Declare version: 6 in bf.yaml and version: 5 in each evals/*.yaml, and write true or false where a YAML 1.1 yes, no, on or off meant a boolean. Replace the note statuses active, paused, blocked, done and archived with draft, stable or deprecated, namespace aliases such as repo:github.com/owner/name, percent-encode spaces and % in BF links, and make each program's executable a bare command or a normalized sensors/ or routines/ path. Pass --brain to update, collect, watch and schedule outside a brain, and regenerate native schedules with bf schedule. Update reply parsers for problems objects, the renamed bf status keys and the removed search more, and MCP read calls to use a bf://NAME/... address instead of brain. Then run bf validate and bf eval and fix what they report.
Added¶
- Sort
bf watchandbf status --watchby name, last success, returned items, state, next due time, changes, duration, output bytes, refresh interval or kind, with reverse order, first/last navigation, an item-count column and a keyboard guide. JSON watch rows exposerecords, the last successful sensor run's returned count. bf schema --kindexports offline editor schemas for brain, watch, registry and evaluation files, generated and checked from the runtime models.bf evalassembles chunked exact reads and verifies their digest before checking read cases.bf validatenames the file of every problem, flags capped lists withproblems_truncatedandunresolved_truncated, checks embedded images and accepts page addresses (home, folders, periods, tags, sources and record files) as link targets. Project notes resolve a leading/fromprojects/, as concepts already did.- Registered brains that are absent on this machine appear in search and read
problems, andbf status --checkfails on them and onbrains:references that retrieval cannot include. memories/SOURCE/undatedis a search scope, like the page of that source's undated records.- The bf-learn evidence helper reads and assembles chunked exact replies with
read REF --brain BRAIN. - Documentation for shell completion, refreshing a brain's
AGENTS.mdfrom the installed template, and every enforced limit. - The package declares
Development Status :: 5 - Production/Stable.
Changed¶
- Search matches words in one Unicode compatibility form, so
ß, ligatures, full-width letters and decomposed accents are found, while excerpts keep the source's characters. The search cache rebuilds itself. - Collection parses only the record files it replaces or removes and syncs each directory once per transaction, and exact reads of absent records reuse a ready cache.
- Every lock follows the physical brain directory, so different paths to one brain share update, watch and program locks, and a busy program names itself.
- Sensors and routines receive
BF_BRAINset to the executing brain, so nestedbfcalls read that brain. - For scheduled window sensors, a manual
bf collectafter a pause no longer moves the resume point past the uncollected gap. - The
AGENTS.mdwritten bybf initstates execution authority, one-brain selection, incomplete-result boundaries,deprecated-only closing, chunked reads and multi-brainurireads. New brains' starter evaluation readsbf://NAME/concepts/welcome.md, and newbf.yamlfiles omit redundant defaults. - The watch dashboard keeps the selected row, program states and failure details visible from 80 columns, shows the sort field and direction in the panel title, applies batched keys in order and redraws only on change or once a second.
- Documentation is organized around first use, everyday tasks, collection and reference. Guides install with
uv tool install --python 3.14 brain-framework, copy examples from the release tag matchingbf --version, and name action foldersYYYY-MM-DD_topic-SUFFIX;tests/test_guides.pyruns the getting-started guide and checks every reply it shows. - Skills describe the 14 contracts, use
## Decision {#decision}in project and action templates, and are tested for the commands, options, anchors and Python 3.11 standard library they rely on. - Example sensors stay within the record limits, map provider fields explicitly and print content-free reasons for their failures. The Calendar sensor keeps cancelled events as
Cancelled: SUMMARYat their original time, the Git history sensor reads branches, tags, remotes andHEADand skips unreadable folders, and the team example is abfandgitwalkthrough. - Ordinary Markdown whose foreign frontmatter is not valid YAML stays searchable without it, a block that never closes is searched as text, and Emacs
.#NAMElock files beside authored files are ignored, so none of them failsbf build,bf updateorbf validate. A routine that already wrote today's action skips its rerun while that folder holds any file, even an editor lock. - Collection replaces, or a snapshot removes, a stored record file that holds its own id but breaks the current record rules, such as a display-name alias or an over-long title; misnamed files still fail it.
- Diagnostics name what to fix: duplicate YAML keys give their position, unknown watch settings and undeclared field mappings name their key, search errors name
QUERYor--scope,bf registernames a missing directory orbf.yaml, unavailable or unloadable brains are named once by their registered orbrains:name, andbf initasks for--namewhen the directory name cannot form one. bf schedulewithout--outputwarns that its install commands name files it did not write. When an update fails only because the search cache skipped files,bf watchsays so and sends no collection-failure alert. JSON watch rows are documented key by key.- The bf-action helper accepts a symlinked brain root, the bookmark inventory helper distinguishes a reached limit from an unsupported export, and example sensors name the repository, folder or limit behind a failure; the Calendar sensor keeps very large events within the 1,000-link record bound. Guides write GitHub identities in lowercase and install skills and the watch demo from the release tag.
- Development uses
uv run --locked, hermetic UTC tests under pytest 9 strict mode, a 95% branch-coverage floor, generated third-party notices (mise run generate:notices) and a dashboard screenshot rendered from the fictional demo (mise run generate:screenshot), each checked by the gate. CI runs shared checks once and tests on all four platforms; the weekly security workflow also installs the package with the newest allowed dependencies, and the package check completes an MCP stdio handshake with the installed package.
Fixed¶
- Body links to identities or records with accents, spaces or
%now match their frontmatter form in backlinks, reads, scopes and validation. - Removing or retyping a schema field no longer hides the stored records that carry it.
- A note whose H1 is followed by a
---rule, or that starts with a byte order mark, keeps its frontmatter; link validation compares exact file names on case-insensitive disks; lead and anchor parsing is linear on adversarial notes. - Period and source pages report each problem once; previews order ties like their continuations; deep search offsets no longer compute skipped excerpts; reading a typed link to an unowned identity works.
bf evalnames the suite and case of an invalid case before any retrieval; JSON replies are UTF-8 whatever the locale; a non-UTF-8 note is reported as such.- Collection survives files that vanish during a scan, names linked intermediate folders and the directory that exceeds the depth limit, and ignores empty or relative
XDG_*values. - A successful sensor whose background helper inherits stderr no longer times out; clock corrections no longer delay scheduled programs; malformed usage events no longer interrupt status.
- The watch dashboard no longer hides the selected row when programs outnumber the screen or truncates states and counts on 80–128 column terminals.
- The example hook, routine and sensors run on Python 3.11 again; example Calendar and Drive sensors reject malformed continuation tokens; the local documents sensor names unreadable, damaged or encrypted files.
- A file or folder name that is not valid UTF-8, such as a Latin-1 name from an old archive, or that holds a backslash, is reported as
file name is not valid UTF-8 or contains a backslash; rename itinstead of failing search, read, status, build and validate for the whole brain. - Documentation navigation and wide tables are keyboard accessible, and release notes reject empty or duplicate sections.
- Remove a breaking-change bullet copied by mistake into historical release sections.
Security¶
- Brain names resolve through the owner's registry before the working directory, an enclosing
bf.yamlis trusted only when you own it, and registered brains are selected for retrieval only, so an untrusted checkout cannot run its programs under your name. - Program environments also drop
SHELLOPTS,BASHOPTSandPS4. - The private state root is created with mode 0700; the search cache is opened through one no-follow descriptor, created with mode 0600 and read with SQLite's defensive settings.
- The example session-context hook never prints collected record refs, and a non-interactive
bf status --watchno longer suggests the program-executingbf watch --json. - A search cache that bf did not create in place, such as one copied, cloned or extracted with a brain, or one holding triggers or views, is rebuilt from the brain's files, so rows no file supports never reach retrieval. The cache is bound to its file's inode number, which a remount keeps.
- CLI JSON replies, MCP tool text and
bf watch --jsonrows write DEL and C1 control characters from collected text as JSON escapes, so a terminal cannot act on them; the decoded values are unchanged. - Collection errors, run history and
bf statusno longer quote an undeclared link relation from sensor output.
v13.0.2 - 2026-09-27¶
First published 13.0.x release. The v13.0.0 and v13.0.1 tags stopped at verification before publication and remain unchanged. CI and scheduled security checks now pin mise 2026.9.15. Terminal-restoration checks exercise line input before comparing all settings, accounting for macOS kernel state while retaining cancellation and restoration assertions.
Brain Framework 13 adds continuous collection, independent record files, complete retrieval and practical workflows from evidence to decisions. Before upgrading from 12, follow the manual steps below on a backed-up copy with collection stopped.
Changed¶
-
Use the same product description in package metadata, CLI help, the README and documentation: 🧠 AI Brain Factory: from information to informed action. Not for 🐙 mindflayers or 🧟 zombies.
-
Breaking storage change:
bf.yamluses format 6. Each source record lives atmemories/SOURCE/SHA256_ID.json, replacing monthly JSONL catalogs. Record IDs andsource:idrefs stay stable; source pages replace thepartitionsinventory with paginated records. Retrieval evaluation files remain format 5. - Breaking execution change: remove machine collection permissions and sensor content-trust settings. Registration stores names and paths only; explicit collection/update/watch commands run enabled programs in selected roots, never referenced brains. Remove obsolete registry
collectfields, sensortrustfields and--collectoptions. Retrieved content remains untrusted evidence. - Breaking note contract: projects, concepts and canonical action
ACTION.mdnotes require OKF structure, a nonemptytype, anddraft/stable/deprecatedlifecycle statuses. Work progress belongs in the body and checkboxes; attachments may remain ordinary Markdown. Routine output is validated before an action is created. - Breaking reply contract: remove
collectfrom init, registration and status replies,trustfrom source metadata, andexternalfrom retrieval and evidence-helper replies. Pages include record excerpts consistently; hooks and routines reference collected records without copying their text into authored context. - Review reminders use local file modification time, optional
review_afterdays or areview_duedate. Replies explain deadlines and newer evidence without claiming a review occurred. File copies/checkouts can reset modification times; explicit deadlines remain portable. - Routine actions use unique session suffixes, with daily suppression local to each collecting clone. Shared brains can merge independent records and actions independently; conflicting evidence still requires review.
- Rewrite guides around a runnable decision example, first sensors, schema mappings, team setup and expected results. Keep the README concise and expand advanced reference pages, privacy boundaries and recovery instructions.
- Refresh compatible Python dependencies and keep task output concise while retaining diagnostics, security findings, test counts and coverage totals.
Added¶
bf watchfollows collection in a full-screen terminal dashboard with keyboard navigation, pause/cancellation and last-run changes.bf status --watchobserves without execution;watch --jsonstreams snapshots. A second interactive watcher observes the active collector.- Brain-owned
settings/watch.yamlcontrols check/display periods and generic desktop failure/recovery alerts, with optional success notifications and cooldowns. bf schedulegenerates inspectable systemd, launchd or cron definitions and installation/removal commands without activating them. Repeatable--sensorand--routineoptions select programs for update, watch and schedule while retaining enabled/refresh rules.- Window sensors can use a separate
reconcilecadence to revisit older evidence. Collection/status replies report requested windows, reconciliation, elapsed seconds, output bytes and record change counts. bf read taskslists open checkboxes with source sections, line locations, complete counts and pagination. Weekly reviews summarize tasks without duplicating the original checkboxes.bf://NAME/tasksis reserved for this computed page.- Browse tags, follow brain-qualified tag pages and search explicit tag membership with
--scope bf://NAME/tags/LABEL. Tags retain their originating notes and use bounded, validated labels. bf-setup,bf-scanandbf-importguide onboarding, explicitly scoped discovery and selected imports. New brains include technical-test and retrieval-evaluation folders with immediately runnable starter cases.- Action helpers create independent sessions and check Context/Resume budgets before handoff. Learning guides cover reviews, evidence retention, sharing and conflict resolution.
- Runnable fictional context-hub, watch and two-contributor examples demonstrate integrations and collaboration. A highlights sensor imports selected passages with URLs, locators and annotations kept separate from source text.
- Deterministic retrieval evaluations under
evals/join the full gate without models or providers. Package checks exercise wheel and source archives outside the checkout; the manual benchmark validates every measured result.
Fixed¶
- Search/listing continuations expose remaining results. Oversized exact replies return lossless JSON chunks with SHA-256 verification; outgoing graph previews mark omitted claims. Empty searches retain failed/never-collected source coverage.
- Symlinks and special files are skipped and reported without following their targets or hiding other evidence. Incomplete exact reads fail visibly; pending recovery journals still block retrieval until repaired.
- Invalid YAML identifies the file, line and column without quoting private content. Persisted-record diagnostics redact provider-controlled keys. Status reports a broken brain while retaining reports for other selected roots.
- Reject unresolved Markdown merge markers and foreign-namespace note aliases during validation/indexing. Preserve source links on every canonical note type and resolve typed links to tag pages correctly.
- Preserve existing evidence-capture destinations, including dangling symlinks. Session hooks constrain metadata to its owning brain; weekly reviews follow all project continuations and reject incomplete retrieval.
- Keep Git history collection within selected directories and half-open time windows, including in-window commits with out-of-order dates.
- Keep starter absent-evidence evaluations stable as notes grow. A malformed optional registry no longer prevents operations on an explicitly selected brain path.
- Retry failed scheduled programs on the next cycle even when an earlier success is still within its refresh interval. The watch display shows these retries as immediately due.
- Remove empty code-line links from the documentation's keyboard navigation and accessibility tree.
Manual upgrade from 12¶
- Stop all writers. With version 12, run
bf buildandbf validate, then back up the whole brain, including ignored memories and attachments. Git alone is not a full backup. Work on a separate copy with version 13 installed in a separate environment. - Convert each nonblank line of
memories/SOURCE/*.jsonlintomemories/SOURCE/SHA256_ID.json, using the lowercase SHA-256 of the UTF-8 record ID. Preserve every field and reject duplicate IDs, duplicate JSON keys, symlinks and unexpected files. Write to a fresh directory, verify counts, then replace only the copy'smemories/; never install partial output. Brains without collected records skip this step. - Set
version: 6in the copiedbf.yaml; retrieval suites stay at format 5. Remove sensortrustfields. Explicit collection/update/watch commands now run enabled programs in selected roots; review their configured argv before execution. - Give projects, concepts and canonical action notes a nonempty
typeanddraft,stableordeprecatedstatus. Move work states into the body/task list; preserve OKF sources and verification metadata. Replace aliases claiming another brain's namespace with explicit links. - Back up the user registry, then remove registration
collectfields and obsolete--collecthost flags. Update installed skills and restart hosts. Reply consumers must follownext_offset, verify/reassemble exact-read chunks and stop expecting removedexternal,trust,collector sourcepartitionsfields. Routine action paths now include a UUID suffix. - On the copy, run
bf build,bf validate,bf evaland technical tests. Compare record counts, search a known decision and read its reason and supporting record. Resolveproblems/staleand check source freshness separately before switching collectors/hosts and resuming the authorized schedule. If checks fail, retain the original version-12 runtime and backup together; do not open format-6 data with version 12.
v13.0.1 - 2026-09-27¶
Unpublished tag. The macOS terminal tests compared a transient kernel flag before processing the next input. See v13.0.2 for the full release notes and portable terminal checks.
v13.0.0 - 2026-09-27¶
Unpublished tag. See v13.0.2 for the full release notes and corrected CI toolchain.
v12.0.2 - 2026-09-25¶
First published 12.0.x maintenance release. The v12.0.1 tag stopped at the CI gate before publication and remains unchanged.
A maintenance release for reliable absence checks, documentation and release verification. Brain configuration and retrieval suites remain at version 5; no manual upgrade is needed.
Fixed¶
- Schema checks use their own scratch directory, so a concurrent clean documentation build cannot delete their intermediate files.
- Collection bounds saved coverage by its successful run and the current observation time. A future window left in run history no longer keeps successful scheduled collection permanently stale.
- A missing read no longer proves absence when a directly referenced brain is unavailable or identity lookup skipped invalid evidence. Retrieval evaluations expecting an empty answer fail visibly until the incomplete scope is repaired.
- Future-dated notes appear in the home page's upcoming items without displacing recent changes.
- PDF converter process tests allow interpreter startup on busy machines while still asserting output limits, timeouts and process cleanup.
Changed¶
- CI and release publication share the four-platform verification workflow. PyPI and GitHub receive the exact distributions that passed isolated installation tests, with hash comparisons before and after publication.
- Wheel and source-distribution checks install locked runtime dependencies outside the checkout and exercise initialization, validation, search, exact reads, status and retrieval evaluation.
- Development tasks and hooks use native tools with separate import sorting and formatting, a configured coverage floor, strict rendered documentation links and disposable schema generation.
- Refresh the README, documentation overview and branding; clarify which sensor integrations ship as reviewed examples and how to create others.
v12.0.0 - 2026-09-25¶
Brain Framework 12 ranks notes and records in one search query and answers several times faster; BF links carry only a relationship. On a personal brain of 52,000 records, full cache builds take 13 s instead of 69 s, searches and reads 0.3–0.4 s instead of up to 1.8 s, and the cache shrinks from 357 MB to 239 MB. The bf.yaml and retrieval suite formats stay at version 5, but notes that use removed link attributes or frontmatter fields need the manual upgrade below. The search cache rebuilds automatically.
Changed¶
- Breaking: search ranks every item containing any of the words in one BM25 query. The former all-words pass let long records that happened to contain every word fill the results before a note matching most of them; BM25 already ranks fuller matches higher.
- Only projects, concepts and each action's
ACTION.mdreceive the note ranking boost.concepts/index.md,concepts/log.mdand an action'sinputs/andoutputs/rank like evidence. - A query shaped like an identity (
re:invent,python:3.14) that no item is, names or links to ranks its words instead of returning a silent empty answer; the reply carries"identity": "unknown". - Record field values are searchable words without their JSON keys, so a word such as
authororkindno longer matches every record with that field. - Breaking: a BF link accepts only
?rel=ROLE. Thesubject,evidenceandasserted-byquery keys and typed link attributes are removed; a link's subject is its note'sentity, otherwise its file, or the collected record. Claims inrelationsandclaimsaresubject,relation,targetandorigin: theevidence,asserted_byandattributesmembers are gone. - Breaking: note frontmatter
fieldsno longer declares relationships; it is ordinary frontmatter data.
Fixed¶
- Searches no longer compute an excerpt for every matching passage before ranking: only returned passages get one. A four-word query over 50,000 records took 1.9 s in excerpts alone.
bf.yamlis parsed once per content within a command, with libyaml when available, instead of several times per search and once per indexed file during a rebuild.- The relationship cache no longer copies an eight-column key into each of its indexes.
- Backlinks, identity searches and project review signals look up links and relationships through indexes instead of scanning every link of the brain for each relationship group.
Upgrade¶
- Find removed link attributes:
grep -rnoE 'bf://[^) ]*\?[^) ]*' projects concepts actions | grep -vE '\?rel=[a-z0-9-]+(#[^) ]*)?$'. Keep?rel=ROLE; move a relationship of another entity into that entity's note, and keep supporting references as ordinary links in the same section. - Find frontmatter relationships:
grep -rln '^fields:' projects concepts actions. Replace each identity value with a[label](bf://NAME/path?rel=FIELD)link in the note body. - Consumers of
relations[].evidence,asserted_byorattributesreadrelations[].origininstead. - Run
bf validate: remaining removed attributes are reported as invalid BF links.
v11.1.1 - 2026-09-25¶
First published 11.1 release. The v11.1.0 candidate stopped at the release test gate before publication; its tag remains unchanged.
Brain Framework 11.1 adds optional decision workflows to the agent skills and hardens collection, retrieval and validation after a full review. The brain format is unchanged: bf.yaml and retrieval suites stay at version 5.
Added¶
- Decision workflows in the
bf-actionandbf-learnskills, loaded on demand: a small working context in each action (## Context {#context}of at most 300 words, six refs and 4 KiB, and## Resume {#resume}), decisions with alternatives and expected outcomes, conditional intentions, explicit unknowns, belief revision with a declaredsupersedesrole, dependency review bounded to two hops and ten dependents, procedures learned from outcomes and reviewed transfer to another brain. skills/bf-learn/scripts/evidence.py, a standard-library helper for Python 3.11 or later:captureretains one exactbf readwith its digest and limitations, andcomparereturns a compactchanged,unchangedorunknownverdict for a new read. It reads stdin only and never opens a brain, runs a provider or uses a model.- An agent workflows page covers the skills, the everyday loop, resuming actions, decision workflows and evidence captures.
- The example brain demonstrates a decision review: a fictional policy, a superseded decision, an intention, an unknown, a draft procedure, a prepared transfer and retrieval cases for each.
Changed¶
- Search excerpts are one line and start below a section's heading, which the result title already names. The search cache rebuilds automatically.
- Exact record reads and search coverage report the same freshness as
bf statusand source pages: a trusted scheduled sensor that never succeeded isnever. An unreadable registry grants no trust and leaves freshnessunknown. - An invalid
--scope,--sinceor--untilexits 2 as invalid input, like other command-line errors. A closed terminal (SIGHUP) cancels like SIGTERM and kills running providers;nohupkeeps it ignored. bf status --checkfails only for scheduled sensors this machine runs, as documented; a failed manual collection is still reported with its log.- Registered brains win over a same-named directory below the working directory for
--brain NAME.
Fixed¶
- The brain writer lock follows the brain directory's device and inode, so bind mounts and differently spelled paths of one brain no longer commit concurrently. Writers must share one private state directory.
- A state directory below a linked ancestor, such as
/homelinked to/var/home, no longer breaks every command; the state root itself still may not be a link. - A registry entry with a relative path is rejected instead of granting collection trust to whatever that path means in the working directory.
- Relative
PATHentries no longer let a bare command resolve inside the brain, and everyPYTHON*variable plus Java, Lua andGCONV_PATHstartup variables are removed before a sensor or routine starts. Brain executables may exceed 1 MiB. - Invalid sensor output is reported by record position and field name only: keys the provider printed no longer reach errors, logs or run history.
- An empty snapshot no longer erases a non-empty catalog; the run fails and keeps the records. Delete
memories/SOURCE/to clear a source deliberately. - A backfill whose
--untillies in the future no longer blocks later scheduled successes: coverage never extends past the run. - A routine run skipped because today's action exists no longer loses its window; the next written action covers it.
- A stored revision claiming a modification after it was first observed, such as a file with a future mtime, no longer freezes a record against newer collections.
- A note dated
0001-01-01or9999-12-31is invalid instead of crashing searches and pages; a damaged cache reports "run bf build" instead of a traceback. readkeeps answering from the other brains when one selected brain has an invalidbf.yaml, and reports it underproblems.- An alias claimed by several notes no longer merges their backlinks in scoped searches and identity pages.
- Identity searches include links to a note's sections, like scoped searches and backlinks.
- Period pages order
changeditems by modification time across brains. memories/SOURCE/PERIODfor an unknown source is a missing page instead of an empty answer.- Reading an identity or an absent source no longer waits for a running writer.
- A record id too long for a BF address still reads, with its backlinks reported as unavailable.
- Headings without word characters get an addressable
sectionslug; explicit anchors cannot end in.md; a link to a non-Markdown file whose name contains#validates. - The session hook and the weekly review show local dates, and the weekly review writes one paragraph per line and fences record ids so that none can become a link.
- The exit-code test accepts colored usage errors, as CI terminals print them.
v11.0.0 - 2026-09-25¶
Brain Framework 11 turns listings into pages, gives actions a resumable page and schedules deterministic routines next to sensors. Search takes words and one scope; everything else is a page that read resolves. The brain format changes: bf.yaml and retrieval suites move to version 5.
Changed¶
bf readwithout a ref returns the home page: active and blocked projects, the latest actions, notes changed in 7 days, record activity per source in 24 hours, items in the coming 7 days, and scheduled sensors or routines that needattention. Projects are marked forreviewwhen their note is older than 14 days or items dated after it link to them (new_links), and show opentaskswith thenextone.readresolves pages: folders (projects,concepts,actionsand subfolders), periods (today,yesterday,YYYY-MM-DD,YYYY-MM,12h,7d,2w) with items modified in the period and each source's share,memories,memories/SOURCEwith its partitions, andmemories/SOURCE/PERIOD,snapshotorundated. Pages combine the selected brains, stay bounded (50 period or source items, 200 notes per folder, 20 per section) and report totals;bf://NAME/andbf://NAME/PAGEselect one brain.- Whole note and record reads include
backlinksacross the selected brains, grouped by explicit relationship with claim explanations, andclaimswhose explicit subject is the item. An identity without an owning note reads as a page of what links to it.bf read actions/FOLDERreturns ACTION.md with the action's files and the projects it links to. - Breaking:
bf search QUERY [--scope SCOPE] [--limit N]requires words or an identity. A scope is a folder or file, a period or an identity.--since,--until,--source,--type,--status,--recent,--changed-since,--current,--relation,--targetand--subjectare removed. MCPsearchtakesquery,scopeandlimit; MCPreadaccepts an empty ref for the home page. - Breaking:
bf.yamlversion 5 declaresroutines:, deterministic programs thatbf updateruns after the sensors with the same trust, process boundary, timeout, output bound and private log. A routine's Markdown is validated and written asactions/YYYY-MM-DD_NAME/ACTION.md; an existing action is never replaced, empty output writes nothing, and a failure writes nothing and keeps it due. Routine names are action slugs distinct from sensor names.bf statusreports routines, and--checkfails on stale or failed ones. - Breaking: retrieval suites use version 5. A case is a search (
query, optionalscopeandlimit) or a read (read: a page, note, record or identity), checked withexpect,forbid,textandempty; a read that finds nothing is empty. - Sensors declare
trust:ownerfor text the brain's owner writes,external(the default) for mail, chat, invitations, issues, feeds and other third-party text. Pages show external records by title and ref without excerpts; searches, exact reads and backlinks label themexternal; source coverage reports each source's trust, and undeclared historical sources are external. bf statusno longer listsreview; project review moved to pages. Process errors name the program rather than a collector, since sensors and routines share the runner. The search cache rebuilds automatically.
Added¶
- The
bf-actionskill starts, resumes and closes one action, a single session of work, when the user asks for it; the action template moves there frombf-learn. examples/routines/weekly-review.pyrenders a weekly review action frombf readpages, with a fake-bftest and a README contract. It names external items by ref only.examples/hooks/session-context.pyprints a short context for the current repository at agent session start (project, review signal, next task, linked evidence), and nothing when unavailable.
Fixed¶
- A manual backfill that ends before a sensor's recorded coverage no longer replaces that coverage, moves its resume point or marks the sensor fresh; a contiguous backfill extends coverage backwards without counting as a fresh success.
Manual upgrade from 10¶
- Pause scheduled writers. Install the same Brain Framework 11 build for every CLI, MCP host, project environment and scheduled writer, and restart long-running MCP readers.
- Change
bf.yamltoversion: 5. Every sensor is nowexternalby default: addtrust: ownerto the sensors whose text you write yourself, such as local Git history or your own documents. - Change every suite under
evals/toversion: 5. Rewrite cases that used removed fields: a time window or filter becomes areadof a page (7d,2026-09,projects,memories/SOURCE) or a searchscope; arelation,targetorsubjectcase becomesread: IDENTITYwithexpect, andtextnaming the role when it matters. - Replace scripts, routines, skills and agent instructions that call removed search options: pages for listings and timelines,
bf read IDENTITYfor backlinks and claims,--scopefor bounded searches. Update theAGENTS.mdthat earlierbf initgenerated, and reinstallbf-use,bf-learn,bf-maintainand the newbf-action. - Optionally move scheduled review scripts into
routines/and declare them underroutines:. Review them like sensors before a trusted machine runs them. - Run
bf build,bf validateandbf eval; compare the home,projectsand period pages with your previous listings, then resume the scheduled writer.
No migration tooling or legacy command surface is included. Runtime dependencies are unchanged.
v10.0.0 - 2026-09-25¶
Changed¶
- Declare directly related brains in
bf.yamlwith stable names and relative, absolute or home-relative paths. Search, read, MCP and evaluations include direct references without recursive discovery or required global configuration. Missing references report incomplete scope; conflicting names are excluded. bf initdefaults to no global registration or collection trust; explicit--collectopts in. Maintenance commands do not expand references, and references never authorize sensors. Retrieval suites accept qualified BF addresses to distinguish same-named files across brains.- Add portable
bf://brain/path#sectionaddresses, explicit noteentityidentities and typed notefields. BF link queries encode declared relationships and attributes, with explicit subject/evidence/attribution and an immutable origin in the derived SQLite projection. - Add selected-brain alias federation, incoming
targetand outgoingsubjectfilters, and relationship explanations through CLI, MCP and retrieval suites. Ambiguous aliases do not merge, external URL queries stay opaque, and foreign links never broaden brain selection. -
Headings support stable
{#anchor}identifiers. Validation checks local BF addresses and reports foreign unresolved targets. New brains include a small relationship vocabulary and agent instructions for links. -
Brain format 4 restores explicit
schemafields inbf.yaml: descriptions, strict types, cardinality, validated examples and typed relationships. Sensors map their record output with JSON Pointers or constants; normalized values are stored in recordfieldsand included in offline search. - Typed relationships form a disposable, evidence-backed SQLite graph. CLI, MCP search and retrieval cases accept
relationandtargettogether, with exact identities and explicit owner aliases. Schema changes invalidate the cache; record replacement and snapshot deletion remove obsolete edges. bf evaldiscovers YAML suites recursively underevals/;--pathselects a suite or directory. Technical tests remain intests/.bf init --fullcreates both folders.- Git and Calendar example sensors preserve author/repository and organizer/attendee roles for explicit mapping.
Manual upgrade from 9¶
- Preserve the brain files, configuration, machine state and previous runtime; pause all collection writers and finish or recover pending transactions.
- Install the same Brain Framework 10 build for every CLI, MCP host, project environment and scheduled writer. Restart long-running readers after the switch.
- Change
bf.yamltoversion: 4. Declare shared fields underschemaand each sensor'sfieldsmapping. Keep provider transformations in sensors; do not infer missing relationships from names or flattened links. - Create
evals/, movequeries.yamltoevals/retrieval.yaml, change suiteversionto 4, and update paths in tasks, docs and skills. Multiple named suites may share the directory. - Existing records without normalized fields remain readable. Preserve originals before explicitly backfilling fields from retained structured evidence; unavailable historical roles remain unknown. Mapping changes alone do not rewrite history or contact providers.
- Add directly related brains under
brains: {team: {path: ../team}}inbf.yaml; ensure target names match. Readers now include these direct references, so review the intended audience. Use paths or local names for discovery. Existing optional registrations remain usable; newly initialized brains need explicit--collectbefore collection. - Keep the brain
namestable across clones; use it as the BF URI authority. Declare roles before adding BF link queries. Give entity notes explicitentityidentities and reviewed aliases; do not reinterpret external URL queries or fabricate historical relationships. Refresh separately installed skills and brain agent instructions. - Run
bf build,bf validate, technical tests andbf eval; check role-specific queries and exact reads, then resume the scheduled writer. Keep originals until recovery is verified. Rollback requires the prior runtime and original configuration and records, not only a cache rebuild.
No migration tooling or legacy command surface is included. Runtime dependencies are unchanged.
v9.2.0 - 2026-09-24¶
Brain Framework 9.2 starts new brains smaller, checks action folders and repairs the PyPI project page. The brain format is unchanged: existing version 3 brains need no conversion.
Added¶
bf init --fullalso creates the optional versioned folders:memories/,assets/,sensors/,routines/,settings/,skills/andtests/.bf validatereports action folders that are not namedYYYY-MM-DD_slugor lackACTION.md. Rename such folders withgit mv; validation then reports any links to update.- Document the optional brain folders: versioned
assets/for media that notes link to, and the unversionedinputs/,originals/andlogs/that new brains already ignore.
Changed¶
bf initcreates onlyprojects/,concepts/andactions/; other folders appear when first needed.bf registerkeeps the registry's leading comment lines when it rewrites the file.- Search, MCP and retrieval cases resolve relative times in one place. An invalid search time exits 2 as invalid input, and an invalid retrieval case names the case.
bf statusbuilds its report in the health service; the CLI stays a thin adapter.- PyPI publication accepts deployments only from
v*tags.
Fixed¶
- README links are absolute, so the PyPI project page reaches the documentation, skills and examples; a test keeps every link resolvable offline.
bf evalnames a missingqueries.yamlinstead of reporting an inaccessible file.- Claude Code discovers the repository's
bf-contributeskill through.claude/skills.
v9.1.0 - 2026-09-24¶
Brain Framework 9.1 prepares team deployments. The brain format is unchanged: existing version 3 brains need no conversion.
Added¶
bf init --no-collectregisters a shared brain for search without collection trust, andinitaccepts a fresh clone of an empty repository.- A team brains guide: distinctive names, joining, CI collection with preserved run state, allowlisted
memories/publication, required review of sensor code, and data retention. - A documented compatibility policy: the brain,
bf.yamlandqueries.yamlformats change only in a major release, with manual upgrade steps.
Fixed¶
bf initanchors.gitignorepatterns to the brain root, soactions/*/inputs/stay versioned and a teammate's clone validates like the author's copy. Existing brains that copied the old patterns should prefixinputs/,logs/,memories/,originals/and.bf/with/.bf initnames a brain after its directory instead ofknowledge, avoiding registry name collisions between personal and team brains, and explains how to resolve a taken name.- Unsupported platforms fail with a clear message instead of an import traceback.
Changed¶
- Call executable collectors sensors in command help, documentation and the
bf-maintainskill; record refs,--source, healthsourcesand OKFsourceskeep their provenance names.search --sourcenow has help text.
v9.0.1 - 2026-09-24¶
First published Brain Framework release. The v9.0.0 candidate stopped at the macOS ARM64 concurrent-registration check before publication; its tag remains unchanged. This release includes the complete identity and format transition described below.
Fixed¶
- Recover when a competing process creates the shared lock during its initial open, while retaining the same confined parent and no-follow checks. A missing or unsafe lock still fails explicitly.
- Cover initial lock creation races, persistent missing locks and unsafe contenders without relaxing writer serialization.
Breaking changes¶
- Rename FKF to Brain Framework: install
brain-framework, importbf, and runbf. The repository and documentation move tofmind/brain-framework. - Use format 3 for
bf.yamlandqueries.yaml, withsensors:,{{brain}},--brain,BF_BRAIN, and abrains:registry under~/.config/bf/. Private runtime state lives under~/.local/state/bf/. - Organize authored knowledge in
projects/,concepts/, andactions/withACTION.md; collected records inmemories/; collection code insensors/; maintenance inroutines/andsettings/; disposable search in.bf/. - Rename workflows to
bf-use,bf-learn,bf-maintain, andbf-contribute. CLI and MCP results identify their brain; collection reports identify sensors while record provenance retainssource:idand OKFsources. - Keep one current format without legacy aliases. Preserve original evidence and per-machine collection trust during any one-time transition, and rebuild caches from the migrated files.
Preserved¶
- Offline search and exact reads, two read-only MCP tools, plain-file evidence, bounded trusted collection, atomic recovery and external scheduling.
- Stable record IDs, provider provenance, explicit concept types, and searchable Markdown in action inputs and outputs.
v9.0.0 - 2026-09-24¶
Unpublished transition candidate. Publication stopped at the macOS ARM64 concurrent-registration gate; the tag remains unchanged. The corrected transition is released in v9.0.1.
v8.2.2 - 2026-09-24¶
Fixed¶
- Refuse collection into a source with duplicate stored IDs before changing evidence, including snapshot replacement.
- Serialize concurrent base registrations and write the registry durably with owner-only permissions.
- Preserve
#and percent escapes in note filenames and local links; require exact record IDs in retrieval cases.
Changed¶
- Explain the value of shared, file-based knowledge through concrete questions and the search, read, work and update loop.
- Add runnable team-pilot retrieval cases, routine upgrade instructions and host connection checks.
- Align documentation and skills on base selection, skill discovery, collection trust, recovery and native scheduling.
v8.2.1 - 2026-09-23¶
First published 8.2 release. The v8.2.0 candidate stopped at the Intel macOS test gate before publication; its tag remains unchanged.
FKF 8.2 makes incomplete results visible, preserves evidence through interrupted writes, and helps distinguish recently edited knowledge from historical records. Existing version 2 bases need no conversion; disposable search caches rebuild automatically.
Added¶
search --changed-sinceand--currentin the CLI, MCP and retrieval cases, with active, disabled and historical source coverage, freshness and change counts.- Reserved record attributes
updated,observedandpartialdistinguish upstream revision, collection time and incomplete content from event time. - Scoped local document extraction and optional Calendar agenda snapshots in the standalone collector examples.
Fixed¶
- Select test timezones before Python starts, preserving all DST and shared-cache checks on builds without
time.tzset(), including Intel macOS. - Recover interrupted multi-partition commits from durable originals through explicit
build, collection or backup. Serialize source runs and state updates, preserve directory entries before journal writes, and bound partitions before writing. - Preserve newer upstream revisions during backfills, repair duplicates and corrupt caches, and retry concurrent cache replacement.
- Report skipped files and unavailable bases in search; reject incomplete retrieval-case answers. Fail stale-cache health checks and skipped-file updates, reject malformed partition paths, confine link validation, and distinguish unreadable record sources from missing records.
- Correct recent and identity ordering, per-item passage selection, local-date and DST handling, and malformed-note isolation. Expose identity ambiguity and OKF provenance links.
- Validate Drive snapshot response identity before accepting empty catalogs, bound provider output while subprocesses run, and cancel collector descendants on SIGTERM.
Changed¶
- Rewrite onboarding around a runnable first decision and a small team pilot. Clarify offline and security limits, scheduler cadence and example isolation.
- Expand failure tests, French retrieval cases and the benchmark's changed and unchanged record paths. No runtime dependencies or services added.
v8.1.0 - 2026-09-23¶
Added¶
fkf statuslists active or blocked project notes whoseupdateddate is more than 14 days old underreview, as a reminder rather than a failure.searchandreadkeep local usage counts in the private state directory (time, operation and result count, never the query), summarized byfkf statusover 7 and 30 days so an owner can see whether agents use a base. Retrieval cases are not counted.
Changed¶
- The example Git collector skips hidden repositories, repositories named with
--skip, and bot or reserved-test-domain authors.
v8.0.1 - 2026-09-23¶
Changed¶
- Match English word forms with the FTS5 Porter stemmer, so
meetingsfindsmeetinganddecidedfindsdecide. Existing caches rebuild on the next search.
v8.0.0 - 2026-09-22¶
FKF 8 focuses on the loop that makes a knowledge base useful: collect on a schedule, search from anywhere, read the exact source, keep notes current. It removes machinery that made bases hard to run and notes hard to read.
Breaking changes¶
- Store records as monthly JSON Lines,
records/<source>/<YYYY-MM>.jsonl, with one line per source item upserted by id; snapshot sources keep onesnapshot.jsonl. Immutable per-run capture files, capture hashes, latest/historical snapshots and--historyare removed; Git or backups keep history. This also removes the 20,000-file ceiling that hourly collection reached within two months. - Replace
findandcontextwith onesearch [QUERY] [--since] [--until] [--source] [--type] [--status] [--limit] [--recent]. An empty query lists a time window newest first. Byte budgets are removed;--limitbounds results. - Use readable refs everywhere:
path,path#sectionandsource:id. Base ids,fkf://qualified references andrecord:<hash>URIs are removed. fkf.yamlisversion: 2with anameand noid;fkf.local.yamlis removed. Bases are registered per user in~/.config/fkf/config.yaml, which also grants collection trust per machine.collect SOURCE [--since] [--until] [--dry-run]replaces positional windows and--preview.buildalways rebuilds from scratch;--checkand--if-staleare removed.- Remove containers,
parents,--withinandindexes/structures.json; link folders and labels with ordinarylinks. Remove note supersession, the special## Historyheading, trust-signal computation,reviewedandeffective; note status is one of draft, active, paused, blocked, done, stable, deprecated or archived, andupdateddates a note. - MCP exposes
searchandread. - Convert a v7 base with a one-off script in that base; see the upgrade notes in the documentation.
Added¶
- Search every registered base from any directory, or only the enclosing base; results name their base.
fkf register PATH [--collect]adds a cloned team base; a base never runs collectors on a machine that has not trusted it.- The search cache refreshes itself incrementally before each query, skips and reports unparsable files, and keeps answering, marked
stale, while another writer holds the base. - Relative times:
now,today,yesterday,12h,7d,2wand localYYYY-MM-DDdates. fkf status [--check]reports each source's last run, success, error and private stderr log, and fails when a trusted scheduled source is stale.fkf updatecovers every trusted base, resumes each window source from its last success with overlap, catches up at most 30 days, and keeps run state outside the base.fkf validatereports every problem at once, including broken links, missing headings, cited records that do not exist and misplaced or duplicate records.
Changed¶
- Rank exact identities first, then items matching all words, then any word; notes above records; deprecated and archived notes last; one result per note through its best section.
- Collectors run from the base root with the user's environment minus loader-injection variables, and write stderr to a bounded private log.
- Retrieval cases use
version: 2withexpect,forbid,text,emptyand time filters.
v7.0.1 - 2026-09-21¶
First published v7 release. The v7.0.0 candidate stopped at the macOS package gate before publication; its tag remains unchanged.
Fixed¶
- Resolve temporary smoke environments to physical paths, including macOS
/var, so strict private-state symlink protection remains enabled during distribution checks. Copy packages explicitly when temporary environments and the cache use different filesystems.
Breaking changes¶
- Replace the Go implementation with one typed Python package and the
fkfcommand. Python 3.14 or newer on Linux or macOS is required; install withuv tool install --python 3.14 'fkf==7.0.1'. - Use one current base format:
fkf.yaml, authoredprojects/,wiki/andtasks/, immutable normalizedrecords/, and disposable.fkf/andindexes/. Preserve a v6 base and executable separately; there is no in-place migration or compatibility command. - Remove bundled provider integrations, presets, harness installation, execution approval registries and learning proposal machinery. Bases own collectors, schedules and knowledge editing. Reusable Markdown skills and three source examples are maintained separately from the Python distribution.
- Require an explicitly built, ready cache for indexed retrieval. Missing, stale or corrupt caches name the
fkf buildrecovery command; direct authored and capture-file reads remain available.
Added¶
- Explicit
updatewith a side-effect-free dry-run, per-source refresh policy and durable successful automatic checkpoints. Failed windows stay due, manual collections do not move automatic progress, andbuild --if-staleskips a ready index. - Base-qualified exact evidence references, explicit source structure and membership filters, current versus historical capture retrieval, and authored section references.
- OKF v0.2 wiki structure validation, provenance and asserted verification signals, lifecycle filters, and resumable task folders with inputs and outputs.
- A runnable fictional base with a credential-free collector and retrieval acceptance cases; focused
fkf-use,fkf-learn,fkf-maintainand repository-localfkf-contributeskills.
Changed¶
- Keep CLI and the three read-only MCP tools on shared services. Context includes the complete JSON and final newline within four UTF-8 bytes per budget unit; MCP also counts its response wrapper.
- Match literal lexical terms with case and diacritic folding, explicit identities and authored-note preference. Keep event-time filtering separate from capture recency and decision validity.
- Confine filesystem access, bound subprocess output and runtime, sanitize collection environments, and preserve atomic immutable evidence and a tested rebuild/recovery path.
- Publish a documented installation and upgrade path, complete command reference, skill setup example, and contributor release checklist. Remove obsolete implementation proposals from the current tree.
v6.0.2 - 2026-09-09¶
Fixed¶
- Share a fifteen-second deadline across passive-hook children while allowing individual context calls up to ten seconds. Expired budgets prevent new children, and timed-out process groups are terminated.
- Create every missing parent directory with owner-only permissions during atomic writes, without changing existing directory modes.
- Isolate the security-rule checkout from Git environment variables inherited by linked-worktree hooks, while retaining rejection of local rule edits.
v6.0.1 - 2026-09-09¶
Fixed¶
- Keep passive hooks compatible with system Python 3.9 and newer, independently of the FKF package’s Python 3.14 environment. The formatter now preserves that syntax boundary and a regression test checks it.
- Consolidate the hook’s validated direct-argv dispatch through the fixed system
envexecutable.
v6.0.0 - 2026-09-09¶
Breaking changes¶
- Consolidate source execution and improve offline retrieval. Base-owned helpers now live in
sources/, retrieval evaluations inchecks/queries.yaml, and optional app scripts inclients/. Update declarations and reinstall managed harness hooks, review the resulting execution plan, and renew trust before collecting. Stored evidence remains readable without re-collection.
Changed¶
- Select a persistent launcher explicitly with
harness print/install --executablewhen package-manager PATH entries disagree. - Reuse status narrative pages for briefing commitments instead of reading and parsing task/project files again.
- Rename base collection helpers from
bin/tosources/and retrieval acceptance tochecks/queries.yaml. - Declare single-script uv app clients under
clients:; hash and disclose their separate execution tree. - Make CLI context receipt persistence opt-in with
--save-receipt, keeping ordinary context reads lock-free. - Surface explicit project next actions, review dates, deadlines, and blockers in the offline brief.
- Improve multi-term lexical ranking and excerpts, reuse Unicode-preserving text analysis, and reduce exact-budget packing work.
- Let retrieval evaluations require answer-bearing excerpts and verified offline reads, beyond URI recall.
- Describe harvested lessons as trace citations rather than a knowledge-quality measure.
Fixed¶
- Report exact missing completed dates per enabled event source using the configured collection window, including in briefing attention.
- Reuse task pages for fallback selection and the global learned backlog, and skip a second Markdown parse when rendered headings contain no Learned section.
- Keep conjunctions out of question scoring and select commitment and body excerpts independently so metadata cannot displace the answer.
- Give body-cache manifests an independent 8 MiB bound, retaining the 4,096-entry and 512 MiB content limits.
- Select prompt transcripts through bounded archive metadata and resolve bodies from stored lineage, generation, and turn provenance without changing evidence IDs or deleting history.
- Search project commitments and preserve active handoffs in compact identity context; unify indexed and fallback lesson backlog semantics.
- Compile canonical fragment validation once per process and report hook timeouts without exposing child output.
-
Compare GitHub commit bounds as instants, project safe fallback titles for untitled browser visits, and discard RSS stylesheet metadata without fetching it.
-
Open Chromium-family browser roots and profile directories through retained no-follow descriptors so linked path components cannot redirect local history or bookmark collection.
v5.0.1 - 2026-09-07¶
Fixed¶
- Prevent long-lived MCP stdio servers on Python 3.14 from accumulating timeout callbacks during cancellation polling, eliminating age-correlated CPU and memory growth.
- Let local release verification ignore only uv's exact one-byte
dist/.gitignoremarker while continuing to reject every other unexpected asset. - Parse RSS, Atom, and OPML with a DTD-rejecting XML parser so valid CDATA and predefined or numeric references retain their text without enabling entity expansion.
- Preserve provider-formatted Gmail recipient names while continuing to derive normalized participant identities from mailbox addresses.
- Keep agent session hooks non-blocking when invoked with terminal standard input.
v5.0.0 - 2026-09-07¶
Highlights¶
- Reimplement FKF as one typed Python 3.14 package while preserving the
fkfcommand,fkf: 1configuration and evidence envelopes, trust digests, rebuildable graph and lexical cache contracts, ranking version 7, offline reads, and bounded read-only MCP surface. - Publish a wheel and source distribution for
uv tool install fkfand one-shotuvx fkfuse, with locked uv development, strict Ruff and ty checks, hermetic branch-coverage tests, PyPI trusted publishing, and GitHub build-provenance attestations. - Consolidate provider execution behind one direct-argv boundary, package presets and skills as runtime resources, and retain deterministic differential coverage against the final Go implementation.
- Load the MCP SDK only for MCP commands so ordinary CLI startup does not pay for its server and transport stack.
- Replace the Hugo module with a locked, self-contained Zensical documentation build while preserving the published Pages routes.
Breaking changes¶
- Replace native release archives,
install.sh, and the self-replacingfkf upgradecommand with standard Python packaging. Useuv tool upgrade fkffor a persistent uv installation. - Narrow the existing
?jq=and--whereselector spelling to the safe field-path grammar plus optional terminal| length; arbitrary jq programs are rejected instead of running an embedded evaluator.
Upgrade notes¶
- Existing bases and collected evidence need no migration or re-collection. After installing v5, refresh official helpers, review and renew execution trust, then rebuild derived caches:
fkf config helpers --refresh,fkf trust --all, andfkf build all. - Use a persistent
uv tool install fkflauncher for harness and schedule integrations. Reserveuvxfor one-shot commands.
v4.0.1 - 2026-09-04¶
Fixed¶
- Make Ruff linting independent of contributor-level configuration and use the correct exception types in the Gmail body helper, restoring the clean four-platform release gate.
- Keep historical agent-session collection available as the append-only store grows by bounding in-window identities before selecting their newest complete generation, while rejecting a partial manifest scan.
v4.0.0 - 2026-09-04¶
Highlights¶
- Make every derived-cache check read-only with
build [graph|index|wiki|all] --check, add selective body-cache pruning by source and age, and report lexical-index integrity alongside graph health. - Add reviewed Gmail and Calendar body helpers plus four disabled Google Workspace metadata presets, while keeping provider diagnostics private and bounding provider output before it can fill memory or temporary storage.
- Keep append-only agent-session stores collectible without a lifetime generation ceiling, normalize Git commit titles without discarding raw messages, and refresh the compact embedded usage skill.
- Harden installation, upgrade, and release delivery with exact dirty-build version handling, portable macOS installation, a four-platform CI gate, draft-before-attestation publication, and exact-head Pages deployment.
- Rewrite the README around the concrete benefit—owned, inspectable memory shared across coding agents—and tighten the command, source, graph, privacy, and contributor guides.
Breaking changes¶
- Remove the documented but ineffective
fkf status --allflag; barestatusalready performs the complete offline check. - Emit one
{wiki, projects, records, lint?, ok}document from bare structuredfkf validateinstead of concatenating several top-level JSON reports. - Bound
receipt.consulted_bodiesunder the requested pack budget and expose the complete count asconsulted_bodies_total. - Aggregate text
find --countoutput across the selected window, bound textwhoneighbours per relation kind, and make body-prune text output explicit. - Treat a corrupt lexical cache as a status error. A missing or stale rebuildable cache remains a warning.
- Remove the unused exported
services.StatusRequest.Allfield and add build/prune request types plus cache-health and receipt fields. Go source consumers using unkeyed literals or strict JSON decoders must update.
Fixed¶
- Preserve body-cache crash consistency and confinement across selective pruning, corrupt or missing cache entries, malformed timestamps, symlinked roots, source/age no-ops, and newest-event restore markers.
- Keep command output inside exact byte budgets, make graph-generation state a published confined URI, and prevent stale or corrupt derived caches from masquerading as current.
- Refuse unsafe response-file-style body arguments, disclose the real body execution policy during trust review, and retain one finite shutdown path for oversized or uncooperative body providers.
- Prevent an equal or newer Git-describe development build from being replaced by an older release, and ensure all release archives carry the README, license, notices, checksums, and build-provenance attestations.
Upgrade notes¶
- Existing
fkf: 1configuration and evidence remain valid; no re-collection or data migration is required. - Refresh any installed official helpers, review and renew execution trust, then rebuild derived caches:
fkf config helpers --refresh,fkf trust --all, andfkf build all. - Update consumers of bare structured
validateand the removedstatus --allflag before upgrading automation.
v3.0.2 - 2026-09-03¶
Fixed¶
- Keep the cross-process writer-lock test helper alive without triggering Go's deadlock detector, removing a timing-dependent macOS CI failure without changing runtime behavior.
v3.0.1 - 2026-09-03¶
Fixed¶
- Make schedule CLI tests select the native fake scheduler and managed-file layout, restoring the hermetic CI contract on macOS without changing runtime behavior.
v3.0.0 - 2026-09-03¶
Highlights¶
- Add deterministic
brief,day,timeline,who, andevalworkflows, temporal query grammar, declared identity aliases, and compact text and structured retrieval receipts. - Add digest-bound lexical and constant-time graph caches while keeping durable evidence authoritative, offline reads reproducible, and indexed and fallback retrieval semantically identical.
- Add login-aware opportunistic sync, hourly systemd and launchd scheduling, and idempotent harness integration for Claude Code, Codex, Gemini CLI, Copilot CLI, Antigravity, OpenCode, Grok, Cursor, Kiro, and Cline.
- Add bounded, ignored, manifest-verified body caching with per-source
none,cache, andsyncpolicies; first-class meeting-note and local agent-memory sources can prefetch searchable text without copying it into durable evidence. - Expand and harden the reviewed personal presets, session traces, staged learning workflow, MCP surface, provider pagination, process isolation, trust revalidation, and graph generation consistency.
Breaking changes¶
- Every collected record must now project one meaningful, control-free
title; update custom source schemas and field mappings before the next sync. - Structured
findandcontextresults omit raw provider records and internal day selections by default; pass--rawonly when those diagnostic fields are required.
Upgrade notes¶
- Existing evidence remains valid and requires no re-collection. Run
fkf build all --base <base>to create the new derived graph and lexical caches. - Refresh FKF-owned helpers and harness integrations, review the resulting execution plan, and renew trust before running changed collectors:
fkf config helpers --refresh,fkf harness install --all, thenfkf trust --all. - Body caching stays opt-in per source. The default
bodies: nonefetches only on an explicitread --body;cacheretains an explicitly fetched body andsyncprefetches it after evidence is written.
v2.1.0 - 2026-08-30¶
Highlights¶
- Add a dedicated base
tests/execution tree for source verification hooks, recursively covered by trust and prepended toPATHonly forfkf test; collection and body commands cannot see test fixtures or shadows. - Report source-hook readiness separately from ordinary
requires:, disclosebin/andtests/as distinct trust items, and carry the new layout through init, permissions, schemas, documentation, and bundled skills. - Preserve v2 compatibility: bases without
tests/keep their existing trust digest, hooks can still resolve frombin/, and an empty optional selection remains a successful 0/0 report. Completion gates should name mandatory sources.
Fixed¶
- Restrict repository metadata projected by bundled session, Git, and agent-hook helpers to GitHub remotes, while continuing to strip credentials and reject malformed paths.
- Open Atuin history read-only in batch mode, omit deleted rows and command text, and declare the Git dependency used by the agent-sessions preset.
Upgrade notes¶
- A pre-existing base
tests/directory is now reserved, recursively trust-covered execution material and must contain no symlinks. Move source hooks and their support files there, keep generic repository tests elsewhere, then review and renew trust.
v2.0.1 - 2026-08-29¶
Fixed¶
- Make verified release archives the documented v2 installation path and explain that Go's major-version import rules keep the unchanged module path's
go install ...@latestresolution on v1.
v2.0.0 - 2026-08-29¶
Highlights¶
- Add optional, trust-covered source
test:argv andfkf test, with enabled-source defaults, explicit disabled-source selection, bounded timeouts, stable reports, and provider-stderr privacy. - Publish
graph.meta.jsonschema version 2 with separate SHA-256 inputs for events, index, projects, tasks, wiki, and edge-relevant schema semantics, plus a framed aggregate and exactgraph.tsvoutput digest. - Give every bundled shell helper an explicit
.shextension and require.shor.pywhen scaffolding a helper, including the interpreter in the generated readiness contract when needed.
Breaking changes¶
- Existing derived graph metadata must be rebuilt with
fkf build graph; collected evidence remains readable and requires no re-collection. - Base configurations and harness integrations using bundled extensionless helper names must move to the corresponding
.shnames before refreshing helpers.
v1.1.2 - 2026-08-27¶
Highlights¶
- Flatten the documentation sidebar on desktop and mobile so Overview and every guide are peers, while preserving all published routes and enforcing the rendered navigation contract in tests.
v1.1.1 - 2026-08-27¶
Highlights¶
- Make failed collection diagnostics actionable with the source, date or window, safe substituted command, neutral working directory, timeout, and exit class while keeping provider stderr and body-derived arguments private.
- Stage release installation beside the destination before an atomic replacement, preserving an existing binary if staging fails; cover every published Linux and macOS architecture tuple hermetically.
- Add a dedicated configuration-schema guide, present every documented agent harness at the same level, refresh vendor hook contracts, simplify root help and contributor instructions, and keep the Overview first in the documentation tree.
- Scope toolchain drift checks to project pins, refresh the embedded usage skill and supported-version policy, and retain a strict, generated, link-checked documentation contract.
v1.1.0 - 2026-08-27¶
Highlights¶
- Add
fkf upgrade, which selects the current platform archive, verifies its published SHA-256 checksum and reported version, and atomically replaces the running executable. - Send the documentation root directly to the Overview, expose Overview in the navigation, and remove the intermediate "Read the docs" landing page.
- Explain repeated
fkf syncsafety and how coding agents learn from project and wiki content through the read-only MCP server and embedded skills.
v1.0.0 - 2026-08-26¶
The initial Fmind Knowledge Framework release: one Go binary that collects developer activity into an owned, inspectable base of JSON and Markdown, links it as a graph of relative URIs, and gives coding agents a deterministic context pack under a token budget.
Highlights¶
- Collect complete daily events and point-in-time indexes from local tools, GitHub, Google Workspace, and Google Cloud presets, plus arbitrary reviewed provider commands.
- Compose each source from direct argv or a trust-digested helper whose shebang selects its interpreter, with curated preset helpers for provider boundaries that need shared pagination, completeness, or privacy handling.
- Declare one root semantic
schema:with descriptions, cardinality, examples, and relation roles; sources associate those shared fields with provider paths, and stored documents retain the exact schema subset they used. - Build an open, transcription-only graph: any non-reserved lowercase entity scheme is valid, relation field names are base-defined, and edges come only from declared fields, authored links, tags, and explicit
relations:frontmatter. - Read, find, rank, and graph stored knowledge entirely offline; the read-only MCP server cannot collect, write, shell, or fetch bodies.
- Share one base across Claude Code, Codex, Gemini CLI, OpenCode, Copilot CLI, Antigravity, Cursor, Kiro, Cline, and other harnesses through portable Agent Skills and documented hooks.
- Keep execution explicit with a canonical-plan trust digest covering enabled commands, body-bound paths, helper scripts, executable bits, executable search directories, retry, pacing, and collection policy without re-arming on YAML presentation, inherited environment, or retrieval-only metadata.
- Use one explicit
fkf: 1marker value for strict base configuration and the separate additive evidence envelope. - Store plain JSON and Markdown in five typed layers, with rebuildable
graph.tsvandgraph.meta.jsonat the base root, strict schemas, bounded and atomic I/O, path confinement, owner-only permissions, and untrusted-content framing. - Reproduce lexical retrieval under a hard whole-pack budget with a selection receipt that records scores, reasons, counted exclusions, rejected pins, evaluation day, ranking version, and semantic-input digest.
- Ship synthetic demos, personal and team presets, a strict Hugo documentation site, hermetic race-tested Go suites, security scans, reproducible archives, checksums, and build-provenance attestations.
Supported platforms¶
Release archives are provided for Linux and macOS on amd64 and arm64. Native Windows is intentionally out of scope; WSL2 uses the Linux archive.