Add a shared MiniJinja-based template crate and migrate workflow prompts,
imports, hooks, and InterpString env references to the new {{ ... }}
syntax. This also threads typed run inputs through workflow rendering and
updates docs and tests to match the new templating model.
Rewrite every docs/ reference and integration guide example that
previously showed legacy flat TOML (`[llm]`, `[vars]`, `[sandbox]`,
`[setup]`, `[exec]`, `[fabro]`, `[pull_request]`, `[mcp_servers]`,
`[git]`, `[web]`, `[api]`, `[features] retros`, `version = 1`,
top-level `storage_dir`) to use the v2 namespaced schema. Also update
the surrounding prose to describe v2 merge semantics (R22 run.inputs
wholesale replacement, R71 sticky sandbox.env/labels, R30 whole-list
prepare.steps replacement, hook id-based replacement).
Files touched:
- docs/reference/user-configuration.mdx (complete rewrite around
[cli.*] ownership, [run.*] run-scoped defaults, [cli.target] /
[cli.exec] / [cli.output] / [cli.updates] / [cli.logging], and
[run.agent.mcps.<name>] with durations like "10s")
- docs/reference/cli.mdx (settings.toml example uses [cli.exec.*],
[run.model], [cli.target])
- docs/execution/run-configuration.mdx (full run-config example
rewritten to use [workflow].graph, [run].goal/working_dir,
[run.model], [run.prepare.steps], [run.sandbox.daytona.snapshot]
with Size values, [run.inputs], [run.artifacts], [run.agent.mcps],
[run.pull_request], [[run.hooks]] with optional id and duration
timeout; section docs explain the new merge semantics)
- docs/execution/environments.mdx and devcontainers.mdx (sandbox
examples now use [run.sandbox.*])
- docs/execution/retros.mdx (retros moved to [run.execution] retros
= true per R31)
- docs/execution/failures.mdx (fallbacks now a single ordered array
under [run.model].fallbacks)
- docs/workflows/variables.mdx ([vars] → [run.inputs], wholesale
replacement semantics explained)
- docs/administration/server-configuration.mdx (full reference
rewritten around [server.listen]/[server.api]/[server.web]/
[server.auth]/[server.storage]/[server.scheduler]/[server.logging]/
[server.integrations])
- docs/api-reference/overview.mdx (auth strategies now enabled via
[server.auth.api.jwt].enabled and [server.auth.api.mtls].enabled;
listener TLS moved to [server.listen.tls])
- docs/integrations/daytona.mdx, github.mdx (provider config now
nested under [run.sandbox.daytona] / [server.integrations.github])
- docs/human-tools/ssh-access.mdx (sandbox examples to v2)
- docs/agents/mcp.mdx (Playwright sandbox example to [run.agent.mcps])
- docs/core-concepts/models.mdx (model config and fallbacks array to
[run.model])
Canonical fabro-cli overrides and server run_manifest now emit
verbose via [cli.output].verbosity = verbose rather than the prior
run.metadata staging. No code changes beyond those Stage 4 fixes that
were already in flight.
Stage captured artifacts in per-attempt tempdirs and persist them through an
explicit artifact sink instead of writing into run scratch cache.
Server-managed and test-owned runs now write directly to ArtifactStore, while
CLI worker runs keep the staged upload path. The local run summary now prints
durable artifact identifiers and copy hints rather than scratch-cache paths,
and the run-directory docs and integration coverage were updated to match.
Add a server-side web.enabled toggle and CLI overrides so Fabro can run
with API and health only while disabling the embedded SPA, browser auth
routes, and web-only helper endpoints.
Accept `--bind <ip>` as a TCP bind request while keeping the default
Unix socket behavior unchanged. Resolve host-only TCP binds inside the
serving process so startup output, server metadata, and status always
reflect the concrete host:port, preferring 32276 and falling back to a
random port with a warning when needed.
Move the built web bundle into an embedded fabro-spa crate so Cargo and
release builds no longer depend on Bun at build time, and preserve the
local dev override path for fast UI iteration.
At the same time, rename interview and agent-level aborted flows to
interrupted, keep cancelled for run-level shutdown, and stop reporting
skipped answers as interruptions in the run event stream.
Make ArtifactStore the only artifact read path, stop writing
manifest.json into run scratch, and update the CLI summary to
resolve artifact paths from the durable server API.
Stop writing scratch final.patch files now that diffs are projected from
run state, and remove the unused cache/artifacts/values plumbing while
keeping runtime/blobs materialization intact.
Update tests and run-directory docs to match the current scratch contract.
Route subprocess worker stderr directly into server tracing and remove
the scratch-file sink. Update the run-directory docs to reflect that
runtime now only documents blob materialization here.
Drop scratch-only compatibility paths and legacy test scaffolding now that
SlateDB-backed state is authoritative. This removes scratch file fallbacks,
updates docs and UI labels, and moves tests onto durable store-backed helpers.
Persist pending interviews in run state, deliver accepted answers to workers
through the server-owned control path, and remove the old scratch-file and
WebInterviewer transports.
This also moves Slack onto the canonical server answer flow, adds richer
question metadata to the API and run events, and covers the subprocess
question lifecycle with end-to-end tests.
Dead feature cleanup: `skill install` was hidden/experimental and never
graduated; the run verification endpoint was only implemented in demo mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- centralize FABRO_HOME and storage path resolution in fabro-config
- rename store types, extract ArtifactStore, and simplify run key layout
- switch run scratch to scratch/, remove RuntimeState, and refresh docs/clients
Consolidate CLI and server machine defaults under settings.toml,
including loader renames, writer preservation fixes, same-machine
manifest handling, and docs/test updates for the new config model.
SQLite was retired as the server metadata store in d490dbe4.
Remove dead sqlx workspace dep, better-sqlite3 trustedDependencies,
and update docs that still referenced SQLite persistence.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move secret storage, diagnostics, and repo/provider validation behind the
server API so credentials live under the server storage dir and take effect
immediately without process env mutation.
This also removes the old .env runtime path, rewires doctor/install/secret/
provider login/repo init around the server contract, and regenerates the
TypeScript client for the new endpoints.
Update the run directory, context, and output docs to describe
large offloaded values as file-backed artifacts while preserving the
existing cache path examples.
Replace the old React Router SSR setup with a static SPA build served by
fabro-server, move setup and GitHub auth handling into Rust, and update the
default local web URL and stale Arc-era references to match the Fabro name.
Users should use `fabro repo init` instead. The deprecation shim has
been in place long enough; remove it and update all docs references.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uses clap_complete to generate tab-completion scripts for zsh, fish,
elvish, and PowerShell. Bash generation is caught gracefully since
clap_complete panics with #[command(flatten)] subcommands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restructure the flat `serve` command into a nested `server start`
subcommand, following the existing namespace pattern (system prune,
repo init, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop the Sprites (Fly.io microVM) sandbox provider entirely. Three
providers remain: Local, Docker, and Daytona.
- Delete lib/crates/fabro-sandbox/src/sprites/ module
- Remove sprites feature flag and dep comments from Cargo.toml
- Remove sprites module declaration from lib.rs
- Update resolve_path cfg guard to daytona-only
- Delete docs/integrations/sprites.mdx and remove nav entry
- Remove Sprites rows from provider tables in docs
- Clean up SDK reference and changelog mentions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These commands all operate on a run's sandbox environment. Grouping them
under `fabro sandbox` makes the mental model clear and avoids confusion
with `fabro asset cp`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the per-run `--run-dir` CLI flag with `--storage-dir` which sets
the base storage directory (default ~/.fabro). Runs are now created under
`<storage-dir>/runs/` automatically. This unifies the server's `data_dir`
config with the CLI by renaming `FabroConfig.data_dir` to `storage_dir`
and adding a `storage_dir()` convenience method.
Key changes:
- FabroConfig: `data_dir` → `storage_dir` (serde alias preserves compat)
- CLI: `--run-dir` → `--storage-dir` on `fabro run`
- `__detached`: now takes `--storage-dir` + `--run-id` instead of `--run-dir`
- All ~20 CLI commands derive runs base from config instead of hardcoded default
- Added parameterized `runs_base(storage_dir)` and `make_run_dir()` helpers
- Updated OpenAPI spec, docs, and all tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preflight validation is conceptually distinct from running a workflow —
it deserves its own top-level command rather than being a flag on `run`.
- Add `PreflightArgs` struct and `Commands::Preflight` variant
- Create `commands/preflight.rs` with dedicated `execute()` function
- Remove `--preflight` flag from `RunArgs`
- Refactor `load_workflow_source_input` to take individual params
instead of `&RunArgs`
- Refactor `resolve_cli_goal` to take `Option<&str>` / `Option<&Path>`
- Refactor `run_preflight` to take `cli_model`/`cli_provider` instead
of `&RunArgs`, make `pub(crate)`
- Update docs and skills references
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resume now follows the same subprocess pattern as run: look up run
directory by ID prefix, validate checkpoint exists, clean stale
artifacts, reset status to Submitted, spawn _run_engine --resume, and
attach. This eliminates ~1600 lines of duplicated env/sandbox setup
from resume.rs.
Key changes:
- operations::start() and operations::resume() take run_dir instead
of Persisted, loading state from disk internally
- run_engine() builds RunOptions from RunRecord on disk, so callers
no longer extract record fields manually
- StartOptions flattened (no more nested InitOptions)
- FabroError::Precondition variant for start/resume guard checks
- _run_engine accepts --resume flag to dispatch to resume path
- operations::restore removed (no longer needed)
- Resume CLI stripped to just <RUN_ID> + --detach
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce two new persistence types aligned to the CREATE/START lifecycle:
- RunRecord (run.json): written at CREATE with merged FabroConfig, fully
transformed Graph, and run metadata
- StartRecord (start.json): written at START with start_time, run_branch,
and base_sha
All readers (run_lookup, inspect, diff, pr, attach, detached_support,
start, run_fork, pull_request, run_rewind, resume) now read from the
new types first. Legacy manifest.json + spec.json are still written
for backward compatibility (removal in follow-up).
Also adds dry_run, auto_approve, no_retro fields to FabroConfig, derives
Default on LlmConfig and Graph, and updates docs + tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preserve original error chains (reqwest, serde_json, etc.) in SdkError
via Arc<dyn Error>-backed #[source] fields on Network, RequestTimeout,
Stream, and Configuration variants. This makes production debugging of
network/TLS/DNS issues easier since error reporters can now walk the
full chain. Serde-compatible via #[serde(skip)] — message string still
carries the text for serialized forms.
Also add a `type` field to ToolCall (defaulting to "function") so
non-function tool types from providers won't be silently mishandled.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove ErrorPolicy enum (continue/fail_fast/ignore) and the k_of_n/quorum
join policies from the parallel handler, leaving only wait_all and
first_success. This deletes ~180 lines of conditional logic including
FailFast early termination, the ParallelEarlyTermination event, and all
related tests and documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove any-edge fallback from select_edge() in deterministic mode; random
mode retains it as an enhancement over the base spec
- Restrict preferred_label and suggested_next_ids matching to unconditional
edges only (already applied in prior work, tests added here)
- Rename default_max_retry → default_max_retries across codebase (code, docs,
fixtures, skills) and change default from 3 to 0
- Update transitions.mdx to document edge selection cascade accurately
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>