Skip to content

djm204/frankenbeast

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2,448 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Frankenbeast

Frankenbeast

Status Latest root release Daily security scan Dependabot

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.

🚀 One-click onboarding

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-docker

The 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-run

Releases

See GitHub Releases for the latest published release and CHANGELOG.md for the complete release history.

Modes

  • MCP mode: Claude Code plugin/tool-provider surface via @franken/mcp-suite
  • Beast mode: standalone orchestrator path with dashboard-first control and CLI parity

Both modes share .fbeast/beast.db.

Why This Exists

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.

Security

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.

Architecture

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
Loading

Beast Loop Sequence

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
Loading

Module Interconnections

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
Loading

Current workspace packages

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.

Core Principles

  • 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 ICliProvider in @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.

HTTP surface

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.

Prerequisites

  • Node.js >=22.13.0 <23 || >=24.0.0 <26 (the local default is pinned in .nvmrc; npm enforces this with engine-strict=true, and CI exercises the same pinned baseline)
  • npm 11.5.1 via the root packageManager pin

Optional

  • ChromaDB — required for semantic memory (MOD-03). Not needed for unit/integration tests.
  • LLM provider credentialsANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY, or GEMINI_API_KEY for API-backed providers. OLLAMA_BASE_URL is 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 is http://localhost:11434.
  • Docker — for running the local dev stack (ChromaDB, Grafana, Tempo).

Beast project-root override

Beast runtime code has two related project-root decisions:

  • Service root: createBeastServices() resolves paths.root ?? process.env.FBEAST_ROOT ?? process.cwd(). This root controls Beast service construction, host-process cwd containment, container workspaceHostPath mounts, 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 process cwd when the run config omits projectRoot.

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.

Quick Start

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:root

For 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.

Run the Dashboard with MCP Mode

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 --hooks

From this Frankenbeast repo, start the dashboard backend against that same project root:

npm --workspace @franken/orchestrator run chat-server -- --base-dir /path/to/your-project

If you initialized MCP in this repo, omit --base-dir.

In a second terminal, start the web UI:

npm --workspace @franken/web run dev:chat

Open 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 dev

For 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.

Usage

The CLI is available as frankenbeast, franken, or frkn — all are identical.

Interactive Session (idea to PR)

# 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.

Subcommands

# 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/repo

Pass one label with --label bug, or multiple labels as a single comma-separated value like --label critical,high.

Options

--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

Runtime config and environment overrides

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.

Operator environment variables

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.

Project Layout

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

Running Tests

# 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:e2e

The 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 --.

Local Dev Environment

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-setup

ChromaDB endpoint (CHROMA_URL)

CHROMA_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-setup

Override 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:seed

Secret Management

Frankenbeast 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.

How it works

  1. frankenbeast init runs an interactive wizard that generates the operator token and persists it to your chosen backend.
  2. The config file stores logical keys (not the secret values) under network.operatorTokenRef, comms.orchestratorTokenRef, and channel *Ref fields.
  3. At startup, SecretResolver reads those keys from ISecretStore and injects the resolved values into the service dependencies.

Backend options

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.

Setup per backend

Local encrypted file (the default):

frankenbeast init   # interactive — prompts for a passphrase, generates and stores the token

When 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.

Operator token setup

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:

  1. Run frankenbeast init — it prints the token once after generation.
  2. Keep the token server-side: use the configured secret store or set FRANKENBEAST_BEAST_OPERATOR_TOKEN=<token> in a local, uncommitted env file.
  3. Run the dashboard through same-origin backend routes. In Vite dev mode, use VITE_API_PROXY_TARGET/VITE_BEAST_API_PROXY_TARGET so the Vite server attaches the token to proxy requests without exposing it to the browser bundle.

Init backend setup flow

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 complete

Choose 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.json

Use 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.

Non-interactive / CI usage

export FRANKENBEAST_PASSPHRASE=<passphrase>
frankenbeast run

With 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.

References

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

Configuration

Environment Variables

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.

Module Configuration

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:

  1. Explicit value for that module key (modules.memory, modules.planner, modules.critique, or modules.governor) in run config or CLI dependency options.
  2. The matching environment fallback (FRANKENBEAST_MODULE_MEMORY, FRANKENBEAST_MODULE_PLANNER, FRANKENBEAST_MODULE_CRITIQUE, or FRANKENBEAST_MODULE_GOVERNOR) when that specific module key is unset.
  3. Enabled-by-default behavior when neither the module key nor a literal false env 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 3737

The Beast Loop

The orchestrator manages execution through four phases with circuit breakers at each stage.

Phase 1: Ingestion & Hydration

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.

Phase 2: Recursive Planning

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.

Lesson rollback workflow

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:

  1. Quarantine the target lesson so it stops being promoted into new worker handoffs.
  2. Attach the rollback reason, evidence URLs, and verifier command to the lesson audit trail.
  3. Either record a replacement lesson with fresh traceability evidence or retire the original lesson with no replacement.
  4. 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.

Phase 3: Validated Execution

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.

Phase 4: Observability & Closure

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.

Circuit Breakers

Trigger Action
Injection detected (MOD-01) Immediate halt
Budget exceeded (MOD-05) Escalate to HITL
Critique fails 3x (MOD-06) Escalate to human

Resilience

  • 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

Adding a New LLM Provider

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.

Wrapping External Agents

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.

Examples

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 start

Pass 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.

Martin Loop Build System

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.

Chat System

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.

Communications Gateway

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
WhatsApp 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 webhook setup and migration

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:

  1. 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.json too. Do not rely on frankenbeast init --repair to rotate a complete configuration; it exits without changing secrets when verification already passes.
  2. After storing the secret, re-register the webhook with Telegram using the fixed /webhooks/telegram URL and the same new value in the Bot API secret_token parameter. Telegram's setWebhook call replaces the previous webhook URL.
  3. Send a test update and confirm the fixed route accepts the X-Telegram-Bot-Api-Secret-Token header. A legacy token-bearing path returns 404 when sent directly to the chat server. The supported dashboard-web reverse proxy instead rewrites legacy token-bearing paths to /webhooks/telegram before forwarding, so verify the fixed upstream route and header validation rather than expecting a proxy-level 404.
  4. 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.

Project Status

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.

In Progress

  • 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.

Development

Working on a package

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 test

Testing patterns

All modules follow the same patterns:

  • Vitest as test runner
  • Root test entrypointsnpm test runs the default deterministic package suites, npm run test:root runs root-only Vitest tests, and npm run test:integration runs deterministic workspace integration suites exposed through Turborepo.
  • Opt-in evalsnpm run test:eval is intentionally separate from npm test and runs only workspaces with explicit eval/LLM-judge suites.
  • Dependency injection — all external deps are constructor-injected
  • Mock factoriesvi.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

Project structure

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)

Documentation

License

MIT

About

Deterministic guardrails framework for AI agents

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages