Find a file
Bryan Helmkamp dc856d0884
feat(settings): stage 6.1 consumer migration builds workspace-wide
Extends the stage 6.1 WIP into a compiling state across the workspace.
Most crates and their unit/integration tests now read run.* / cli.* /
server.* v2 layers directly or through targeted bridge helpers.

Key moves in this commit:

fabro-server
- AppState.settings: Arc<RwLock<SettingsFile>> -- all helpers,
  create_app_state_with_* factories, and tests updated.
- api_server_settings bridges SettingsFile -> legacy Settings via the
  transitional bridge so /api/v1/settings still emits the legacy DTO
  shape until Stage 6.6 replaces it with an allow-list DTO.
- get_system_info, get_system_df, get_github_repo, webhook startup, and
  other read sites use the v2 accessors (github_app_id_str,
  server_web, run_sandbox, run_model_*).
- web_auth.rs wraps each oauth / register / setup-status handler in a
  local `bridged` helper that produces a legacy Settings from the v2
  state, so the complex oauth mutation flow keeps working until its
  Stage 6.6 rewrite.
- diagnostics::check_github_app reads via github_*_str accessors;
  check_crypto bridges to the legacy shape inline.
- serve.rs: load_settings returns SettingsFile; apply_serve_overrides /
  apply_runtime_settings mutate v2 subtrees directly; the config poll
  loop and TLS/webhook startup use bridged() for legacy-shape reads.
