Deterministic guardrails for AI agents.
Frankenbeast is a safety framework that enforces guardrails outside the LLM's context window. Every check that can be deterministic is deterministic — regex-based injection scanning, schema validation, dependency whitelisting, DAG cycle detection, HMAC signature verification. These do not hallucinate.
Want to make your first change? Follow the contributor guide from issue selection through setup, focused verification, and pull-request review. If the issue changes only Markdown, use the docs-only contribution quickstart to skip unrelated runtime setup while preserving link checks and review evidence. If your fork is behind, you edited the wrong branch, or a push is rejected, use the fork and branch recovery guide before resetting or rewriting history. If a pull-request check turns red, use the first-PR CI failure triage guide to inspect the current head, reproduce the narrow failure, and avoid blind reruns. If you get blocked, use the first-contribution help guide to choose the right discussion and share safe, actionable evidence. After your pull request merges, use the first-PR completion guide to verify issue closure, update your fork, and safely remove the merged branch or worktree.
Starting from a fresh checkout? Use the Frankenbeast onboarding checklist for prerequisites, environment setup, and first-run validation. If you need to choose among the repository's setup, contribution, architecture, agent, and release guides, use the onboarding guide index instead of reading every document up front. Dashboard contributors can use the dashboard UX contribution checklist to reproduce, implement, and verify accessible UI changes with reviewable evidence. Read the concise RAMP_UP.md guide when you need a quick contributor orientation. If you want a role-specific path first, choose the persona quickstart track for operators, contributors, or agent-developers. If setup fails, use the setup troubleshooting matrix to map symptoms to diagnostic commands, safe remediations, and verification checks. Coding agents should also read the first-PR agent runbook for the end-to-end issue-to-PR flow, the coding-agent PR etiquette guide before opening, updating, or merging PRs, and the release and deployment mental model before owning post-merge or release handoffs. If you are trying to understand the system before changing it, follow the Architecture reading path for current implementation docs before historical plans, then use the architecture map for new agent contributors to route issues to the right package, tests, approval/HITL boundary, and memory surface. If an agent coordination handoff uses runtime coordination terms, read the agent coordination runtime glossary before acting. New agents that need a low-risk edit/test rehearsal can use the agent practice fixture, which includes an intentionally failing scoreboard test, reset script, and sample issue body. Then run the repository bootstrap script:
npm run bootstrap -- --no-dockerThe bootstrap command delegates to scripts/bootstrap.sh, which validates Node.js, npm/Corepack, .env defaults, dependencies, and optional Docker services. The persona quickstart tracks name the prerequisites, setup commands, validation commands, and first-success output for each supported role. If you want persona-specific generated guidance before running setup commands, use npm run first-run:checklist -- --persona operator or npm --silent run first-run:checklist -- --persona coding-agent --json. To orient a human or agent inside the repository, run npm run workspace:tour or npm --silent run workspace:tour -- --json for a package map, key docs, generated files, test commands, runtime state paths, safe first commands, and docs-drift checks. New issue workers can run npm --silent run new-worker:preflight -- --json before coding to verify the local Node/npm/git/gh/jq toolchain, GitHub authentication, project git identity, repository root, and worktree cleanliness with parseable structured output for coordination handoffs. For a broader setup healthcheck with actionable remediation and machine-readable output, run npm --silent run setup:healthcheck -- --json; it verifies Node/npm, dependency install state, env files, git status, common local ports, optional GitHub auth, and optional service endpoints without failing on warnings. Pass --services when you want bootstrap to start the optional Docker compose stack after dependency installation. To preview the checks without changing files or installing packages, run:
./scripts/bootstrap.sh --dry-runSee GitHub Releases for the latest published release and CHANGELOG.md for the complete release history.
MCP mode: Claude Code plugin/tool-provider surface via@franken/mcp-suiteBeast mode: standalone orchestrator path with dashboard-first control and CLI parity
Both modes share .fbeast/beast.db.
LLM-based agents routinely lose safety constraints when context windows compress, hallucinate tool calls that violate architectural rules, and take destructive actions without human oversight. Frankenbeast solves this by placing safety enforcement in a deterministic pipeline that the LLM cannot bypass, forget, or summarise away.
The key guarantee: Safety constraints survive context-window compression because they are enforced by the firewall pipeline, not by the LLM prompt.
See SECURITY.md for vulnerability reporting, dependency update expectations, secret handling, HTTPS guidance, and runtime hardening recommendations. See docs/agent-tool-execution-threat-model.md for the agent tool-execution trust boundaries that cover terminal, filesystem, GitHub, profile state, cron, and agent coordination approval flows. See docs/security-json-parsing-limits.md for JSON input limits; Beast config, run config, GitHub issue payloads, and LLM issue decomposition payloads are size/depth/fan-out bounded, and YAML is not accepted on those surfaces.
Frankenbeast is currently organized as 10 npm workspace packages under packages/*. Several originally separate MOD packages have been consolidated into the orchestrator or MCP suite: firewall/security middleware, skills/provider loading, heartbeat/reflection, external comms, and MCP registration are current implementation surfaces inside @franken/orchestrator and @franken/mcp-suite, not standalone package directories.
The diagrams below use current package names or implementation-surface names, and the package inventory table remains the authoritative workspace map.
Start with the current workspace package inventory for the package-name source of truth, then see docs/ARCHITECTURE.md for the full interconnection diagram.
Older copies of these diagrams used numbered MOD capability labels. Their current equivalents are: MOD-01 → @franken/orchestrator firewall; MOD-02 → @franken/orchestrator skills; MOD-03 → @franken/brain; MOD-04 → @franken/planner; MOD-05 → @franken/observer; MOD-06 → @franken/critique; MOD-07 → @franken/governor; and MOD-08 → @franken/orchestrator heartbeat.
Text alternative — Beast Loop overview: User input enters ingestion, where the orchestrator firewall sanitizes it and the brain hydrates context. Planning builds and critiques a task graph. Execution resolves tools and requests human approval for high-stakes work. Closure records observability data and performs reflection before it returns the final BeastResult to the user. Circuit breakers can halt unsafe input, require approval when budgets are exceeded, or escalate planning spirals.
flowchart TD
User([User Input])
subgraph Beast["The Beast Loop"]
direction TB
subgraph P1["Phase 1: Ingestion"]
FW["@franken/orchestrator firewall<br/>Injection scan, PII mask"]
MEM["@franken/brain<br/>Context hydration"]
end
subgraph P2["Phase 2: Planning"]
PL["@franken/planner<br/>DAG task graph"]
CR["@franken/critique<br/>8 evaluators, loop"]
end
subgraph P3["Phase 3: Execution"]
SK["@franken/orchestrator skills<br/>Registry + MCP tools"]
GOV["@franken/governor<br/>HITL approval gates"]
end
subgraph P4["Phase 4: Closure"]
OB["@franken/observer<br/>Traces, cost, evals"]
HB["@franken/orchestrator heartbeat<br/>Reflection + briefs"]
end
CB["Circuit Breakers<br/>Injection → halt | Budget → HITL | Spiral → escalate"]
P1 --> P2 --> P3 --> P4
CB -.-> P1
CB -.-> P2
CB -.-> P3
end
Result([BeastResult])
User --> P1
P4 --> Result
classDef phase1 fill:#ff6b6b,stroke:#c0392b,color:#fff
classDef phase2 fill:#ff9f43,stroke:#ee5a24,color:#fff
classDef phase3 fill:#54a0ff,stroke:#2e86de,color:#fff
classDef phase4 fill:#10ac84,stroke:#0a3d62,color:#fff
classDef breaker fill:#2d3436,stroke:#636e72,color:#fff
classDef external fill:#dfe6e9,stroke:#636e72,color:#333
class FW,MEM phase1
class PL,CR phase2
class SK,GOV phase3
class OB,HB phase4
class CB breaker
class User,Result external
Text alternative — Beast Loop sequence: The user sends raw input to the orchestrator firewall, which scans for injection and masks PII while the brain supplies project context to the planner. The planner builds a task DAG and sends it through repeated deterministic and heuristic critique until it passes; a spiral instead escalates to the governor. For each approved task, orchestrator skills resolve a registry or MCP tool, the governor accepts or denies high-stakes actions, and the observer records spans and token usage. Finally, the observer produces trace and cost summaries, orchestrator heartbeat reflects and may feed improvement tasks back to planning, and the observer returns BeastResult to the user.
sequenceDiagram
participant U as User
participant FW as @franken/orchestrator firewall
participant MEM as @franken/brain
participant PL as @franken/planner
participant CR as @franken/critique
participant SK as @franken/orchestrator skills
participant GOV as @franken/governor
participant OB as @franken/observer
participant HB as @franken/orchestrator heartbeat
U->>FW: raw input
rect rgb(255, 220, 220)
Note over FW,MEM: Phase 1 — Ingestion
FW->>FW: injection scan + PII mask
FW-->>PL: sanitized intent
MEM->>MEM: hydrate ADRs, episodic traces
MEM-->>PL: project context
end
rect rgb(255, 240, 220)
Note over PL,CR: Phase 2 — Planning
PL->>PL: build task DAG
loop Critique loop (max N)
PL->>CR: submit plan
CR->>CR: deterministic evals first, then heuristic
alt Plan passes
CR-->>PL: approved
else Plan fails
CR-->>PL: re-plan
end
end
alt Spiral breaker tripped
CR->>GOV: escalate to human
end
end
rect rgb(220, 230, 255)
Note over SK,GOV: Phase 3 — Execution
loop Each task in topoSort()
SK->>SK: resolve skill (registry or MCP)
alt High-stakes task
SK->>GOV: request HITL approval
GOV-->>SK: approved / denied
end
SK->>OB: record span + token usage
end
end
rect rgb(220, 255, 230)
Note over OB,HB: Phase 4 — Closure
OB->>OB: finalize traces, cost summary
HB->>HB: pulse check + reflection
HB-->>PL: inject self-improvement tasks (if any)
end
OB-->>U: BeastResult
Text alternative — module interconnections: The orchestrator's four-phase Beast Loop coordinates the current implementation surfaces: ingestion connects to the orchestrator firewall and brain; planning connects to planner and critique; execution connects to orchestrator skills, governor, and the MCP suite; and closure connects to observer and orchestrator heartbeat before returning a result. The firewall sends sanitized intent to planning and validates skill calls; planning discovers skills and loads memory; critique can enforce firewall rules or escalate to the governor; the governor consults observer circuit breakers; and heartbeat uses traces and memory to inject improvement tasks. External LLM providers connect through the firewall adapter, while external MCP servers connect through the MCP suite registry and client.
graph TB
User([User Input])
subgraph "@franken/orchestrator firewall"
FW_IN["Inbound Interceptors<br/>Injection Scanner, PII Masker"]
FW_ADAPT["Adapter Pipeline<br/>Claude / OpenAI / Ollama"]
FW_OUT["Outbound Interceptors<br/>Schema Enforcer, Hallucination Scraper"]
FW_IN --> FW_ADAPT --> FW_OUT
end
subgraph "@franken/orchestrator skills"
SK_REG["Skill Registry<br/>ISkillRegistry"]
end
subgraph "@franken/brain"
MEM_W["Working Memory"]
MEM_E["Episodic Memory<br/>SQLite"]
MEM_S["Semantic Memory<br/>ChromaDB"]
MEM_O["Memory Orchestrator"]
MEM_O --> MEM_W
MEM_O --> MEM_E
MEM_O --> MEM_S
end
subgraph "@franken/planner"
PL_DAG["DAG Builder<br/>Linear / Parallel / Recursive"]
PL_COT["CoT Gate<br/>RationaleBlock"]
end
subgraph "@franken/observer"
OB_TRACE["TraceContext + Spans"]
OB_COST["TokenCounter + CostCalc"]
OB_CB["Circuit Breaker"]
OB_EXPORT["Export Adapters<br/>OTEL / SQLite / Langfuse<br/>Prometheus / Tempo"]
OB_TRACE --> OB_EXPORT
OB_COST --> OB_CB
end
subgraph "@franken/critique"
CR_DET["Deterministic Evaluators<br/>Safety, GhostDep, LogicLoop, ADR"]
CR_HEUR["Heuristic Evaluators<br/>Factuality, Conciseness, Complexity"]
CR_LOOP["Critique Loop"]
CR_DET --> CR_LOOP
CR_HEUR --> CR_LOOP
end
subgraph "@franken/governor"
GOV_TRIG["Trigger Evaluators<br/>Budget / Skill / Confidence / Ambiguity"]
GOV_GW["Approval Gateway<br/>CLI / Slack channels"]
GOV_SEC["HMAC-SHA256 Signing"]
GOV_TRIG --> GOV_GW
GOV_SEC --> GOV_GW
end
subgraph "@franken/orchestrator heartbeat"
HB_DET["Deterministic Check"]
HB_REFL["Reflection Engine"]
HB_DISP["Action Dispatcher"]
HB_DET --> HB_REFL --> HB_DISP
end
subgraph "@franken/mcp-suite registry"
MCP_REG["McpRegistry<br/>Tool routing"]
MCP_CLI["McpClient<br/>JSON-RPC 2.0"]
MCP_REG --> MCP_CLI
end
MCP_SERVERS[(MCP Servers)]
LLM[(LLM Providers<br/>Claude / OpenAI / Ollama)]
subgraph "Orchestrator: Beast Loop"
direction LR
BL1["Phase 1<br/>Ingestion"]
BL2["Phase 2<br/>Planning"]
BL3["Phase 3<br/>Execution"]
BL4["Phase 4<br/>Closure"]
BL1 --> BL2 --> BL3 --> BL4
end
%% Orchestrator wiring
User --> BL1
BL1 -- "sanitize" --> FW_IN
BL1 -- "hydrate" --> MEM_O
BL2 -- "plan" --> PL_DAG
BL2 -- "critique" --> CR_LOOP
BL3 -- "resolve" --> SK_REG
BL3 -- "approve" --> GOV_GW
BL3 -- "callTool" --> MCP_REG
BL4 -- "trace" --> OB_TRACE
BL4 -- "pulse" --> HB_DET
BL4 -- "result" --> User
%% Cross-module connections
FW_ADAPT <--> LLM
FW_OUT -- "sanitized intent" --> PL_DAG
FW_OUT -- "validate tool calls" --> SK_REG
PL_DAG -- "skill discovery" --> SK_REG
PL_DAG -- "load context" --> MEM_O
PL_COT -- "verify rationale" --> GOV_TRIG
CR_DET -- "safety rules" --> FW_IN
CR_DET -- "search ADRs" --> MEM_S
CR_LOOP -- "escalation" --> GOV_GW
GOV_TRIG -- "budget check" --> OB_CB
HB_REFL -- "traces + lessons" --> MEM_O
HB_DET -- "token spend" --> OB_TRACE
HB_DISP -- "inject tasks" --> PL_DAG
MCP_CLI -- "stdio" --> MCP_SERVERS
MCP_REG -- "tool defs" --> SK_REG
classDef firewall fill:#ff6b6b,stroke:#c0392b,color:#fff
classDef skills fill:#54a0ff,stroke:#2e86de,color:#fff
classDef brain fill:#5f27cd,stroke:#341f97,color:#fff
classDef planner fill:#ff9f43,stroke:#ee5a24,color:#fff
classDef observer fill:#10ac84,stroke:#0a3d62,color:#fff
classDef critique fill:#f368e0,stroke:#c44569,color:#fff
classDef governor fill:#feca57,stroke:#f6b93b,color:#333
classDef heartbeat fill:#48dbfb,stroke:#0abde3,color:#333
classDef orchestrator fill:#2d3436,stroke:#636e72,color:#fff
classDef mcp fill:#a29bfe,stroke:#6c5ce7,color:#fff
classDef external fill:#dfe6e9,stroke:#636e72,color:#333
class FW_IN,FW_ADAPT,FW_OUT firewall
class SK_REG skills
class MEM_W,MEM_E,MEM_S,MEM_O brain
class PL_DAG,PL_COT planner
class OB_TRACE,OB_COST,OB_CB,OB_EXPORT observer
class CR_DET,CR_HEUR,CR_LOOP critique
class GOV_TRIG,GOV_GW,GOV_SEC governor
class HB_DET,HB_REFL,HB_DISP heartbeat
class BL1,BL2,BL3,BL4 orchestrator
class MCP_REG,MCP_CLI mcp
class User,LLM,MCP_SERVERS external
| Package | Current role |
|---|---|
@franken/brain |
SQLite-backed working memory, episodic event recall, recovery checkpoints, serialization/hydration. |
@franken/planner |
Intent-to-DAG planning primitives, linear/parallel/recursive strategies, HITL plan export, recovery task insertion. |
@franken/observer |
Trace/span lifecycle, token and cost tracking, circuit breaker, loop detection, export adapters, local trace viewing. |
@franken/critique |
Deterministic/heuristic critique pipeline and correction-request loop; it evaluates and returns feedback for callers to apply. |
@franken/governor |
Trigger evaluation, approval gateway/channels, audit recording, HMAC/session-token helpers for HITL decisions. |
@franken/types |
Shared TypeScript types plus runtime Zod schemas. |
@franken/orchestrator |
Beast Loop, CLI, issue runner, provider registry, middleware, chat/network/comms/security/skills/dashboard/analytics HTTP routes. |
@franken/mcp-suite |
fbeast CLI, MCP servers, hooks, proxy server, shared .fbeast/beast.db, Beast-mode activation shim; see the MCP suite README for skill health endpoint usage. |
@franken/web |
React dashboard for chat, tracked Beast agents, network controls, analytics/cost/safety views. |
@franken/live-bench |
Live CLI benchmark tooling. |
Earlier standalone package surfaces have been consolidated into @franken/orchestrator and @franken/mcp-suite. Treat the current ten-package inventory above as authoritative for available workspace packages.
- Determinism over probabilism. Regex-based injection scanning, schema validation, HMAC verification — these do not hallucinate.
- LLM-agnostic. Provider extension is split by surface: CLI execution/chat providers implement
ICliProviderin@franken/orchestrator, while API-backed clients live in the provider registry and config loading paths. - Immutable safety constraints. Guardrails live in the firewall pipeline, not in the LLM prompt. They cannot be compressed or forgotten.
- Human-in-the-loop as a first-class primitive. High-stakes actions require cryptographically signed human approval.
- Full auditability. Every decision is traced, costed, and exportable.
The shipped Hono HTTP surface is integrated in @franken/orchestrator's chat server (packages/franken-orchestrator/src/http/chat-app.ts and chat-server.ts). The frankenbeast chat-server runtime always mounts chat (with WebSocket chat on /v1/chat/ws), network, and analytics routes; tracked Beast agents/SSE (/v1/beasts/*) routes mount only when an operator token resolves (loopback dev mode run without a token omits them), and skills/dashboard routes activate when a provider registry is configured. When comms channels are enabled, the CLI resolves comms secrets, passes commsConfig to startChatServer(), and auto-wires a ChatRuntimeCommsAdapter, which mounts /comms/health, /v1/comms/inbound, /v1/comms/action, and enabled /webhooks/* routes on the chat server. Security routes (/api/security) mount when securityConfig is supplied. The old standalone Firewall/Critique/Governor service table is historical rather than the current local runtime shape.
- Node.js
>=22.13.0 <23 || >=24.0.0 <26(the local default is pinned in .nvmrc; npm enforces this withengine-strict=true, and CI exercises the same pinned baseline) - npm 11.5.1 via the root
packageManagerpin
- ChromaDB — required for semantic memory (MOD-03). Not needed for unit/integration tests.
- LLM provider credentials —
ANTHROPIC_API_KEY,OPENAI_API_KEY,GOOGLE_API_KEY, orGEMINI_API_KEYfor API-backed providers.OLLAMA_BASE_URLis documented for legacy/future Ollama-compatible builds, but it is not consumed by the current provider schema or Beast activation presets; the conventional local Ollama endpoint ishttp://localhost:11434. - Docker — for running the local dev stack (ChromaDB, Grafana, Tempo).
Beast runtime code has two related project-root decisions:
- Service root:
createBeastServices()resolvespaths.root ?? process.env.FBEAST_ROOT ?? process.cwd(). This root controls Beast service construction, host-processcwdcontainment, containerworkspaceHostPathmounts, worktree isolation, and run-config snapshots under.fbeast/.build/run-configs. - Per-run child working directory: built-in Beast definitions resolve
config.projectRoot ?? process.env.FBEAST_ROOT ?? process.cwd()for the child processcwdwhen the run config omitsprojectRoot.
For CLI entrypoints such as frankenbeast chat-server, frankenbeast network, and frankenbeast beasts-daemon, prefer passing the explicit project root (--base-dir /absolute/path/to/project) because the CLI parses --base-dir with a process.cwd() default before constructing services. Use FBEAST_ROOT=/absolute/path/to/project only for callers that construct Beast services or dispatch built-in Beast runs without an explicit paths.root/config.projectRoot, and keep it aligned with --base-dir when both are present so the service root and child cwd stay inside the same checkout. Historical ADRs and plan documents may mention FBEAST_ROOT, but this section is the operator-facing supported configuration reference.
For a fresh checkout, follow the same supported first-run path as ONBOARDING.md and docs/guides/quickstart.md: use bootstrap so Node.js, npm/Corepack, .env defaults, dependency installation, and optional Docker-service checks stay in sync.
# Clone the repository
git clone <repo-url> frankenbeast
cd frankenbeast
# Run the canonical local setup path without optional Docker services
npm run bootstrap -- --no-docker
# Optional: scaffold a standalone quick-start example into ../my-frankenbeast-app
npm run create:project -- quick-start ../my-frankenbeast-app
# Build all modules
npm run build
# Run root-level integration tests
npm test
# Run root-level Vitest tests only
npm run test:rootFor CI-style validation without mutating files or installing dependencies, run ./scripts/bootstrap.sh --dry-run. If you intentionally need a manual dependency install instead of bootstrap, run it from the repository root with the Corepack-activated npm version from packageManager, copy or merge .env.example into .env, and note that you are skipping bootstrap's environment validation and optional Docker-service prompts.
Browse the standalone examples for copyable CLI planning, MCP registration, and minimal orchestrator configuration projects. Each example has its own locked dependencies and can be scaffolded with npm run create:project -- <example-name> <target-directory>.
The root Vitest suite also checks local Markdown links in README/docs/package READMEs. Local link targets are treated as untrusted input: keep them simple repository-relative paths and do not add shell metacharacters such as backticks, $, ;, &, |, <, or >. External http(s) links and same-page anchors are ignored by that local filesystem check.
See ONBOARDING.md for the complete first-time setup checklist, including prerequisites, bootstrap, UI startup, troubleshooting, and secret backends. See docs/guides/quickstart.md for the shorter setup guide including Docker services.
Use this path when you installed @franken/mcp-suite and ran fbeast mcp init, and want a browser view of the same project telemetry. MCP servers, hooks, Beast mode, and the dashboard share the .fbeast/beast.db under the project root you point the backend at.
From the project where you initialized MCP:
# Install the suite persistently so `fbeast` and the `fbeast-*` MCP server
# binaries stay on PATH. A one-shot `npx` won't work here: `mcp init` registers
# servers as bare `fbeast-memory`/`fbeast-proxy` commands the AI client spawns
# later, so those binaries must remain installed after setup.
npm install -g @franken/mcp-suite
# One-time MCP setup. Add --hooks if you want tool-call governance and audit logs.
fbeast mcp init --hooksFrom this Frankenbeast repo, start the dashboard backend against that same project root:
npm --workspace @franken/orchestrator run chat-server -- --base-dir /path/to/your-projectIf you initialized MCP in this repo, omit --base-dir.
In a second terminal, start the web UI:
npm --workspace @franken/web run dev:chatOpen the Vite URL, usually http://127.0.0.1:5173/. By default the dashboard talks to the chat server through TLS-preferred API defaults and reads the same observer, governor, cost, and Beast data written by MCP mode in that project.
If you run the backend on a different port, keep browser requests same-origin and point the Vite dev proxy at that backend. Leave VITE_API_URL unset for local Vite development; the current dashboard ignores that legacy value, so it will not change the backend port. Use VITE_API_PROXY_TARGET instead so /v1 and /api continue flowing through the dev proxy. If Beast controls use a separate backend, set VITE_BEAST_API_PROXY_TARGET for that target too.
npm --workspace @franken/orchestrator run chat-server -- --base-dir /path/to/your-project --port 4242
VITE_API_PROXY_TARGET=http://127.0.0.1:4242 npm --workspace @franken/web run devFor Beast controls, set the operator token once in the repo root .env so the backend and Vite dev proxy can read it server-side:
FRANKENBEAST_BEAST_OPERATOR_TOKEN=<token-from-frankenbeast-init>See Run the Dashboard Chat for provider overrides and troubleshooting.
The CLI is available as frankenbeast, franken, or frkn — all are identical.
# Start from scratch — interview, design, plan, execute
frankenbeast
# Start from an existing design document — plan, then execute
frankenbeast plan --design-doc docs/my-feature-design.md
frankenbeast run
# Start from existing chunk files
frankenbeast --plan-dir ./my-chunks/Cold frankenbeast run clears checkpoint/chunk-session state before execution. Use frankenbeast run --resume only when a previous run was interrupted and saved checkpoint state exists; the run resumes from that checkpoint/chunk-session data. If the checkpoint is missing, the resume command fails fast with a missing-checkpoint error instead of silently starting a cold run.
# Interview only — generates .fbeast/plans/design.md
frankenbeast interview
# Plan only — decomposes design doc into chunk files
frankenbeast plan --design-doc design.md
# Run only — executes chunks from .fbeast/plans/
frankenbeast run
# Interactive chat — two-tier REPL (conversational + execution)
frankenbeast chat
# Chat server — HTTP + WebSocket for franken-web dashboard
frankenbeast chat-server --port 3737
# GitHub issues — fetch, triage, and fix issues autonomously
frankenbeast issues --label bug --repo owner/repoPass one label with --label bug, or multiple labels as a single comma-separated value like --label critical,high.
--base-dir <path> Project root (default: cwd)
--base-branch <name> Git base branch (default: main)
--budget <usd> Budget limit in USD (default: 10)
--provider <name> claude | codex | gemini | aider (default: claude)
--providers <list> Comma-separated fallback chain (e.g. claude,gemini,aider)
--design-doc <path> Path to design document
--plan-dir <path> Path to chunk files directory
--config <path> Path to config file (JSON)
--no-pr Skip PR creation after execution
--verbose Debug logs + trace viewer on :4040
--reset Clear checkpoint and traces
--resume Resume from an existing checkpoint for the selected plan
--cleanup Remove all build artifacts from .fbeast/.build/
--help Show help
Issues-specific flags:
--label <labels> Comma-separated labels (e.g. critical,high)
--search <query> GitHub search syntax
--milestone <name> Filter by milestone
--assignee <user> Filter by assignee
--limit <n> Max issues to fetch (default: 1000)
--repo <owner/repo> Target repository (auto-inferred if omitted)
--target-upstream Use the checkout's upstream remote as the target repo
--dry-run Preview triage without executing
Execution controls such as --budget, --provider, --providers, and --no-pr are global options that also affect frankenbeast issues runs; see Fix GitHub Issues for the complete issue workflow flag table.
Chat server flags:
--host <addr> Server bind address (default: localhost)
--port <n> Server port (default: 3737)
--allow-origin <url> CORS origin for dashboard
frankenbeast run loads orchestrator config from defaults, an optional JSON config file (--config <path> or the project-local .fbeast/config.json), FRANKEN_* environment variables, and CLI flags. When the same field is set in more than one place, precedence is: CLI flags > FRANKEN_* env vars > config file > built-in defaults.
| Environment variable | Config field | Type and accepted values | Default / validation |
|---|---|---|---|
FRANKEN_MAX_TOTAL_TOKENS |
maxTotalTokens |
integer token budget | default 100000; must be at least 10000 |
FRANKEN_MAX_DURATION_MS |
maxDurationMs |
integer milliseconds | default 300000; must be at least 1000 and at least maxCritiqueIterations * 10000 |
FRANKEN_MAX_CRITIQUE_ITERATIONS |
maxCritiqueIterations |
integer critique passes | default 3; valid range 1 through 10 |
FRANKEN_ENABLE_HEARTBEAT |
enableHeartbeat |
boolean string; accepted true values: true, 1, yes, on; false values: false, 0, no, off |
default false |
FRANKEN_ENABLE_TRACING |
enableTracing |
boolean string; accepted true values: true, 1, yes, on; false values: false, 0, no, off |
default false; --verbose also enables tracing and wins over env/config |
FRANKEN_ENABLE_REFLECTION |
enableReflection |
boolean string; accepted true values: true, 1, yes, on; false values: false, 0, no, off |
default false |
FRANKEN_MIN_CRITIQUE_SCORE |
minCritiqueScore |
numeric score | default 0.7; must be >= 0 and < 1 |
Numeric env values are parsed as numbers and then validated with the same schema as JSON config files. Unset numeric variables leave the lower-priority source in effect. Boolean env overrides apply whenever the variable is present. Boolean values are parsed strictly: use true, 1, yes, or on to enable a field and false, 0, no, or off to disable it. Other values are rejected unless a higher-priority CLI flag, such as --verbose, shadows that field.
If stateDir is set to a path inside a sibling Hermes profile such as .hermes/profiles/<profile>/..., Frankenbeast fails closed by default when <profile> does not match the active HERMES_PROFILE (or default when unset). Set allowCrossProfileStateAccess: true in an operator-owned config file outside the checked-out repository only for deliberate migrations/imports that must read or write another profile's state; repository-local .fbeast/config.json cannot self-approve this opt-in.
FRANKENBEAST_NETWORK_MANAGED=1 is an internal child-process marker owned by frankenbeast network. The supervisor sets it for managed services such as chat-server; operators normally should not export it for standalone local debugging. Managed children suppress the normal CLI startup banner, and managed chat-server fails closed without an operator token even on loopback. If a standalone chat-server run unexpectedly asks for an operator token on 127.0.0.1 or localhost, unset FRANKENBEAST_NETWORK_MANAGED; if you intentionally exercise managed semantics, provide FRANKENBEAST_BEAST_OPERATOR_TOKEN or the configured secret-store token reference.
Running frankenbeast in any project creates:
your-project/
.fbeast/
config.json # optional project config
plans/
design.md # generated by interview
01_chunk.md, 02_... # generated from design
.build/
<plan-name>.checkpoint # plan-scoped execution state
<plan-name>-<datetime>-build.log # plan-scoped session log (crash-safe, written incrementally)
build-traces.db # observer traces
# All package tests through Turborepo
npm test
# Per-package tests via Turborepo
npx turbo run test --filter=franken-brain
# Orchestrator E2E tests (sets E2E=true and delegates to @franken/orchestrator)
npm run test:e2eThe E2E suites are opt-in and remain outside the regular npm test path. Before
running them from a clean checkout, run the dependency-aware root build with
npm run build, install a real claude CLI on PATH, and provide a valid
ANTHROPIC_API_KEY in the environment. The root test:e2e script delegates to
the workspace script, which sets E2E=true for the gated suites and forwards
Vitest arguments after --.
For first-time setup, use the onboarding checklist and bootstrap script:
# Validate prerequisites and create .env without starting optional services.
npm run bootstrap -- --no-docker
# CI-style prerequisite validation without mutating files or installing packages.
./scripts/bootstrap.sh --dry-run
# Generate a unique Grafana password before starting the full compose stack;
# Grafana requires GRAFANA_USER=admin with a non-default password.
$EDITOR .env # uncomment GRAFANA_USER=admin, set a unique GRAFANA_PASSWORD, and adjust CHROMA_URL if needed
# .env.example defaults CHROMA_URL to http://localhost:8000 for local compose.
# Override it only when ChromaDB runs at a different local port/host or a remote
# TLS-terminated endpoint, then keep the same endpoint in .env or export it
# before seed/verify.
# In CI, point CHROMA_URL at the Chroma service container hostname instead.
# export CHROMA_URL=http://chroma:8000
# Start supporting services (ChromaDB, Grafana, Tempo) through bootstrap. The
# compose file pins image versions and mounts ./tempo.yaml so local tracing
# starts deterministically.
npm run bootstrap -- --services
# Local Tempo exposes OTLP/HTTP writes on http://localhost:4318 for TempoAdapter
# and readiness on http://localhost:3200/ready for verify-setup. The root
# .env.example intentionally does not define a TEMPO_ENDPOINT override; pass
# custom Tempo endpoints through TempoAdapter options instead.
# Optional Grafana Cloud Tempo export uses TempoAdapter basic auth. Leave these
# unset for the local docker-compose Tempo service.
# export GRAFANA_INSTANCE_ID=123456
# export GRAFANA_API_KEY=glc_...
# Seed ChromaDB with initial collections. This uses CHROMA_URL from .env or
# the environment.
npm run local:seed
# Verify everything is running. This probes the same CHROMA_URL endpoint,
# plus fixed compose defaults for Grafana (http://localhost:3000/api/health)
# and Tempo readiness (http://localhost:3200/ready).
npm run local:verify-setupCHROMA_URL points Frankenbeast's local setup scripts at the ChromaDB HTTP API.
Both npm run local:seed (scripts/seed.ts) and npm run local:verify-setup
(scripts/verify-setup.mjs) read it from the environment or the copied .env
file, falling back to http://localhost:8000 when it is unset. The default
matches the root docker-compose.yml, which publishes ChromaDB on port 8000
for local development.
Use the default for the standard local compose stack:
cp .env.example .env
$EDITOR .env # uncomment GRAFANA_USER=admin and set a unique GRAFANA_PASSWORD
npm run bootstrap -- --services
npm run local:seed
npm run local:verify-setupOverride it when ChromaDB is reachable somewhere else, and set the same value
in .env or export it before seed and verification:
# Alternate local port or host
export CHROMA_URL=http://127.0.0.1:18000
npm run local:seed
npm run local:verify-setup
# CI service container named "chroma"
export CHROMA_URL=http://chroma:8000
npm run local:verify-setup
# Remote/TLS-terminated ChromaDB endpoint
export CHROMA_URL=https://chromadb.example.com
npm run local:seedFrankenbeast stores secrets outside the config file. The config references secrets by logical key — a short string like frankenbeast/operator-token — and resolves them at boot via the configured secureBackend.
frankenbeast initruns an interactive wizard that generates the operator token and persists it to your chosen backend.- The config file stores logical keys (not the secret values) under
network.operatorTokenRef,comms.orchestratorTokenRef, and channel*Reffields. - At startup,
SecretResolverreads those keys fromISecretStoreand injects the resolved values into the service dependencies.
| Backend | Key | Best for |
|---|---|---|
| Local encrypted file | local-encrypted |
Default backend; zero-install local dev, CI/CD, offline, or minimal environments |
| OS keychain (Linux Secret Service) | os-keychain |
Explicit opt-in for Linux single-machine local dev when you want OS-managed storage and no passphrase prompt |
| 1Password | 1password |
Teams using 1Password vaults |
| Bitwarden | bitwarden |
Teams using Bitwarden |
Copy the relevant settings from frankenbeast.example.json into .fbeast/config.json, then set network.secureBackend there. If you omit network.secureBackend, the config schema and init flow use local-encrypted; os-keychain is never selected automatically. frankenbeast init reads and updates .fbeast/config.json.
Local encrypted file (the default):
frankenbeast init # interactive — prompts for a passphrase, generates and stores the tokenWhen network.secureBackend is unset, init defaults to local-encrypted: the passphrase encrypts the local vault at .fbeast/secrets.enc, with key-derivation metadata in .fbeast/secrets.meta.json. For CI/headless runtime flows, mount or persist .fbeast/config.json (which selects the backend and stores logical refs), .fbeast/secrets.enc, and .fbeast/secrets.meta.json — or persist the whole .fbeast secret-store state — then set FRANKENBEAST_PASSPHRASE in the environment so runtime commands can decrypt the vault without prompting; this is used by commands like frankenbeast run, not as a replacement for interactive setup.
OS keychain:
{ "network": { "secureBackend": "os-keychain" } }Set this in .fbeast/config.json before running frankenbeast init when you want local secrets in Linux Secret Service instead of the default encrypted file. The token is generated and stored through secret-tool stdin (no passphrase prompt), so secret values never enter process arguments. macOS and Windows writes fail closed because their built-in noninteractive CLIs require secret values in process arguments; use local-encrypted, 1password, or bitwarden on those platforms. Use os-keychain only when you explicitly select it; it is convenient for Linux single-machine local development, but it is not the default backend.
1Password / Bitwarden:
{ "network": { "secureBackend": "1password" } }{ "network": { "secureBackend": "bitwarden" } }Set one of those values in .fbeast/config.json, then run frankenbeast init. You can also use the current CLI shortcut frankenbeast init --backend 1password or frankenbeast init --backend bitwarden; it applies the same network.secureBackend choice before the wizard writes .fbeast/config.json.
For 1Password, install 1Password CLI 2.23.0 or newer, create or use a vault literally named frankenbeast, and authenticate op; init-created items use titles like frankenbeast/network.operatorTokenRef. For Bitwarden, install the Bitwarden CLI, run bw login/bw unlock, and export BW_SESSION first; init-created secure notes use the same frankenbeast/ title prefix. Both backends send credential payloads through stdin instead of command-line arguments and fail closed when a stdin-capable runner is unavailable.
frankenbeast init generates a strong random operator token and stores it in the backend. The franken-web dashboard must not receive that long-lived token in browser-readable VITE_* env. To wire local dashboard development:
- Run
frankenbeast init— it prints the token once after generation. - Keep the token server-side: use the configured secret store or set
FRANKENBEAST_BEAST_OPERATOR_TOKEN=<token>in a local, uncommitted env file. - Run the dashboard through same-origin backend routes. In Vite dev mode, use
VITE_API_PROXY_TARGET/VITE_BEAST_API_PROXY_TARGETso the Vite server attaches the token to proxy requests without exposing it to the browser bundle.
frankenbeast init configures the orchestrator/backend control plane. It is separate from fbeast mcp init, which only registers MCP servers and optional hooks for an AI client in the current project. Run frankenbeast init before enabling Beast controls in the dashboard so the backend has module settings, a secret backend, and network.operatorTokenRef ready for the Vite proxy or production BFF.
Common forms:
frankenbeast init # interactive setup wizard
frankenbeast init --verify # validate .fbeast/config.json and .fbeast/init-state.json
frankenbeast init --repair # re-run repair wizard paths; review token prompts carefully
frankenbeast init --non-interactive # safe only after config and init state are completeChoose the secret backend before the first init run by writing network.secureBackend in .fbeast/config.json, for example { "network": { "secureBackend": "os-keychain" } }. Keeping the config choice ahead of init ensures the generated operator token is written to the same backend that later runtime and dashboard processes will read.
During the interactive wizard, expect prompts for the Chat, Dashboard, and Comms modules; the default provider; the secure/insecure network mode; optional Slack, Discord, Telegram, or WhatsApp credentials when Comms is enabled; and an operator token prompt that can be left blank to auto-generate a token. Sensitive values are stored in the selected secret backend and referenced from .fbeast/config.json; the raw operator token is printed once when auto-generated so you can copy it into a local server-side .env if you are not resolving it through the configured backend.
For the default local-encrypted backend, interactive init needs a passphrase to create or update the encrypted vault. In CI or other headless runtime paths, export only that variable before commands that actually resolve stored secrets, such as a run or dashboard backend process:
export FRANKENBEAST_PASSPHRASE=<passphrase>
frankenbeast run --config .fbeast/config.jsonUse frankenbeast init --non-interactive only when .fbeast/config.json, .fbeast/init-state.json, and the selected backend entries already exist. It checks the config/init-state files and selected ref fields, but it does not prove every completed step, create a fresh vault, answer wizard prompts, decrypt the secret vault, or resolve secret refs. Likewise, frankenbeast init --verify validates init config and state files but does not resolve secret refs, so keep a runtime smoke check in CI when you need to prove operator-token resolution works. During --repair, review the operator-token prompt before accepting defaults; leaving it blank can generate a replacement token and rotate the dashboard/control-plane credential.
export FRANKENBEAST_PASSPHRASE=<passphrase>
frankenbeast runWith local-encrypted backend and FRANKENBEAST_PASSPHRASE set, the orchestrator decrypts the vault from .fbeast/config.json without prompting. If you run with --config <path>, keep that file in sync with the backend and token refs written by frankenbeast init.
Required HITL approvals fail closed when a run has no interactive TTY. In trusted CI/headless automation that intentionally allows required HITL-gated skills, set FRANKENBEAST_ALLOW_NONINTERACTIVE_APPROVAL=1; otherwise rerun in an interactive TTY and approve the prompt.
The ADRs are historical decision records: they capture original design rationale, not current implementation guidance. For current behavior, cross-check the relevant package READMEs, architecture docs, and source.
- ADR-018 — secret store design and backend selection rationale
- ADR-017 — network operator control plane and token auth
- Worker push rollback runbook — dry-run planning and approval runner routing for failed or bad worker branch publishes
- Corrupted worktrees and queues runbook — incident diagnosis, backup-before-repair, queue repair, worker defer/replace, and approval runner routing for automation-state corruption
| Variable | Module | Required | Description |
|---|---|---|---|
ANTHROPIC_API_KEY |
MOD-01 | Runtime only | Claude adapter API key |
OPENAI_API_KEY |
MOD-01 | Runtime only | OpenAI adapter API key |
GOOGLE_API_KEY |
MOD-01 | Runtime only | Gemini adapter API key (Google AI Studio name) |
GEMINI_API_KEY |
MOD-01 | Runtime only | Gemini adapter API key (alternative name) |
OLLAMA_BASE_URL |
Provider registry | Not consumed by the current provider schema; legacy/future Ollama-compatible builds only | Ollama daemon base URL, usually http://localhost:11434; set a different HTTP(S) endpoint for remote or non-default daemons only in builds that actually support an Ollama provider. It is intentionally absent from .env.example because the default local setup, current provider schema, and current fbeast mcp beast presets do not consume it. |
CHROMA_URL |
MOD-03 | If using semantic memory | ChromaDB base URL used by scripts/seed.ts and scripts/verify-setup.mjs (default: http://localhost:8000) |
SLACK_WEBHOOK_URL |
MOD-07 | If using Slack approvals | Slack webhook for HITL notifications |
FRANKENBEAST_MODULE_MEMORY |
MOD-03 | Optional | Memory module config fallback and Beast child-env toggle. Only the literal value false records it as disabled when the memory config key is unset; current local CLI wiring still constructs the real memory adapter. |
FRANKENBEAST_MODULE_PLANNER |
MOD-04 | Optional | Planner module config fallback and Beast child-env toggle. Only literal false records it as disabled when the planner config key is unset; current local CLI wiring still uses the graph-builder path. |
FRANKENBEAST_MODULE_CRITIQUE |
MOD-06 | Optional | Active critique safety-module toggle. Only literal false disables critique when the critique config key is unset; otherwise it is enabled by default. |
FRANKENBEAST_MODULE_GOVERNOR |
MOD-07 | Optional | Active governor safety-module toggle. Only literal false disables governor when the governor config key is unset; otherwise it is enabled by default. |
FRANKENBEAST_ALLOW_MISSING_SAFETY_MODULES |
MOD-06/MOD-07 | Unsafe override | Set to literal 1 to allow enabled critique/governor packages that are not installed to fall back to all-pass stubs. Leave unset unless intentionally accepting degraded safety in local/debug runs. |
FRANKENBEAST_ALLOW_NONINTERACTIVE_APPROVAL |
MOD-07 | Trusted CI/headless only | Set to literal 1 to allow required HITL approvals in non-interactive runs. Without it, required HITL gates fail closed outside an interactive TTY. |
See .env.example for the full local-development list. Keep .env.example and this table aligned when adding operator-facing environment controls.
Runtime modules use dependency injection first: explicit constructor, CLI, or run-config inputs win over environment variables. For the local CLI path, selected operator controls then fall back to environment variables, and defaults apply last. Module enablement precedence is:
- Explicit value for that module key (
modules.memory,modules.planner,modules.critique, ormodules.governor) in run config or CLI dependency options. - The matching environment fallback (
FRANKENBEAST_MODULE_MEMORY,FRANKENBEAST_MODULE_PLANNER,FRANKENBEAST_MODULE_CRITIQUE, orFRANKENBEAST_MODULE_GOVERNOR) when that specific module key is unset. - Enabled-by-default behavior when neither the module key nor a literal
falseenv toggle is provided.
Safety-critical critique/governor imports fail closed when the module is enabled but its package is missing. FRANKENBEAST_ALLOW_MISSING_SAFETY_MODULES=1 is the explicit unsafe escape hatch that keeps the run going with passthrough stubs; prefer installing the package or setting an explicit module config instead.
// Orchestrator — via config file or CLI flags
frankenbeast plan --design-doc docs/my-feature-design.md --config frankenbeast.config.json
// Orchestrator chat/dashboard HTTP server
npm --workspace @franken/orchestrator run chat-server -- --port 3737The orchestrator manages execution through four phases with circuit breakers at each stage.
Modules: MOD-01 (Firewall) + MOD-03 (Memory)
Raw user input is scrubbed for PII and scanned for injection attacks by the firewall. Relevant ADRs and episodic traces are loaded from memory to give the agent contextual wisdom.
Modules: MOD-04 (Planner) + MOD-06 (Critique)
The Planner generates a Task DAG. The Critique module audits it with 8 evaluators (deterministic evaluators run first, then heuristic). If critique fails, the orchestrator forces a re-plan (max 3 iterations). After 3 failures, it escalates to a human via MOD-07.
Critique lessons recorded after a recovered failure include a rollbackWorkflow object for coordination/liveness consumers. Use it when a lesson is later found to be incorrect, stale, over-broad, or harmful:
- Quarantine the target lesson so it stops being promoted into new worker handoffs.
- Attach the rollback reason, evidence URLs, and verifier command to the lesson audit trail.
- Either record a replacement lesson with fresh traceability evidence or retire the original lesson with no replacement.
- Run the verifier command and include the result in the coordination handoff before removing the rollback block.
Rollback requests must provide a stable lesson id, a concrete rollback reason, evidence such as a review comment/regression/operator report, and a verification command. If any of that evidence is missing, coordination tooling should keep the lesson blocked instead of silently retiring or replacing it.
Modules: MOD-02 (Skills) + MOD-07 (Governor)
Tasks execute in topological order from the DAG. High-stakes tasks pause for human approval via the Governor's trigger evaluators (budget, skill, confidence, ambiguity). Every task result is recorded to memory and traced.
Modules: MOD-05 (Observer) + MOD-08 (Heartbeat)
The trace is closed and token spend summarised. In the current local CLI path, @franken/orchestrator/src/cli/create-beast-deps.ts builds a real ReflectionHeartbeatAdapter: it wires the provider registry through the middleware chain and runs the reflection evaluator when dependency config keeps reflection enabled. The lower-level adapter can fall back to a static summary when constructed without a reflection function, but the legacy CLI bridge currently passes reflection: true; treat heartbeat-driven self-improvement beyond that per-run reflection adapter as target architecture rather than a fully verified end-to-end local learning loop.
| Trigger | Action |
|---|---|
| Injection detected (MOD-01) | Immediate halt |
| Budget exceeded (MOD-05) | Escalate to HITL |
| Critique fails 3x (MOD-06) | Escalate to human |
- Context serialization — BeastContext snapshots saved to disk for crash recovery
- Graceful shutdown — SIGTERM/SIGINT handlers save state before exit
- Module health checks — all 8 modules probed on startup
Frankenbeast is LLM-agnostic through the orchestrator provider registry. CLI providers live under packages/franken-orchestrator/src/skills/providers, API providers live under packages/franken-orchestrator/src/providers, and configuration schemas live under packages/franken-orchestrator/src/config. See docs/guides/add-llm-provider.md for the current extension points.
The currently shipped integration path is to call the orchestrator runtime, use @franken/mcp-suite tools/hooks, or implement BeastLoop dependencies around your agent components. The old standalone firewall HTTP proxy guide is historical; see docs/guides/wrap-external-agent.md for current options and caveats.
Use the root scaffolding script to copy an example into a fresh standalone folder, create .env from the example's .env.example, and run npm ci in the new project:
npm run create:project -- quick-start ../my-frankenbeast-app
cd ../my-frankenbeast-app
npm startPass another example name when more directories are added under examples/. The target directory is optional and defaults to ./<example-name>-project from your current working directory.
Package READMEs, docs/guides/quickstart.md, docs/guides/run-cli-beast.md, docs/guides/run-dashboard-chat.md, and implementation-adjacent tests remain useful runnable examples for the full monorepo. Older references to provider quickstarts or an OpenClaw/firewall-proxy example are pre-consolidation documentation.
Frankenbeast includes an observer-powered autonomous build runner (MartinLoop) integrated into the orchestrator — iterative AI loops that process chunk files with deterministic completion detection.
Features:
- Observer tracing — TraceContext spans per iteration, TokenCounter + CostCalculator per chunk
- Budget enforcement — CircuitBreaker stops execution when spend exceeds limit
- Loop detection — LoopDetector identifies stuck sessions
- Checkpoint/resume — crash recovery via FileCheckpointStore
- Chunk sessions — canonical execution state with pre-compaction snapshots and context-window-aware compaction at >= 85% usage
- Rate limit handling — automatic provider fallback chain (e.g. Claude → Gemini → Aider)
- Git isolation — per-chunk branches via GitBranchIsolator, auto-commit, merge back to base
- 4 pluggable providers — Claude, Codex, Gemini, Aider via ProviderRegistry
See docs/beast-loop-explained.md for the full iteration mechanics.
The frankenbeast chat REPL provides a two-tier interactive experience:
- Tier 1 (Conversational) — cheap model with session continuation, quirky spinner, colored output (cyan prompt, green replies)
- Tier 2 (Execution) —
/run <desc>spawns a full-permissions CLI agent./plan <desc>dispatches to planning. Natural language triggers execution via IntentRouter → EscalationPolicy - Output sanitization — strips raw web search JSON blobs and REMINDER instruction blocks from Claude CLI output
- Session persistence — file-backed session store for conversation history across restarts
The frankenbeast chat-server exposes the same runtime over HTTP + WebSocket for the franken-web dashboard.
External communications are implemented in @franken/orchestrator under packages/franken-orchestrator/src/comms; they are not provided by a separate workspace package. The gateway keeps deterministic session mapping for supported channels:
| Channel | Transport | Security |
|---|---|---|
| Slack | Events API + Interactivity | HMAC-SHA256 signature verification |
| Discord | Gateway events | ED25519 signature verification |
| Telegram | Webhook | Telegram secret_token header validation |
| Cloud API | SHA256 signature verification |
Channels route through the orchestrator comms pipeline. See ADR-016 for the original gateway decision and the orchestrator comms source for current implementation details.
Telegram updates use the fixed https://<public-host>/webhooks/telegram route. Configure a dedicated, randomly generated webhook secret through comms.telegram.webhookSecretTokenRef, then pass the resolved value as Telegram's secret_token when registering the webhook. The secret must be 1–256 characters using only A-Z, a-z, 0-9, _, and -, as required by the Telegram Bot API. Telegram sends that value in X-Telegram-Bot-Api-Secret-Token; Frankenbeast rejects requests whose header is missing or invalid. Do not append the bot token to the webhook URL.
To migrate an existing token-bearing webhook URL:
- Generate a new webhook secret that is independent of the Telegram bot token and store it directly in the configured secret backend under the reference named by
comms.telegram.webhookSecretTokenRef. If the logical reference changes, update.fbeast/config.jsontoo. Do not rely onfrankenbeast init --repairto rotate a complete configuration; it exits without changing secrets when verification already passes. - After storing the secret, re-register the webhook with Telegram using the fixed
/webhooks/telegramURL and the same new value in the Bot APIsecret_tokenparameter. Telegram'ssetWebhookcall replaces the previous webhook URL. - Send a test update and confirm the fixed route accepts the
X-Telegram-Bot-Api-Secret-Tokenheader. A legacy token-bearing path returns404when sent directly to the chat server. The supporteddashboard-webreverse proxy instead rewrites legacy token-bearing paths to/webhooks/telegrambefore forwarding, so verify the fixed upstream route and header validation rather than expecting a proxy-level404. - If the old URL may have appeared in proxy logs, screenshots, or support tools, rotate the bot token with BotFather and update
comms.telegram.botTokenRef; then remove or redact retained copies of the old URL.
Never log the resolved bot token or webhook secret. Treat both secret-store references as server-side configuration.
Delivery-channel sensitivity defaults fail-closed: runtime replies marked with sensitivity: "sensitive" or metadata deliverySensitivity: "sensitive" are withheld from Slack, Discord, Telegram, and WhatsApp unless that channel explicitly sets allowSensitiveDelivery: true. Unknown sensitivity labels are treated as sensitive. Withheld messages send a generic operator guidance notice and route metadata only, never the sensitive payload or interactive actions.
| Phase | Description | Status |
|---|---|---|
| 1 | Individual Module Implementation | Complete |
| 2 | LLM-Agnostic Adapter Layer | Complete (PRs 15-18) |
| 3 | Inter-Module Contracts & Shared Types | Complete (PRs 19-24) |
| 4 | The Orchestrator ("Beast Loop") | Complete (PRs 25-30) |
| 5 | Guardrails as a Service (HTTP) | Complete (PRs 31-35) |
| 6 | End-to-End Testing & Hardening | Complete (PRs 36-39) |
| 7 | CLI & Developer Experience | Complete (PRs 40-42) |
| 8 | CLI Skill Execution (Martin Loop) | Complete |
| 9 | Interactive Chat & Two-Tier Dispatch | Complete |
| 10 | Chat Server (HTTP + WebSocket) | Complete |
| 11 | External Comms (Slack/Discord/Telegram/WhatsApp) | Complete |
| 12 | GitHub Issues Pipeline | Complete |
Run npm test, npm run typecheck, and npm run build for the current baseline. Use the test command decision tree to choose narrower checks for a specific change. The maintained root and workspace scripts are authoritative; avoid relying on stale static test-count claims in older docs.
For historical implementation chronology only, see the archived PR-by-PR progress tracker; it does not define the current testing baseline.
- Web Dashboard — React-based UI (
franken-web) for chat, tracked Beast agents, network control, analytics/cost/safety views, and settings. - Escalation Policy Hardening — Refining intent routing and tier escalation logic for the chat REPL.
All packages live under packages/ in the monorepo:
# Build and test a single package
npx turbo run test --filter=franken-brain
npx turbo run build --filter=franken-brain
# Or work directly in the package
cd packages/franken-brain && npm testAll modules follow the same patterns:
- Vitest as test runner
- Root test entrypoints —
npm testruns the default deterministic package suites,npm run test:rootruns root-only Vitest tests, andnpm run test:integrationruns deterministic workspace integration suites exposed through Turborepo. - Opt-in evals —
npm run test:evalis intentionally separate fromnpm testand runs only workspaces with explicit eval/LLM-judge suites. - Dependency injection — all external deps are constructor-injected
- Mock factories —
vi.fn()stubs for port interfaces - No I/O in unit tests — real SQLite only in integration tests (
:memory:mode) - Zod validation at all system boundaries
frankenbeast/
├── README.md
├── package.json # Root workspace + Turborepo scripts
├── turbo.json # Build orchestration (build, test, typecheck)
├── docker-compose.yml # Local dev stack (ChromaDB, Grafana, Tempo)
├── frankenbeast.config.example.json
├── assets/img/ # Project logos
├── docs/
│ ├── ARCHITECTURE.md # System overview with Mermaid diagrams
│ ├── PROGRESS.md # PR-by-PR implementation tracker
│ ├── CONTRACT_MATRIX.md # Port interface compatibility matrix
│ ├── beast-loop-explained.md # Iteration mechanics deep dive
│ ├── adr/ # Architecture Decision Records (see docs/adr/*.md)
│ ├── guides/ # Quickstart, run/deploy, provider, agent, verification, and issue-workflow guides
│ ├── onboarding/ # Contributor and agent onboarding guides
│ │ └── RAMP_UP.md # Concise agent onboarding doc
│ └── plans/ # Design docs and implementation plans
├── tests/ # Root-level integration tests
├── scripts/ # seed.ts, verify-setup.mjs
├── packages/
│ ├── franken-brain/ # MOD-03: Memory Systems
│ ├── franken-planner/ # MOD-04: Planning & Decomposition
│ ├── franken-observer/ # MOD-05: Observability
│ ├── franken-critique/ # MOD-06: Self-Critique & Reflection
│ ├── franken-governor/ # MOD-07: HITL & Governance
│ ├── franken-types/ # Shared type definitions
│ ├── franken-orchestrator/ # The Beast Loop & CLI (bin: frankenbeast)
│ ├── franken-mcp-suite/ # MCP suite CLI, servers, hooks, proxy
│ ├── live-bench/ # Live CLI benchmark tooling
│ └── franken-web/ # React web dashboard (dev tool)
└── .fbeast/ # Project-scoped runtime state (gitignored)
- Architecture — system overview with Mermaid diagrams
- Beast Loop Explained — the 5 interlocking loops and their mechanics
- Quickstart Guide — get running in 7 steps
- Run the Dashboard Chat — start the WebSocket chat server and dashboard locally
- Run the Network Operator — start Frankenbeast request-serving services through
frankenbeast network - Add an LLM Provider — add CLI execution providers through
ICliProvideror API-backed clients through the provider registry - Wrap an External Agent — MCP tool governance, orchestrator runtime, or BeastLoop dependency integration
- Contract Matrix — all port interfaces documented
- ADRs — architectural decisions and rationale
- Design Plans — design docs and implementation plans
MIT
