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.
Resolve every clippy warning across the workspace when running with
--tests enabled. Previously only library code was lint-clean; test
code had accumulated issues that were invisible without --tests.
Fixes:
- redundant_closure_for_method_calls: |s| s.as_source() -> InterpString::as_source
(effective_settings, resolve_cli/root/server/features, run_event/record_serde,
materialize_run) — add InterpString imports where needed
- absolute_paths: inline fabro_types::settings::* paths -> use imports;
add #![allow(clippy::absolute_paths)] to fabro-cli and fabro-server
IT test harnesses (matching the existing pattern in integration.rs)
- bool_assert_comparison: assert_eq!(x, true) -> assert!(x)
- needless_raw_string_hashes: r#"..."# -> r"..." where no inner quotes
- field_reassign_with_default: mut + field assign -> struct literal with ..Default
- match_same_arms: merge Timeout | Disconnected arms in attach.rs
- needless_pass_by_value: signal_rx by ref in attach.rs
- unreadable_literal: 9999999999 -> 9_999_999_999
- default_trait_access: Default::default() -> BTreeMap::default()
- items_after_statements: move use to function top
- large_futures: allow in integration.rs test module (test-only, not prod)
- filter_map_bool_then: .filter_map(bool::then) -> .filter().map()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop the dead sandbox and hook bridge helpers that no longer have runtime
callers, and move the run settings serde coverage into fabro-types where the
wire types live. Add the missing /api/v1/runs/:id/settings contract test so the
outward sparse settings shape stays covered after the refactor.
`TlsSettings` and its `from_settings(&SettingsFile)` constructor
lived in `jwt_auth.rs` as a historical artifact from the Stage 6.6g
rewrite — the auth resolver only needs to know *whether* TLS is
present (for mTLS support), not the contents of the triple. The
type is really a listen-side concern that belongs next to the
rustls builder.
Moves the type into a new `fabro-server/src/tls_config.rs` module
(35 LOC). Updates three importers:
- `jwt_auth.rs` — imports `TlsSettings` from `crate::tls_config`;
drops the `std::path::PathBuf` / `InterpString` / `ServerListenLayer`
/ `serde::Deserialize` imports that are no longer used after the
type moved.
- `serve.rs` — splits the multi-item `use crate::jwt_auth::{...}`
line so `TlsSettings` comes from `crate::tls_config`.
- `tls.rs` — same split.
- `tests/it/api/mtls.rs` — same split.
Pure relocation; no behavioral change. 156 fabro-server tests pass,
`cargo fmt --check --all` and `cargo clippy --workspace -- -D warnings`
are clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Final mechanical pass: replaces every remaining
`fabro_types::settings::v2::*` import path with
`fabro_types::settings::*` (or the appropriate submodule) across 53
files in 10 crates, then deletes the transitional
`pub mod v2 { pub use super::*; }` alias from
`fabro-types/src/settings/mod.rs`.
No functional changes — all touches are `sed s|settings::v2::|settings::|g`
on import statements and fully-qualified type paths. The v2
namespace is now fully gone; the authoritative module path is
`fabro_types::settings::{accessors, cli, duration, features, interp,
model_ref, project, run, server, size, splice_array, tree, version,
workflow}`.
All 3,758 workspace tests pass. `cargo fmt --check --all` and
`cargo clippy --workspace -- -D warnings` are clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
**6.3b finishing touch:** relocates the last three transitional server
runtime types (`ApiAuthStrategy`, `TlsSettings`, `ApiSettings`) out of
`fabro-types` into `fabro-server/src/jwt_auth.rs` — the only crate
that consumes them. `serve.rs`, `tls.rs`, and the mTLS integration
test now import from `crate::jwt_auth` / `fabro_server::jwt_auth`
instead of `fabro_types::settings::server`.
`lib/crates/fabro-types/src/settings/server.rs` (the legacy one) and
the `pub mod server_config { pub use fabro_types::settings::server::*; }`
block in `fabro-server/src/lib.rs` are both deleted. The legacy
runtime type module tree under `fabro-types/src/settings/{hook,
mcp, project, run, sandbox, server, user}.rs` is now fully gone —
nothing left to promote.
**6.5b flatten:** `git mv` the fourteen v2 modules up one directory:
- `settings/v2/accessors.rs` → `settings/accessors.rs`
- `settings/v2/cli.rs` → `settings/cli.rs`
- `settings/v2/duration.rs` → `settings/duration.rs`
- `settings/v2/features.rs` → `settings/features.rs`
- `settings/v2/interp.rs` → `settings/interp.rs`
- `settings/v2/model_ref.rs` → `settings/model_ref.rs`
- `settings/v2/project.rs` → `settings/project.rs`
- `settings/v2/run.rs` → `settings/run.rs`
- `settings/v2/server.rs` → `settings/server.rs` (name no longer
collides with the deleted legacy `server.rs`)
- `settings/v2/size.rs` → `settings/size.rs`
- `settings/v2/splice_array.rs` → `settings/splice_array.rs`
- `settings/v2/tree.rs` → `settings/tree.rs`
- `settings/v2/version.rs` → `settings/version.rs`
- `settings/v2/workflow.rs` → `settings/workflow.rs`
- `settings/v2/mod.rs` — deleted (its `pub mod` / `pub use` block
moved into `settings/mod.rs`).
`settings/mod.rs` picks up those `pub mod` declarations and the
accompanying `pub use <module>::*` re-exports, plus a transitional
`pub mod v2 { pub use super::*; }` alias so that existing
`fabro_types::settings::v2::*` import paths across the workspace
keep compiling. A follow-up sweep will drop the `::v2::` prefix from
every consumer and then the alias can go away.
3,758 workspace tests pass. `cargo fmt --check --all` and
`cargo clippy --workspace -- -D warnings` are clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
bridge.rs (818 LOC) is gone. Production consumers no longer produce a
full legacy `Settings` from v2 state; every read path walks the v2 tree
directly or uses one of the narrow v2->runtime helpers in the new
`settings::v2::to_runtime` module.
Core moves:
fabro-types
- Delete `settings::v2::bridge::bridge_to_old` and the whole bridge.rs
file.
- Relocate the narrow v2->runtime helpers (`bridge_sandbox`,
`bridge_mcp_entry`, `bridge_mcps`, `bridge_hook`, `bridge_worktree_mode`,
`bridge_merge_strategy`, `bridge_pull_request`, `bridge_run_artifacts`)
into a new `settings::v2::to_runtime` module. Each helper takes a
single v2 subtree and produces the corresponding runtime shape;
nothing assembles a full legacy `Settings` anymore.
- `settings/mod.rs` doc comment rewritten to describe `Settings` as a
runtime shape, not a resolved parse target. Stage 6.3 deletes it.
fabro-config
- `ConfigLayer::resolve` is gone along with the `TryFrom<ConfigLayer>
for Settings` impls. Consumers call `.into()` for a `SettingsFile`,
or `.as_v2()` to borrow one.
- `fabro_config::server::resolve_storage_dir` now takes `&SettingsFile`.
fabro-server
- `api_server_settings` emits the v2 `SettingsFile` JSON shape
directly instead of bridging to the legacy flat DTO. Stage 6.6
replaces the shape again with an explicit allow-list DTO.
- `serve.rs`: `load_settings` returns `SettingsFile`;
`apply_serve_overrides` / `apply_runtime_settings` mutate v2
subtrees directly; `build_artifact_object_store` walks
`server.artifacts`; `build_legacy_api_settings` projects the v2
auth/listen/api subtrees down to the legacy `ApiSettings` shape for
the (still-legacy) auth resolver.
- `diagnostics::check_crypto` walks `server.auth.api.{jwt,mtls}` and
`server.listen.tls` directly.
- `web_auth.rs` oauth / register / setup-status / auth-me flows all
read `server.web`, `server.integrations.github`, and
`server.auth.web` directly via the v2 accessors. `merge_settings_keys`
now writes v2 TOML (with `[server.web]`, `[server.integrations.github]`,
etc.) instead of the legacy v1 top-level keys, and the register
handler re-parses the freshly-written file back into the in-memory
`SettingsFile` state.
fabro-cli
- `CommandContext::machine_settings` returns `&SettingsFile`.
- `user_config::load_settings` and friends return `SettingsFile`.
- `user_config::resolve_server_target` / `exec_server_target` /
`configured_server_target` walk `cli.target.{http,unix}` directly.
Tests rewritten against v2 TOML fixtures.
- `main.rs` logging init reads `cli.logging.level` / `server.logging.level`
via v2 accessors.
- `commands/exec.rs` reads `cli.exec.{model,agent}` and builds mcps
from `cli.exec.agent.mcps` (falling back to `run.agent.mcps`) via
`to_runtime::bridge_mcp_entry`.
- `commands/pr/mod.rs` calls `github_app_id_str()`.
- `commands/run/create.rs` drops the legacy `.resolve()` call and uses
`Into::<SettingsFile>::into(...)`.
- `commands/config/mod.rs::legacy_settings_to_v2` is now a real
reverse-mapping helper that covers `storage`, `scheduler`,
`integrations.{github,slack}`, `run.model`, `run.inputs`, and
`cli.output.verbosity`. Stage 6.6 deletes it when the API client
returns v2 natively.
- `tests/it/cmd/config.rs` tests now walk the v2 tree directly (via
`cfg.run_model_name_str()`, `cfg.run_inputs()`, `cfg.run_sandbox()`,
`cfg.run_hooks()`, `cfg.run_agent_mcps()`, `cfg.run_prepare_commands()`,
`cfg.server_storage_root_str()`, etc.). The `bridge_to_old` test
helper is gone.
- `tests/it/api/settings.rs` asserts against the v2 JSON shape.
Build, test, and quality gates all green:
- `cargo build --workspace --tests`
- `cargo clippy --workspace -- -D warnings`
- `cargo fmt --check --all`
- `cargo nextest run --workspace`: 3758 / 3758 passed, 182 skipped.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Use a synthetic .map path instead of scanning apps/fabro-web/dist at
runtime, which requires a prior bun build and breaks on fresh checkouts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
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.
Move subprocess workers fully behind the server-owned run store by
switching worker/server coordination to HTTP-backed run events and
control state. Reconcile stale in-flight runs on boot, terminate live
workers during shutdown, and update process titles to reflect server and
worker lifecycle phases.
Default `fabro settings` now resolves effective runtime settings against the
selected server, while `--local` preserves local-only inspection. This also
extracts shared settings resolution logic so CLI output, manifest preparation,
and the `/api/v1/settings` contract stay aligned.
Move integration tests from monolithic api.rs into api/ (single-endpoint
contract tests) and scenario/ (multi-API-step flows), mirroring the CLI's
cmd/ vs scenario/ pattern. Move 3 scheduler-dependent unit tests from
server.rs into it/scenario/ where they get the correct nextest timeout
(kind=test override). Deduplicate shared helpers into helpers.rs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>