6.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build and test commands
Rust
cargo build --workspace— build all cratescargo nextest run --workspace— run all unit testscargo nextest run -p fabro-server— test a single cratecargo nextest run -p fabro-workflows -- test_name— run a single testset -a && source .env && set +a && cargo nextest run --workspace --profile e2e --run-ignored only— run all E2E live tests (requires credentials in.env, see.env.example)set -a && source .env && set +a && cargo nextest run -p fabro-llm --profile e2e --run-ignored only— run E2E tests for a single cratecargo fmt --check --all— check formattingcargo clippy --workspace -- -D warnings— lint
TypeScript (fabro-web)
cd apps/fabro-web && bun run dev— start React dev servercd apps/fabro-web && bun test— run testscd apps/fabro-web && bun run typecheck— type checkcd apps/fabro-web && bun run build— production build
Marketing site (apps/marketing)
cd apps/marketing && bun run dev— start Astro dev servercd apps/marketing && bun run build— production buildcd apps/marketing && bunx vercel --prod— deploy to Vercel (project: website, domain: fabro.sh)
Dev servers
fabro serve— starts the Rust API server (demo mode is per-request viaX-Fabro-Demo: 1header)cd apps/fabro-web && bun run dev— starts the React dev server- Mintlify docs dev server (requires Docker —
mintlify devneeds Node LTS which may not match the host):
Then open http://localhost:3333. Stop withdocker run --rm -d -p 3333:3333 -v $(pwd)/docs:/docs -w /docs --name mintlify-dev node:22-slim \ bash -c "npx mintlify dev --host 0.0.0.0 --port 3333"docker stop mintlify-dev.
API workflow
The OpenAPI spec at docs/api-reference/fabro-api.yaml is the source of truth for the fabro-api HTTP interface.
- Edit
docs/api-reference/fabro-api.yaml cargo build -p fabro-api-types— build.rs regenerates Rust types via typify- Write/update handler in
lib/crates/fabro-server/src/server.rs, add route tobuild_router() cargo nextest run -p fabro-server— conformance test catches spec/router driftcd lib/packages/fabro-api-client && bun run generate— regenerates TypeScript Axios client
Architecture
Fabro is an AI-powered workflow orchestration platform. Workflows are defined as Graphviz graphs, where each node is a stage (agent, prompt, command, conditional, human, parallel, etc.) executed by the workflow engine.
Rust crates (lib/crates/)
- fabro-cli — CLI entry point. Commands:
run,exec,serve,validate,parse,cp,model,doctor,init,install,ps,system prune,llm - fabro-workflows — Core workflow engine. Parses Graphviz graphs, runs stages, manages checkpoints/resume, hooks, retros, and human-in-the-loop interactions
- fabro-agent — AI coding agent with tool use (Bash, Read, Write, Edit, Glob, Grep, WebFetch).
Sandboxtrait abstracts execution environments - fabro-server — Axum HTTP server. Routes for runs, sessions, models, completions, usage. SSE event streaming. Demo mode via header
- fabro-exe — SSH-based sandbox implementation (
ExeSandbox) - fabro-sprites — Sprites VM sandbox implementation via
spriteCLI - fabro-llm — Unified LLM client with providers: Anthropic, OpenAI, Gemini, OpenAI-compatible, plus retry/middleware/streaming
- fabro-api-types — Auto-generated Rust types from OpenAPI spec (build.rs + typify)
- fabro-github — GitHub App auth (JWT signing, installation tokens, PR creation)
- fabro-db — SQLite with WAL mode, schema migrations
- fabro-mcp — Model Context Protocol client/server
- fabro-slack — Slack integration (socket mode, blocks API)
- fabro-devcontainer — Parses
.devcontainer/devcontainer.jsonfor container setup - fabro-git-storage — Git-based storage with branch store and snapshots
- fabro-telemetry — CLI analytics (Segment) and crash reporting (Sentry), with anonymous IDs, command sanitization, and detached subprocess delivery
- fabro-util — Shared utilities (redaction, terminal formatting)
TypeScript (apps/ and lib/packages/)
- apps/fabro-web — React 19 + React Router + Vite + Tailwind CSS frontend
- lib/packages/fabro-api-client — Auto-generated TypeScript Axios client from OpenAPI spec
Key design patterns
- Sandbox trait — Uniform interface for local, Docker, SSH (ExeSandbox), Sprites, and Daytona execution environments
- Graphviz graph workflows — Stages and transitions defined as Graphviz graph attributes
- OpenAPI-first —
fabro-api.yamldrives both Rust type generation (typify) and TypeScript client generation (openapi-generator) - Checkpoint/resume — Workflows can be paused, checkpointed, and resumed
Logging and events
When working on Rust crates, read the relevant strategy doc before making changes:
files-internal/logging-strategy.md— read when addingtracingcalls (info!,debug!,warn!,error!), working on error handling paths, or adding new operations that should be observablefiles-internal/events-strategy.md— read when adding or modifyingWorkflowRunEventvariants, touchingEventEmitter/emit(), changingprogress.jsonloutput, or adding new workflow stage types
Shell quoting in sandbox code
When interpolating values into shell command strings (in fabro-exe and fabro-workflows), always use the shell_quote() helper (backed by shlex::try_quote). Never use manual replace('\'', "'\\''") or unquoted interpolation. This applies to file paths, branch names, URLs, env vars, image names, glob patterns, and any other user-controlled input assembled into a shell script.
Rust import style
- Types (structs, enums, traits): import by name —
use crate::outcome::Outcome; - Functions: import the parent module, call as
module::function()—use fabro_workflows::operations; operations::create(...) - No glob imports in production code (
use foo::*). Globs are acceptable in test modules and preludes. Enforced by clippywildcard_importslint.
Testing workflows
fabro run <name>— run a workflow by name (resolvesfabro/workflows/<name>/workflow.toml), e.g.fabro run repl- Use
--no-retroto skip the retro step and finish faster