- Tests in tests/it/{helpers,api/*,scenario/*} rewritten to construct
  SettingsFile via ConfigLayer::parse or v2 struct literals.

fabro-workflow
- Every test fixture in pipeline/{finalize,initialize,pull_request,retro,
  execute,persist}, operations/{create,rebuild_meta,start}, run_lookup,
  runtime_store, handler/manager_loop, and tests/it/{integration,
  daytona_integration}.rs now uses SettingsFile.
- start.rs hooks into the bridge helpers directly via use-imports.
- run_graph / run_graph_from_checkpoint / initialize / finalize /
  pull_request calls are Box::pin'd to stay under clippy's large-future
  threshold after the v2 tree brought RunOptions size up.
- resolve_run_settings writes resolved model/provider back into
  run.model as InterpStrings; tests assert via run_model_*_str().
- preprocess_and_validate pulls vars from run_inputs_as_strings().

fabro-cli
- manifest_builder uses ConfigLayer.combine(...).into() to get a v2
  SettingsFile for the manifest goal resolution path; file-based
  goal_file handling is deferred to 6.6 when the manifest schema catches
  up.
- runner::maybe_build_github_app_credentials and
  tests/it/cmd/{create,runner}.rs read from v2 accessors.
- commands/config/mod.rs::merged_config returns SettingsFile; the
  server-side retrieve_server_settings is bridged via a stopgap
  legacy_settings_to_v2 shim that Stage 6.6 replaces.
- commands/store/dump.rs sample_run_record constructs SettingsFile.

fabro-store, fabro-checkpoint
- Test fixtures constructing RunRecord values updated to SettingsFile.
- fabro-checkpoint/src/author.rs stays (v2 From impl landed in a
  previous additive commit).

fabro-config
- effective_settings.rs rewrite compiles and passes its unit tests.
- project::resolve_working_directory takes &SettingsFile.

Build status: `cargo build --workspace --tests`, `cargo clippy
--workspace -- -D warnings`, and `cargo fmt --check --all` all pass.
`cargo nextest run --workspace` passes 3,749 of 3,764 tests; the 15
remaining failures are fabro-cli integration tests whose snapshot +
TOML fixture shapes still need manual updates:

- cmd::config::* (seven tests): fixture TOML files still use v1
  top-level keys and the snapshot outputs expect the legacy flat JSON
  shape.
- cmd::inspect::* (four tests): run-record JSON snapshots embed the
  flat Settings shape.
- cmd::run::dry_run_persists_event_history_in_store and
  json_run_implies_auto_approve_for_human_gates: check `settings.dry_run
  == Some(true)` directly on the v2 file; should assert
  dry_run_enabled() instead.
- cmd::attach::attach_json_errors_without_prompting_for_human_input:
  unrelated insta snapshot drift caused by the new SettingsFile JSON
  shape leaking into an events-log snapshot.

Follow-up work for this stage also includes:
- Rewriting web_auth.rs register flow to emit v2 TOML directly and to
  re-parse the written file back into state.settings so in-memory
  state doesn't lag the on-disk file.
- Removing the legacy_settings_to_v2 shim in fabro-cli/config once
  the server-side settings endpoint returns v2 shapes (Stage 6.6).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:25:59 -04:00
.ai/prompts Unify fabro run foreground to use create + start + attach (#141) 2026-03-22 22:48:09 -04:00
.cargo Disable empty doc-tests and add terse test output alias 2026-02-23 10:57:26 -05:00
.claude docs 2026-04-06 16:57:34 -04:00
.config test(nextest): set leak timeout to 500ms 2026-04-07 16:19:47 -04:00
.github feat: embed fabro spa and align interruption semantics 2026-04-08 14:43:44 -04:00
apps fix(fabro-web): restore local watch rebuilds 2026-04-08 15:27:27 -04:00
bin Rename fabro-workflows crate to fabro-workflow 2026-03-30 12:27:40 -04:00
docker refactor(config): unify machine config as settings.toml 2026-04-05 23:55:28 -04:00
docs feat(settings): stage 6.1 consumer migration builds workspace-wide 2026-04-09 15:25:59 -04:00
docs-internal feat(artifacts): remove scratch artifact cache staging 2026-04-08 17:42:55 -04:00
evals/swe-bench Persist fabro_run_dir in scoreboard instances.jsonl 2026-03-20 16:43:25 -04:00
fabro/workflows feat(tests): migrate fabro-cli fixtures and repo fabro.toml to v2 2026-04-09 09:57:30 -04:00
files-internal test: standardize no-proxy localhost HTTP clients 2026-04-05 12:17:29 -04:00
lib feat(settings): stage 6.1 consumer migration builds workspace-wide 2026-04-09 15:25:59 -04:00
scripts feat: embed fabro spa and align interruption semantics 2026-04-08 14:43:44 -04:00
test refactor(workspace): satisfy clippy all-targets warnings 2026-04-05 14:37:32 -04:00
.env.example fix clippy large_enum_variant and rename ARC_ env vars in .env.example 2026-03-12 14:37:22 -04:00
.gitattributes feat: embed fabro spa and align interruption semantics 2026-04-08 14:43:44 -04:00
.gitignore feat: embed fabro spa and align interruption semantics 2026-04-08 14:43:44 -04:00
AGENTS.md feat: embed fabro spa and align interruption semantics 2026-04-08 14:43:44 -04:00
bun.lock chore: remove stale SQLite references after retirement 2026-04-05 21:29:24 -04:00
Cargo.lock feat(types): add settings v2 parse tree scaffolding 2026-04-09 09:02:45 -04:00
Cargo.toml feat(artifacts): finish object-backed artifact uploads 2026-04-07 16:56:37 -04:00
CLAUDE.md Move CLAUDE.md to AGENTS.md with symlink for compatibility 2026-03-09 13:02:06 -04:00
clippy.toml Enforce no-inline-qualified-paths via clippy absolute_paths lint 2026-03-29 13:47:08 -04:00
CONTRIBUTING.md Add issue-based contribution policy to README and CONTRIBUTING 2026-03-18 17:41:34 -04:00
fabro.toml feat(tests): migrate fabro-cli fixtures and repo fabro.toml to v2 2026-04-09 09:57:30 -04:00
install.md Move install files to apps/marketing/public, symlink from repo root 2026-03-16 13:23:58 -04:00
install.sh Move install files to apps/marketing/public, symlink from repo root 2026-03-16 13:23:58 -04:00
LICENSE.md Add README.md and MIT LICENSE 2026-03-10 14:48:58 -04:00
package.json chore: remove stale SQLite references after retirement 2026-04-05 21:29:24 -04:00
README.md Remove deprecated fabro init command 2026-03-30 16:17:38 -04:00
rustfmt.toml Apply rustfmt 2024 style edition across workspace 2026-03-29 13:47:08 -04:00

Fabro

The open source dark software factory for expert engineers

AI coding agents are powerful but unpredictable. You either babysit every step or review a 50-file diff you don't trust. Fabro gives you a middle path: define the process as a graph, let agents execute it, and intervene only where it matters. Why Fabro?

License: MIT docs

# With Claude Code
curl -fsSL https://fabro.sh/install.md | claude

# With Codex
codex "$(curl -fsSL https://fabro.sh/install.md)"

# With Bash
curl -fsSL https://fabro.sh/install.sh | bash
Fabro Runs board showing workflows across Working, Pending, Verify, and Merge stages

Use Cases

  • Extend disengagement time — Stop babysitting an agent REPL. Define a workflow with verification gates and walk away — Fabro keeps the process on track without you.
  • Leverage ensemble intelligence — Seamlessly combine models from different vendors. Use one model to implement, another to cross-critique, and a third to summarize — all in a single workflow.
  • Share best practices across your team — Collaborate on version-controlled workflows that encode your software processes as code. Review, iterate, and reuse them like any other source file.
  • Reduce token bills — Route cheap tasks to fast, inexpensive models and reserve frontier models for the steps that need them. CSS-like stylesheets make this a one-line change.
  • Improve agent security — Run agents in cloud sandboxes with full network and filesystem isolation. Keep untrusted code off your laptop and out of your production environment.
  • Run agents 24/7 — Fabro's API server queues and executes runs continuously. Close your laptop — workflows keep running and results are waiting when you return.
  • Scale infinitely — Move execution off your laptop and into cloud sandboxes. Run as many concurrent workflows as your infrastructure allows.
  • Guarantee code quality — Layer deterministic verifications — test suites, linters, type checkers, LLM-as-judge — into your workflow graph. Failures trigger fix loops automatically.
  • Achieve compounding engineering — Automatic retrospectives after every run feed a continuous improvement loop. Your workflows get better over time, not just your code.
  • Specify in natural language — Define requirements as natural-language specs and let Fabro generate — and regenerate — implementations that conform to them.

Key Features

Feature Description
🔀 Deterministic workflow graphs Define pipelines in Graphviz DOT with branching, loops, parallelism, and human gates. Diffable, reviewable, version-controlled
🙋 Human-in-the-loop Approval gates pause for human decisions. Steer running agents mid-turn. Interview steps collect structured input
🎨 Multi-model routing CSS-like stylesheets route each node to the right model and provider, with automatic fallback chains
☁️ Cloud sandboxes Run agents in isolated Daytona cloud VMs with snapshot-based setup, network controls, and automatic cleanup
🔌 SSH access and preview links Shell into running sandboxes with fabro sandbox ssh and expose ports with fabro sandbox preview for live debugging
🌲 Git checkpointing Every stage commits code changes and execution metadata to Git branches. Resume, revert, or trace any change
📊 Automatic retros Each run generates a retrospective with cost, duration, files touched, and an LLM-written narrative
Comprehensive API REST API with SSE event streaming and a React web UI. Run workflows programmatically or as a service
🦀 Single binary, no runtime One compiled Rust executable with zero dependencies. No Python, no Node, no Docker required
⚖️ Open source (MIT) Full source code, no vendor lock-in. Self-host, fork, or extend to fit your workflow

Example Workflow

A plan-approve-implement workflow where a human reviews the plan before the agent writes code:

Plan-Implement workflow graph showing Start → Plan → Approve Plan → Implement → Simplify → Exit with a Revise loop
digraph PlanImplement {
    graph [
        goal="Plan, approve, implement, and simplify a change"
        model_stylesheet="
            *        { model: claude-haiku-4-5; reasoning_effort: low; }
            .coding  { model: claude-sonnet-4-5; reasoning_effort: high; }
        "
    ]

    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare, label="Exit"]

    plan      [label="Plan", prompt="Analyze the goal and codebase. Write a step-by-step plan.", reasoning_effort="high"]
    approve   [shape=hexagon, label="Approve Plan"]
    implement [label="Implement", class="coding", prompt="Read plan.md and implement every step."]
    simplify  [label="Simplify", class="coding", prompt="Review the changes for clarity and correctness."]

    start -> plan -> approve
    approve -> implement [label="[A] Approve"]
    approve -> plan      [label="[R] Revise"]
    implement -> simplify -> exit
}

Agents run as multi-turn LLM sessions with tool access. Human gates (hexagon) pause for approval. The stylesheet routes planning to a cheap model and coding to a frontier model. See the Graphviz DOT language reference for the full syntax.


📖 Documentation

Fabro ships with comprehensive documentation covering every feature in depth:

  • Getting Started -- Installation, first workflow, and why Fabro exists
  • Defining Workflows -- Node types, transitions, variables, stylesheets, and human gates
  • Executing Workflows -- Run configuration, sandboxes, checkpoints, retros, and failure handling
  • Tutorials -- Step-by-step guides from hello world to parallel multi-model ensembles
  • API Reference -- Full OpenAPI spec with authentication, SSE events, and client SDKs

Quick Start

Install

# With Claude Code
curl -fsSL https://fabro.sh/install.md | claude

# With Codex
codex "$(curl -fsSL https://fabro.sh/install.md)"

# With Bash
curl -fsSL https://fabro.sh/install.sh | bash

Then initialize Fabro in your project:

fabro install          # one-time setup

cd my-project
fabro repo init        # per project

Contributing to Fabro

Fabro uses an issue-based contribution model. Instead of accepting outside pull requests, we accept bug reports and feature requests as GitHub Issues.

AI can rapidly write or edit large amounts of plausible-looking code. Accepting these patches from external sources opens up risks to security and quality. To mitigate these risks, we are tightly controlling the inputs into the software development process.

Contributions follow these steps:

  1. Open an issue -- File an issue with a bug report or feature request. The more detail your issue contains, the easier it will be for us to address it quickly and successfully.

  2. We build it -- A Fabro maintainer will follow our software development process to create a patch, supervising AI coding agents and workflows.

  3. You get credit -- We will include you as a co-author on the commit which lands the change.

As a result, you get the feature you need, without needing to keep a fork in sync.

If you need a capability which is not in-scope for Fabro, you always have the option to maintain a fork of Fabro as it is distributed under the MIT license.


Help or Feedback


License

Fabro is licensed under the MIT License.