Your Claude Code, opinionated.
Pip-install a runtime and a Claude Code skill. Run /bonfire scan in chat.
Name your assistant — your cadre wires itself around the name.
Quickstart · The Cadre · Docs · Issues
pip install bonfire-ai # PyPI distribution; Python 3.12+
bonfire install-skill # registers ~/.claude/skills/bonfire/SKILL.md
export ANTHROPIC_API_KEY=sk-ant-...Then in Claude Code, in any project:
> /bonfire scan
> what do you want to call me?
you: Cinder
> what do you want to ship next?
you: a tested refactor of the checkout endpoint
That naming gesture is the inception of your Lexicon — every decision after this becomes part of how Cinder understands you. See Your First Scan for the full conversation.
You don't start with Bonfire and stay the same. The first time you run
/bonfire scan, it asks what you want to call it. You name it. From
then on, every decision you make becomes part of how it understands
you — your trade-offs captured in your bonfire.toml, your nine-role
cadre under whatever names you give them, your priorities recorded in
your persona. Like reading The Neverending Story: the more you
engage, the more the narrative becomes yours.
For flow coders — people who think in systems, who understand craft — the point is to stay in the deep state. Nine role-bound voices (your researcher, your tester, your implementer, your reviewer, and five others) dispatch as Claude Code subagents while you talk. Conversation is the interface. Configuration is what the conversation produces. No external surfaces, no context switching, no friction between thinking and shipping.
The discipline is structural, not advisory. The role that writes failing tests cannot edit implementation. The role that writes implementation cannot edit tests. The reviewer is read-only. Source code is the deliverable.
pip install bonfire-ai drops a Python runtime plus a Claude Code
skill. A one-time bonfire install-skill registers the skill so your
Claude Code session learns /bonfire scan and the rest of the
conversational surface. Bring your own provider key
(ANTHROPIC_API_KEY). File issues at
github.com/BonfireAI/bonfire/issues.
Three things to do before your first scan:
# 1. Install the package. The PyPI distribution is `bonfire-ai`;
# the installed console script is `bonfire`. Python 3.12+.
pip install bonfire-ai
# 2. Set your provider key. Bonfire dispatches to Claude via the
# Anthropic SDK — without ANTHROPIC_API_KEY the first scan fails
# with a cryptic SDK error. Set it in your shell before you scan.
export ANTHROPIC_API_KEY=sk-ant-...
# 3. Install the Claude Code skill. This copies the bundled
# SKILL.md to ~/.claude/skills/bonfire/ so Claude Code learns
# `/bonfire scan` and the rest of the in-chat surface. Re-running
# is safe; it refuses to overwrite a divergent local copy
# without `--force`.
bonfire install-skillNow open Claude Code in your project and ask it:
> /bonfire scan
Bonfire reads your repo, asks you a handful of questions, and writes the config. See Your First Scan below for the shape of the conversation.
A small set of subcommands also work directly from the shell — useful in CI, scripts, or when you want to peek at state without opening a Claude Code session.
# Scaffold a project from the shell (Claude-Code-free path). Creates
# four artefacts under the target directory:
# - bonfire.toml (project config; minimal stub `[bonfire]`)
# - .bonfire/ (per-project state directory)
# - agents/ (role-local prompt + identity-block overrides; see
# Extension Points)
# - .gitignore carrying two entries, appended if missing (idempotent;
# re-running duplicates neither line): `.bonfire/tools.local.toml`
# and `.bonfire/vault`, the knowledge-backend store
bonfire init .
# Drive a prompt through a workflow and the pipeline engine. Needs a
# live agent backend (ANTHROPIC_API_KEY) and spends money. Defaults to
# the nine-stage `standard_build` workflow, whose last stage pushes and
# opens a PR; see "What's Not There Yet" for what that stage needs.
# Pass `--workflow debug` for the two-stage path.
bonfire run "add a failing test for the parser"
# Inspect cumulative cost and recent sessions.
bonfire cost
# List installed personas.
bonfire persona list
# Switch the active persona for this project (writes to bonfire.toml).
bonfire persona set defaultAvailable subcommands: init, scan, run, status, resume,
handoff, install-skill, persona, cost. Run bonfire --help
for the full surface or bonfire <command> --help for any single
command.
From inside Claude Code:
> /bonfire scan
Bonfire reads your repo first — language, frameworks, what's already
in .bonfire/ if anything — then starts asking.
> what do you want to call me?
you: Cinder
> what do you want to ship next?
you: a tested refactor of the checkout endpoint
> what should your researcher focus on first?
you: the data path, then the error handling
> anything off-limits? credentials, secrets, prod databases?
you: yes — never touch the live db
When the conversation completes, bonfire.toml and .bonfire/ are
written. Your cadre is configured.
A Bonfire pipeline is an ordered sequence of stages. Each stage
dispatches an agent of a specific AgentRole (researcher, tester,
implementer, verifier, publisher, reviewer, closer, synthesizer,
analyst). Between stages, QualityGate instances inspect the
envelope and decide whether to proceed, retry once, or stop.
The TDD contract is enforced at the role boundary: your tester writes failing tests that define the contract (RED), your implementer writes code to pass them (GREEN), and your verifier runs an independent quality check before your publisher opens a PR. Your reviewer can bounce work back into the loop until it passes or the budget is exhausted. Your closer seals the work — merges the PR, posts the completion, closes the ticket — only after every gate has cleared.
Bring your own provider key. Pick the model per role. Models are
resolved through resolve_model_for_role, which maps each
AgentRole to a capability tier (reasoning, fast, or balanced)
and returns the corresponding provider model string from your
config. Pure synchronous resolution; never raises on a string input.
Bonfire ships nine role-bound agents; the runtime picks how each one
runs. Four dispatch through an LLM agent backend; three are
deterministic stage handlers wrapping gh / git / pytest with no
LLM call at all; one combines synthesis with a bounded correction
step; one is opt-in pre-pipeline architectural analysis. The cadre is
fixed in source as a StrEnum and rendered through three name
layers — the generic identifier, the professional display name, and
the gamified display name. The persona you pick chooses how each role
is named in your CLI output; if you author a custom persona, every
role can wear whatever name you give it.
The generic concept describes what the role does. The
professional name (AgentRole) is the canonical serialized form
used in TOML, JSONL, CLI output, and grep patterns. The gamified
name is a workflow alias emitted by the standard and research
workflow templates and normalized through GAMIFIED_TO_GENERIC
before tier lookup.
| Generic Concept | Professional (AgentRole) |
Gamified (workflow alias) |
|---|---|---|
| Investigates the task and gathers context | researcher |
scout |
| Writes failing tests (TDD RED) | tester |
knight |
| Writes code to pass the tests (TDD GREEN) | implementer |
warrior |
| Independent quality verification | verifier |
cleric |
| Creates branches, commits, opens PRs | publisher |
bard |
| Code review with structured verdicts | reviewer |
wizard |
| Merges approved PRs and announces completion | closer |
steward |
| Combines multiple reports into unified analysis | synthesizer |
sage |
| Architectural and structural analysis | analyst |
architect |
The string prover appears in the standard_build pipeline as a
stage label; that stage dispatches to the verifier role. Stage
labels name DAG nodes inside a workflow plan; display names are the
persona-emitted role names in CLI output.
Note — Falcor is a persona, not a role. The cadre is the nine roles above. The persona is what speaks for them at the CLI surface. See Personality below.
Alongside the cadre, the Vault is the named knowledge store of
Bonfire's world — capitalized, personified in display vocabulary,
narrated by the persona at lifecycle moments (The Vault remembers,
The Vault gives back). The Vault is not an agent; it is never
dispatched and has no role. Today the VaultBackend Protocol is
published and an in-memory default backend ships (substring
matching, no embeddings, no external dependencies, suitable for
tests and small projects). A SQLite backend also ships in the base
install and persists across processes, retrieving by keyword substring
rather than by vector. A LanceDB-backed implementation is available
behind the bonfire-ai[knowledge] extra. The graph layer over that
persisted store is still to come.
Bonfire reads bonfire.toml from the current working directory.
Settings priority is: constructor kwargs → environment variables
(BONFIRE_ prefix, __ nested delimiter) → bonfire.toml → field
defaults.
A minimal complete config showing every section and its real defaults:
# bonfire.toml
[bonfire]
tier = "free" # commercial tier
model = "claude-sonnet-4-6" # default model when no role match
max_turns = 10 # per-agent turn cap (must be > 0)
max_budget_usd = 5.0 # per-pipeline budget cap (>= 0)
persona = "falcor" # CLI output persona
trust_project_settings = false # opt-in: ingest CLAUDE.md / .claude/ (see Security)
[bonfire.profile] # written by `bonfire scan`; the onboarding answers
# companion_mode = "friend" # free-form string map, absent until you run a scan
[models] # bring your own provider key — strings live here
reasoning = "claude-opus-4-7" # researcher, reviewer, synthesizer, analyst
fast = "claude-haiku-4-5" # tester, implementer, verifier, publisher, closer
balanced = "claude-sonnet-4-6" # fallback for unknown role strings
[memory]
session_dir = ".bonfire/sessions"
context_file = ".bonfire/context.json"
[git]
auto_branch = true
auto_commit_on_green = true
require_pr = trueThe [models] section holds the strings Bonfire passes verbatim to
the agent backend. To use a different provider, swap the strings to
that provider's model identifiers and plug in a matching
AgentBackend (see Extension Points below).
Bonfire dispatches agents with the Claude Agent SDK, which can ingest
the project's CLAUDE.md and .claude/settings.json into the agent's
system prompt and hook table. Bonfire defaults to deny: a foreign
repo's project settings are NOT loaded unless one of these holds:
bonfire.tomlcontains[bonfire] trust_project_settings = true(literal boolean — strings and ints are ignored).- The environment variable
BONFIRE_TRUST_PROJECT_SETTINGS=1is set (operator escape hatch, strict equality on the value"1"). - The dispatch
cwdis empty /None(in-tree dogfood path).
Why this matters: a malicious clone could otherwise plant instructions
in its CLAUDE.md or wire hostile hooks in .claude/settings.json
that would silently land in any agent you dispatch from inside that
repo. Opt-in is required.
resolve_model_for_role(role, settings) -> str is the public
primitive. Given a role string (canonical or gamified) and a
BonfireSettings, it normalizes the input, looks up the canonical
AgentRole, maps that role to a ModelTier, and returns the
provider model string for that tier from settings.models.
The default role-to-tier mapping:
AgentRole |
ModelTier |
|---|---|
researcher |
reasoning |
tester |
fast |
implementer |
fast |
verifier |
fast |
publisher |
fast |
reviewer |
reasoning |
closer |
fast |
synthesizer |
reasoning |
analyst |
reasoning |
If the input string matches neither a canonical AgentRole nor a
gamified alias, the resolver falls back to ModelTier.BALANCED and
returns settings.models.balanced. The function never raises on a
string input — unknown roles degrade to the balanced model rather
than failing the dispatch.
Bonfire ships persona-driven CLI output. The persona affects display only — it never enters agent prompts and never changes quality standards. The cadre is what runs; the persona is what speaks.
The default persona for v1.0.0 is Falcor — gentle, encouraging,
warm. The friend who tells you not to let it end.1 Falcor
narrates pipeline events, greets you on /bonfire scan, and names
lifecycle moments of the Vault.
Two other personas ship for users who want neutral output:
default (professional) and minimal (terse, CI-friendly).
# Inspect installed personas
bonfire persona list
# Switch the default for this project (writes to bonfire.toml)
bonfire persona set defaultThe persona is configured per project via bonfire persona set <name>;
there is no per-command override flag. A per-command override lands
when the narration/output layer grows persona awareness.
Custom personas live in ~/.bonfire/personas/. The persona slot is
user-extensible: name your own assistant, write a phrase bank, drop
it in the directory.
A breadcrumb: Falcor refactors a slot earlier occupied by a
predecessor named Passelewe. History is sacred — see
docs/_lore/passelewe.md if you want the lineage.
Four @runtime_checkable Protocols define Bonfire's pluggable
boundaries. The composition root verifies conformance at registration
time, so any object with the matching shape works — no inheritance
required.
from typing import Protocol, runtime_checkable
from bonfire.protocols import (
AgentBackend,
DispatchOptions,
QualityGate,
StageHandler,
VaultBackend,
VaultEntry,
)AgentBackend — swap the LLM provider that executes a single
agent turn.
@runtime_checkable
class AgentBackend(Protocol):
async def execute(
self, envelope: Envelope, *, options: DispatchOptions
) -> Envelope: ...
async def health_check(self) -> bool: ...VaultBackend — swap the persistent knowledge store. Embedding
is internal to the backend; callers pass text, never vectors.
@runtime_checkable
class VaultBackend(Protocol):
async def store(self, entry: VaultEntry) -> str: ...
async def query(
self, query: str, *, limit: int = 5, entry_type: str | None = None
) -> list[VaultEntry]: ...
async def exists(self, content_hash: str) -> bool: ...
async def get_by_source(self, source_path: str) -> list[VaultEntry]: ...QualityGate — custom pass/fail logic between pipeline stages.
@runtime_checkable
class QualityGate(Protocol):
async def evaluate(
self, envelope: Envelope, context: GateContext
) -> GateResult: ...StageHandler — custom stage orchestration when an agent
dispatch is the wrong shape (parallel fan-out, human-in-the-loop,
external APIs).
@runtime_checkable
class StageHandler(Protocol):
async def handle(
self,
stage: StageSpec,
envelope: Envelope,
prior_results: dict[str, str],
) -> Envelope: ...The graph layer over the persisted store is still to come. The
protocol is stable today; the in-memory default backend and a
persistent SQLite backend both ship in the base install, and a
LanceDB-backed implementation is available behind the
bonfire-ai[knowledge] extra.
Honest list:
standard_buildneeds a publishable git remote to finish. The verb is wired end to end, andstandard_build, the nine-stage flagship, is the default workflow. Its publishing stage reads the list of files to commit fromEnvelope.artifacts; the dispatch layer now records the agent's file-mutating tool calls onto that field and the engine carries them down the run, so the stage reaches git instead of refusing withempty_artifactson every run. What it still needs is somewhere to publish to: a git remote it can push to and a workinggh. Without those it fails at the push, naming the cause.--workflowacceptsdebug,spike,dual_scout,triple_scoutandstandard_build.bonfire resumereports, it does not re-dispatch. It reads the last checkpoint, reconstructs the workflow plan, and prints which stages remain. It does not run them. Driving the remaining stages is a library call today:PipelineEngine.run(plan, completed=...).- Legacy onboarding path.
bonfire scanfrom a shell still launches the alpha-era Front Door (a local browser auto-opens by default; pass--no-browserfor headless). That path is the deprecated alpha onboarding surface and is preserved for users who have not yet installed the Claude Code skill. The opinionated front door is/bonfire scanfrom inside Claude Code; seedocs/scan-front-door-protocol.mdfor the legacy protocol if you need it. - Bundled prompt templates cover four cadre roles, not all nine.
Default identity blocks ship in the wheel for the researcher,
implementer, reviewer and tester roles, and load automatically when
a project supplies no override. The other roles have no bundled
default; their prompt-layer identity is contributor-supplied via
agents/<role>/. - Embedding-backed retrieval is an optional extra. A persistent
knowledge store ships in the base install (SQLite, standard library
only, survives across processes) and retrieves by keyword substring
match. Vector search needs
pip install bonfire-ai[knowledge], which pulls LanceDB and Ollama. The default backend when nothing is configured is still in-memory, so it is discarded at exit. - No downstream product surface imports the package yet. Wrappers
and vertical surfaces are designed against the engine but not wired
to it. The release-gate Box is the exception and is not a product
surface: it installs the built wheel into a container, imports it,
and runs the real
bonfire runagainst a fixture repo.
The under-claim is the feature. This list is checked against main,
not against the roadmap.
What's coming next, in rough order:
- A
standard_buildrun graded end to end in the release-gate box. The publishing stage now receives the files the agent wrote. What is still unproven is a full nine-stage run against a fixture repo with a real remote, which is the E2E signaldocs/release-gates.mdrequires before av0.1.0tag. - In-chat parity for every CLI verb.
/bonfire scanis the primary conversational surface; the other verbs gain in-chat skill mappings later. - Bundled identity blocks for the remaining cadre roles. Four of nine ship today.
- Vector retrieval as a default rather than an extra, and a
knowledge graph over the persisted store. Today the base install
persists to SQLite and retrieves by keyword; embeddings live behind
the
bonfire-ai[knowledge]extra. - Multi-forge support via the Instruction Set Markup (ISM) seam —
declarative third-party tool integrations replacing today's
hard-coded
gh-only forge calls. - Additional public products — Bonfire is the first; more open repos will follow.
Bonfire is developed at github.com/BonfireAI. Issues, PRs, and discussion welcome.
Apache-2.0.
Footnotes
-
Yes, that Falcor — the luckdragon, The Neverending Story (1984). ↩