Adds **Amazon Bedrock** as an opt-in built-in provider, over Bedrock's unified **Converse / ConverseStream** API. One codec serves every Converse-capable family — Claude, Amazon Nova, Meta Llama, Mistral, DeepSeek, Moonshot Kimi, Z.AI GLM, MiniMax, NVIDIA Nemotron, and OpenAI gpt-oss — because AWS translates the envelope to each model's native dialect server-side. Auth is either **AWS SigV4** (the default credential chain — env / profile / IMDS / IRSA / SSO, resolved per request so sessions refresh) or a **Bedrock API key** (`AWS_BEARER_TOKEN_BEDROCK`, bearer). Disabled by default (the Ollama / OpenRouter opt-in pattern). This is the redo of #459's original Claude-only `InvokeModel` adapter, rebuilt on the gateway-refactor seams (#481–#497). @depopry's SigV4 signer, AWS event-stream frame decoder, `BedrockAuth`, the `aws_sigv4` credential grammar, `AdapterKind::Bedrock`, region-from-base_url, and the lean-deps decision are preserved and authored by him on the first two commits; the per-family `BedrockCodec` trait he wrote turned out to be the crate-wide `Codec` seam in miniature, so the refactor promoted exactly that shape. The original Claude-only description is preserved in a comment below. ## What's here - **`AdapterKind::Bedrock` × `CodecKind::BedrockConverse`** on the route, plus the `aws_sigv4` credential source (no static secret — the adapter signs at request time; `fabro-auth` stays AWS-free). *(@depopry)* - **SigV4 signer + AWS event-stream `FrameDecoder`** on the lean AWS stack (no `aws-sdk-bedrockruntime`; transport stays on `fabro-http`). Re-targeted at Converse's direct-JSON stream frames; the signer resolves credentials per request. *(@depopry)* - **`bedrock_converse` codec** — Converse envelope (`system[]`, typed content blocks, `inferenceConfig`, `toolConfig`), prompt caching via `cachePoint`, thinking-signature round-trip through `reasoningContent`, usage mapped onto the disjoint `TokenCounts` buckets, `provider_options.bedrock` passthrough. Plus the adapter shell and an event-stream byte loop beside the transport's shared SSE loop. - **Catalog**: `bedrock.toml` (Claude incl. Fable 5, Nova 2, Llama 4, Mistral, DeepSeek, Kimi, GLM, MiniMax, Nemotron, gpt-oss — cross-region inference-profile ids, per-model `billing_policy` so Claude bills Anthropic-style) and a companion **`bedrock-openai`** provider for GPT-5.5/5.4 over the `bedrock-mantle` Responses endpoint (pure config over the existing `openai_responses` codec, zero new code). - Secrets registry (`AWS_BEARER_TOKEN_BEDROCK`), gitleaks rules for both Bedrock key formats, the `docs/integrations/bedrock` guide, and live e2e tests. ## Live verification (confirmed end-to-end against a real AWS account) Verified on a real Bedrock account (us-east-2, SigV4 + bearer): - **SigV4 + Converse** — multiple families (Claude, Nova, DeepSeek, …) via the full settings → catalog → route → adapter → codec path. - **ConverseStream** — streaming deltas through the workflow engine. - **Multi-turn tool use** — agent loop with tool calls round-tripping (no-arg tools included). - **Multi-model routing** — Claude + DeepSeek pinned in one run through the single Converse codec. - **mantle Responses** — `openai.gpt-5.5` answered via the `bedrock-openai` provider (bearer auth). The exercise caught and fixed several issues that unit tests (static creds, mocked transports) could not — see the follow-up commits below. ## Follow-up fixes from live testing (commits on top of the foundation) 1. **Worker AWS env** — the workflow worker scrubs its env to an allowlist, so SigV4 (which re-resolves from the ambient chain per request) couldn't work through `fabro run`. The AWS credential-chain inputs now cross into the worker. 2. **Vault bearer key** — Bedrock was the only key-based provider missing a `vault:` credential ref, so `fabro secret set AWS_BEARER_TOKEN_BEDROCK` silently didn't feed it. Now resolves env → vault → SigV4. 3. **Converse tool-encoding hardening** — a no-arg tool call's `toolUse.input` is now a `{}` object (Bedrock rejects null), and every tool `inputSchema` gets a top-level `type: "object"` (strict families like DeepSeek reject a typeless schema Claude tolerates). 4. **Nova output cap** — `amazon.nova-2-lite` max_output 65536 → 65535 (Bedrock's per-request limit). Earlier fixes already folded into the foundation commits: the `aws-config` sleep-impl (default chain panicked) and AWS error-body decoding (top-level `message`/`Message`/`__type` → proper messages instead of "Unknown error"). ## Manual testing & setup See `docs/integrations/bedrock` — now documents the non-obvious account setup that live testing surfaced: the per-Region Anthropic use-case approval, `aws-marketplace:Subscribe` for third-party models, the Fable 5 / Mythos-class data-sharing opt-in, and the bearer-vs-SigV4 precedence override for running Converse + mantle side by side. ## Open decision / discussion - **Model-id naming** — Bedrock rows use dotted ids mirroring Bedrock's native inference-profile ids (`us.anthropic.claude-sonnet-4-6`, `openai.gpt-5.5`), which also makes them the wire `api_id`. Third scheme alongside bare ids and OpenRouter's `vendor/model` slashes. No collision risk (enforced at catalog build). Open to a uniform scheme if preferred. - **`BEDROCK_API_KEY` alias** — see the comment thread; the AWS console hands some users `export BEDROCK_API_KEY=` while the SDK-standard var is `AWS_BEARER_TOKEN_BEDROCK`. Question of whether to accept both. ## Deferred (named follow-ups) - **`qwen.qwen3-coder-next`** — omitted pending a verified Bedrock model/inference-profile id (its fabro id isn't a valid Bedrock identifier; needs an explicit `api_id`). Re-add once confirmed via `aws bedrock list-inference-profiles`. - **Claude Mythos 5** — Anthropic-Messages-only on `bedrock-mantle` (limited preview). - **Converse structured output** (`response_format` rejected with a clear error). - **`reasoning_effort` on Converse rows** via `additionalModelRequestFields` (the `bedrock-openai` GPT rows already accept effort levels). - **CountTokens** route (`count_input_tokens` returns `None`). ## Verification `cargo nextest run --workspace`: green except the pre-existing environment-dependent fabro-workflow failures (identical on main). clippy `-D warnings` + pinned-nightly fmt clean. Codec unit tests + adapter httpmock tests + frame-decoder/signer locks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Scott Werner <scott@sublayer.com> Co-authored-by: Scott Werner <stwerner@vt.edu> |
||
|---|---|---|
| .ai/prompts | ||
| .cargo | ||
| .claude | ||
| .config | ||
| .fabro | ||
| .github | ||
| apps | ||
| bin/agent | ||
| docker | ||
| docs | ||
| evals/swe-bench | ||
| installer | ||
| lib | ||
| test | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| bun.lock | ||
| bunfig.toml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| clippy.toml | ||
| CONTRIBUTING.md | ||
| docker-compose.local.yaml | ||
| docker-compose.prod.yaml | ||
| docker-compose.split-web.yaml | ||
| docker-compose.yaml | ||
| Dockerfile | ||
| install.md | ||
| install.sh | ||
| LICENSE.md | ||
| package.json | ||
| README.md | ||
| rustfmt.toml | ||
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?
# With Claude Code
curl -fsSL https://fabro.sh/install.md | claude
# With Codex
codex "$(curl -fsSL https://fabro.sh/install.md)"
# With Homebrew
brew install fabro-sh/tap/fabro-nightly
# With Bash
curl -fsSL https://fabro.sh/install.sh | bash
Then run fabro server start to finish setup in your browser. The server opens a web wizard, exits when the wizard completes, and starts in configured mode the next time you run it.
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.
- Inspect every run — Query durable event streams, checkpoints, conclusions, and stage outputs to understand what happened and improve the workflow.
- 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 |
| 📊 | Run observability | Durable events, checkpoints, conclusions, and stage outputs make every run inspectable and exportable |
| ⚡ | 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:
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, observability, 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 Homebrew
brew install fabro-sh/tap/fabro-nightly
# With Bash
curl -fsSL https://fabro.sh/install.sh | bash
Release binaries and the multi-arch Docker image ship with SLSA Build Provenance attestations. See Verifying Releases to check an artifact was built by our GitHub Actions workflow.
Then finish setup in your browser and initialize Fabro in your project:
fabro server start # opens a web install wizard in your browser
# (server exits when the wizard finishes — start it again to run Fabro)
cd my-project
fabro repo init # per project
For headless or scripted environments, fabro install runs the same setup as a CLI-only wizard.
Running Fabro
Fabro runs as a server. You choose where it runs:
- On your laptop — install the CLI (above) and run
fabro server start. Workflows pause when your laptop sleeps. - On a host (self-hosted) — deploy the Docker image with
docker composeor any cloud container service (ECS, Cloud Run, Kubernetes). See Self-host with Docker.
One-click managed alternative for the same Docker image:
See the deployment overview for the full picture.
Contributing to Fabro
Outside contributions are welcome! Whether it's a bug fix, a new feature, documentation, or a typo -- we'd love your help making Fabro better.
- Bug fixes and small improvements -- Send a pull request directly.
- Larger features or changes -- Open a GitHub Issue or start a Discussion first so we can align on the approach.
- Questions -- Open a Discussion or email bryan@qlty.sh.
See CONTRIBUTING.md for build instructions and development workflow.
Help or Feedback
- Bug reports via GitHub Issues
- Feature requests via GitHub Discussions
- Email bryan@qlty.sh for questions
- See CONTRIBUTING.md for build instructions and development workflow
License
Fabro is licensed under the MIT License.