Skip to content

v14.0.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 02:05
· 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) require version. YAML follows the 1.2 core schema: yes, no, on and off are strings, 017 is decimal and 1:30 is text.
  • Notes: in projects, concepts and ACTION.md notes, only deprecated closes a note: it ranks last and leaves home, tasks and review reminders. Aliases must be namespaced identities such as repo: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 valid title, type, status, updated, summary and description apply, 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-with is reserved for tag membership, and periods accept ASCII digits only. bf://NAME/source:id always 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 validate reports stray files and hidden .json files under memories/.
  • Selection and execution: a bare --brain NAME or BF_BRAIN=NAME resolves through your registry first and fails when the enclosing brain or its references claim that name for another directory. update, collect, watch and schedule act on exactly one brain (--brain, BF_BRAIN or 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 with neither registered nor the enclosing brain. An enclosing bf.yaml must be a regular file owned by you, and the user registry ~/.config/bf/config.yaml must be a regular file. Program executables must be bare command names or normalized sensors/ or routines/ 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-removal accepts one such run. Failed sensors and routines retry after 1, 2, 4… minutes, capped at their refresh, instead of every cycle; bf collect retries a sensor at once. A concurrent bf update of 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: problems is always a list of objects with error and optional brain and file. bf build and bf update report skipped files as skipped and exit 1 when files were skipped; bf status reports its cache as cache, and its source and routine entries use state, last_collected, window, last_run, last_success, failed, failures and log instead of the removed enabled, configured, run, success, start and end keys. bf update replies with one brain object whose sensors and routines lists are always present. Search no longer returns more; next_offset alone signals continuation. All instants are canonical UTC ending in Z; absent ones are omitted, except in bf watch --json rows, where success and next_due are then empty strings. A source without dated records has no latest. bf watch --json no longer emits observing.
  • 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 read tool has no brain argument; use a bf://NAME/... address. Both MCP tools reject unknown arguments, such as that brain or a misspelled scope, instead of ignoring them. Identity scopes include the identity's owning note. An unknown memories/SOURCE scope is not found, and a segment below it other than a period, undated or a record file is invalid. Malformed refs, bf://NAME without 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 .bf and rejects a .bf that is a symlink, not a directory or owned by someone else.
  • Evaluation: bf eval validates every case while loading, including scopes (a 0d window is invalid), read refs, bf:// addresses and query words, and fails the whole run on an invalid suite.
  • Scheduling: a relative bf schedule --output resolves 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, done and archived statuses, the /logs/ entry in new brains' .gitignore and the hand-written systemd example.

Added

  • Sort bf watch and bf status --watch by 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 expose records, the last successful sensor run's returned count.
  • bf schema --kind exports offline editor schemas for brain, watch, registry and evaluation files, generated and checked from the runtime models.
  • bf eval assembles chunked exact reads and verifies their digest before checking read cases.
  • bf validate names the file of every problem, flags capped lists with problems_truncated and unresolved_truncated, checks embedded images and accepts page addresses (home, folders, periods, tags, sources and record files) as link targets. Project notes resolve a leading / from projects/, as concepts already did.
  • Registered brains that are absent on this machine appear in search and read problems, and bf status --check fails on them and on brains: references that retrieval cannot include.
  • memories/SOURCE/undated is 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.md from 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_BRAIN set to the executing brain, so nested bf calls read that brain.
  • For scheduled window sensors, a manual bf collect after a pause no longer moves the resume point past the uncollected gap.
  • The AGENTS.md written by bf init states execution authority, one-brain selection, incomplete-result boundaries, deprecated-only closing, chunked reads and multi-brain uri reads. New brains' starter evaluation reads bf://NAME/concepts/welcome.md, and new bf.yaml files 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 matching bf --version, and name action folders YYYY-MM-DD_topic-SUFFIX; tests/test_guides.py runs 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: SUMMARY at their original time, the Git history sensor reads branches, tags, remotes and HEAD and skips unreadable folders, and the team example is a bf and git walkthrough.
  • Ordinary Markdown whose foreign frontmatter is not valid YAML stays searchable without it, a block that never closes is searched as text, and Emacs .#NAME lock files beside authored files are ignored, so none of them fails bf build, bf update or bf 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 QUERY or --scope, bf register names a missing directory or bf.yaml, unavailable or unloadable brains are named once by their registered or brains: name, and bf init asks for --name when the directory name cannot form one.
  • bf schedule without --output warns that its install commands name files it did not write. When an update fails only because the search cache skipped files, bf watch says 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 eval names 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 it instead 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.yaml is 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, BASHOPTS and PS4.
  • 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 --watch no longer suggests the program-executing bf 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 --json rows 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 status no longer quote an undeclared link relation from sensor output.