brf (say "brief") gives each of your projects a re-entry brief: one page you can read on your phone that tells you, as if you had just come back from a long vacation, what the project is, why it matters, what happened while you were away, and what it needs from you.
Your coding agent writes it from the repository's own records: git history, handoffs, planning files, CI and live deployments. The agent changes nothing in the repository. The page is a single HTML file with its fonts inside it and no scripts, so it opens offline from any phone's files app.
Big picture first, in about 180 words on one screen:
- Status strip: stage, health and momentum from the same closed vocabulary on every project, and an attention dial from 1 to 5 with one line of reason.
- The big idea: what the project is for and why it matters, in a sentence or two.
- What it unlocks, naming your other projects, and related projects as chips.
- What's missing to be functional: a short checklist with a meter ("3 of 5 in place").
- One decision at most, with a recommended answer and the time it needs.
- Activity: commits per week for the last eight weeks.
Collapsed below: what changed since the last brief, risks, and two appendices for the project manager: a planning records inventory that shows where plans live and whether they match what is built, and a read-only code hygiene inventory.
The meta brief is one page across all your projects: where to start today, every decision waiting on you, every project as a ranked card, and how the projects feed each other.
Both switch between light and dark with one button and no script.
examples/tidewater.filled.html and examples/meta.filled.html are complete examples about a
fictional portfolio.
brf is an agent skill plus a small command line, brf: one program, written in Rust, with the
templates and fonts built in. You need git. Clone the kit (the skill reads its protocol and
examples from the clone), then install brf one of two ways:
git clone https://github.com/bradheitmann/brf.git ~/brf
cargo install --locked --path ~/brf # builds brf and puts it in ~/.cargo/binor download the prebuilt archive for your computer (macOS Apple silicon or Intel, Linux x86_64 or
arm64) from the releases page, unpack it, and put brf on your PATH. brf version should print
brf 2.0.0 or newer. After a git pull, run the cargo install line again.
Make /brf available to your agent by linking the clone into its skills folder. For Claude Code:
ln -s ~/brf ~/.claude/skills/brfAgents that do not load skills can use PROMPT.md instead.
Optional:
- Playwright with Chromium for the render check at five screen widths. The check is a small
TypeScript script that
brfruns with Node 22.18 or newer, or Bun, so one of those is needed too. Install Playwright, then tell brf where it is when you runinit(below):npm i -g playwright && npx playwright install chromium, then add--playwright "$(npm root -g)/playwright"tobrf init. - Mister Clean for the hygiene audit (
npm i -g @bradheitmann/mister-clean). Without it the agent inspects the ten categories by hand. - GitHub CLI (
gh) for pull requests, issues and CI runs.
brf never picks the folder for you. Choose one you can open on your phone, such as a synced cloud-drive folder, then run:
brf init --output "<your folder>"This creates the folder with an empty registry.json and an archive/ folder, and records the
path in ~/.config/brf/config.json. On a second computer that syncs the same folder, run the same
command; the existing registry is kept. BRF_OUTPUT_DIR overrides the config for one shell.
Other settings in the config file: playwright (a path from which Playwright resolves),
gh_user (the gh account that can read your repositories), extra_banned_words, and
templates_dir: a folder with your own project.html, meta.html and fonts.css in your own design
system. brf uses each file it finds there instead of its built-in one. Your templates must carry the
same slots and repeat blocks as the built-in ones of the same major version. Keeping that folder next to your
briefs means every machine that syncs the output folder uses the same design.
Only projects in your registry get briefs. Agents never go looking for projects, and asking for a brief does not register one. To add a project, say so explicitly from inside that repository; the agent records your words:
brf register --reason "Brief this one every Monday" --everyday-name "Tidewater"Each entry records the project's folder and remote. If a project moves or its repository is
renamed, update local_path and remote in registry.json yourself; brf refuses a checkout
whose remote no longer matches its entry.
Inside a registered repository, ask your agent for /brf. It writes one brief for that project
and delivers it. /brf meta writes the meta brief from the current project briefs.
The output folder:
<your folder>/
registry.json
brf_<repo-name>_<yyyymmdd>.html one current brief per project
meta_brf_<yyyymmdd>.html the current meta brief
archive/ every earlier brief; nothing is deleted
Each brief shows, at its foot and in its meta tags, its brief number for that project, the
brf version, and the template version it was built from. Template versions follow semantic
versioning on their own; see CHANGELOG.md.
| Command | What it does |
|---|---|
brf init --output <folder> |
Set up the output folder and point this computer at it |
brf context [--meta] |
JSON for the agent: project name, registration, file name, brief number, earlier briefs, work folder |
brf register --reason "<words>" |
Add the current repository to the registry |
brf snapshot --out <file> / --compare <file> |
Compare covered Git state, with explicit exclusions |
brf build <filled> --out <work_dir>/<name> [--verify] |
Embed fonts, refuse unfilled slots, stamp versions, render-check |
brf deliver <built> |
File the brief; the project's previous brief moves to archive/ |
brf check [--file <brief>] |
Check one brief, or the whole folder, against the protocol |
brf version |
Print the brf and template versions |
Exit codes: 0 done, 1 problems found (a check, a changed snapshot, a failed render check), 2 a refusal or usage error, with the reason on stderr, 3 the render check was skipped.
brf carries its templates. Run from a clone (target/release/brf), it uses the clone's
templates/; installed on its own, it unpacks them once to ~/.cache/brf/assets/<version>/
(or under $XDG_CACHE_HOME), and brf context gives the agent that path.
This repository holds templates, the protocol, the skill and the command line. Your briefs, your registry and your settings stay in your output folder and your config file, never here.
npm install --prefix verify # TypeScript, for the type check of verify/verify.ts
# (with pnpm: pnpm install --dir verify --ignore-workspace)
cargo test
cargo build --release # target/release/brfcargo test runs the Rust tests, type-checks verify/verify.ts with tsc --noEmit in strict
mode, and runs a parity test that compares brf with brf 1.2.0, the earlier Node command line,
taken from this repository's git history. The parity test needs node; without it the test says
it skipped (set BRF_PARITY_REQUIRED=1 to make that a failure, as CI does). To compare both on a
copy of your own brief folder:
BRF_PARITY_REAL_DIR=<folder> cargo test --test parity -- --ignored.
Pushing a version tag (v2.1.0) builds macOS and Linux archives and attaches them to a draft
release; see .github/workflows/release.yml.
Protocol and voice rules: PROTOCOL.md. Agent procedure: SKILL.md. Changes: CHANGELOG.md.
MIT for brf. The embedded fonts (Cormorant Garamond, Inter, JetBrains Mono) are under the SIL Open
Font License 1.1; see fonts/OFL.txt.
A repository identity includes its Git host and any non-default port. HTTPS and SSH spellings on the same host can match; an unknown SSH alias or mirror is a different identity. Case is preserved on hosts without a known case-insensitive namespace. A changed host cannot silently retain a registered identity.
brf snapshot compares the git-state-v1 coverage printed in its JSON output.
same: true means that covered state matched, not that every file is unchanged.
Coverage includes tracked changes, non-ignored untracked contents, ignored path
names, refs, stashes, worktrees and HEAD's reflog. It excludes ignored contents
(such as an existing .env), Git configuration/hooks, external files and changes
that happen between its separate reads. Use an independent filesystem-integrity
control when those excluded inputs matter. No secret file contents enter a
snapshot. The historical snapshot digest remains compatible with v1.
The default build keeps the complete CLI, templates, render verification, Git snapshots, registry, and delivery workflow. To validate supplied HTML in an embedding application without compiling those capabilities, use the Git source pinned below. The binary install and release paths described above do not imply that the Rust library is published on crates.io.
brf = { git = "https://github.com/bradheitmann/brf", rev = "5960d4b284fe503535800543c894064075bd3355", default-features = false }use brf::validation::{BriefInput, validate};
let report = validate(BriefInput {
html: "<main>Example</main>",
name: "brf_example_20261019.html",
banned_extra: &[],
});
assert!(!report.is_valid()); // A finished brief requires its version stamps.validation owns the content allowlist, CSS checks, stamp agreement, and prose
rules. It treats the supplied name as metadata and performs no I/O. It is a
protocol checker, not a general-purpose HTML sanitizer or browser-equivalence
proof. The lightweight surface also includes html, naming, and util.
full enables all existing public modules; check::* keeps its content APIs as
compatibility re-exports and owns file/folder orchestration. Template versions
and snapshot coverage remain unchanged. Rendering still requires its separate
runtime and browser dependencies when requested.
Validate this boundary with cargo test --no-default-features --lib --test validation.