Repository navigation
v14.0.0
·
63 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
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.
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.