Adopts uv's clippy lint configuration: pedantic group at warn priority,
with noisy lints allowed, plus restriction lints for print/dbg/exit/use_self.
Fixes all violations across the workspace.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add clippy.toml with absolute-paths-max-segments = 2 (allowing std/core/alloc)
and enable the absolute_paths = "warn" lint workspace-wide. Fix all ~300
violations across the codebase: replace 3+-segment inline paths with use
statements so call sites read as operations::create() rather than
fabro_workflows::operations::create(). The demo module gets an allow
attribute since it constructs many API types by design.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Configure clippy `wildcard_imports = "warn"` at the workspace level and
opt all 28 crates in via `[lints] workspace = true`. Fix the three
production glob imports that triggered warnings: fabro-sandbox
read_guard, fabro-cli main, and fabro-api demo module (allowed via
attribute since it constructs many API types by design). Document the
import style convention in CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Better reflects that this crate contains auto-generated types scoped
to the API layer. Pure rename with no behavior change.
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>
Allow workflow authors to set default goal files and labels in
workflow.toml/fabro.toml, reducing repetitive CLI flags. CLI flags
override config values; labels are deep-merged with CLI winning on
key collision.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Follow-up to fafc0a3c. Renames local variables, function parameters,
and struct fields that hold renamed types (ExecutorOptions, RunCreateOptions,
RunOptions) from config/settings to options/run_options for consistency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Standardize naming so all "bag of options" structs use the Options
suffix: ExecutorSettings→ExecutorOptions, RunSettings→RunOptions,
GitCheckpointSettings→GitCheckpointOptions, LifecycleConfig→LifecycleOptions,
RunCreateSettings→RunCreateOptions, StartRetroConfig→StartRetroOptions,
StartFinalizeConfig→StartFinalizeOptions, AutoMergeConfig→AutoMergeOptions.
Also renames the run_settings module to run_options.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
operations::create now handles the full pipeline: var expansion, parse,
goal override, transform, validate, config normalization, and persist.
This eliminates duplicated RunRecord construction and pipeline::persist
calls across CLI and API callers.
Key changes:
- Rename operations::create → validate, CreateOptions → ValidateOptions
- New operations::create returns Persisted, with RunCreateSettings
- Add ValidationFailed error variant with diagnostics
- Move normalize_config, default_run_dir into operations
- Delete prepare_workflow, PreparedWorkflow, CliFlags from CLI
- Make pipeline::persist and types module pub(crate)
- API catches both Parse and ValidationFailed as 400
- CLI prints diagnostics directly from error (no re-validation)
- ExecutionOverrides struct replaces 9-param function
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The enum had zero internal usage in fabro-workflows and naturally belongs
in fabro-sandbox alongside the sandbox implementations. Removed cfg
gates from the Exe variant (it's just a tag) and added non-exedev
fallback arms in fabro-cli to handle feature unification from fabro-api.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Colocate compute_stage_cost and format_cost with StageUsage, eliminating a
thin module that only imported from outcome.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidate all record types under the records module. Files are renamed
to drop the _record suffix (run_record→run, start_record→start,
sandbox_record→sandbox) since the module path provides that context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-locate LLM backend implementations (AgentApiBackend, AgentCliBackend,
BackendRouter) under handler/ since they implement the CodergenBackend
trait defined in handler/agent.rs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename `settings: mut config` binding to `mut settings` in resume.rs
and update all 8 downstream references
- Deduplicate normalize_config call in run.rs by reusing the result
computed for RunRecord
- Replace expect() with graceful error handling when loading RunRecord
in the API server's execute_run
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 5: Rename debug artifacts from run.toml/graph.fabro to
workflow.toml/workflow.fabro. Change write_run_config_snapshot to
byte-for-byte copy of the original TOML instead of re-serialization.
Phase 6: Add run_from_record() that builds execution state directly
from a RunRecord, bypassing prepare_workflow(). Refactor run_command
into run_command + run_command_impl to share execution logic. Simplify
run_engine_entrypoint to call run_from_record() instead of
reconstructing RunArgs and re-parsing the workflow.
Step 7k: Write RunRecord in the API server's execute_run() for
observability, enabling fabro ps/inspect for API-initiated runs.
Fix stale manifest.json reference in docs/agents/outputs.mdx.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace five config types with a single FabroConfig superset type. All
loading functions (load_cli_config, load_server_config, load_run_config,
parse_project_config) now return FabroConfig. This eliminates the
run_defaults indirection, into_run_defaults() conversion, and
apply_defaults() bridging method in favor of a single merge_overlay()
that works across all config layers (CLI → project → workflow).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The field was populated in constructors but never read by any code.
Selected keys are already carried by AnswerValue::MultiSelected(Vec<String>),
making this field redundant. Also removes the unused options parameter from
Answer::multi_selected().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces a typed ReasoningEffort enum (Low, Medium, High) with
serde, Display, and FromStr support. Updates Request, GenerateParams,
and SessionConfig to use Option<ReasoningEffort> instead of
Option<String>. Aligns with spec change removing "none" as a valid
reasoning_effort value.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete the single-implementor LanguageModel trait and merge its methods
into inherent impl on a renamed Model struct. Change provider field from
String to Provider enum, eliminating constant string↔enum conversions
across the codebase. Fix Provider serde attributes so OpenAi serializes
as "openai" (not "open_ai") to match catalog.json.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce OOP API for the model catalog: LanguageModel trait with blanket
impl on ModelInfo, Catalog struct with typed methods (get, list,
default_for_provider, closest, build_fallback_chain, etc.), ModelRef enum
replacing ModelId, and Provider::OpenAiCompatible variant. Migrate all
callers across the workspace to use Catalog::builtin() and remove the old
free-function API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract the Sandbox trait, types, and all sandbox implementations from
fabro-agent and four separate crates (fabro-exe, fabro-ssh, fabro-sprites,
fabro-daytona) into a single fabro-sandbox crate. This cleans up the
dependency graph — implementation crates no longer pull in the full
fabro-agent just for the trait.
The new crate uses feature flags (local, docker, ssh, exe, sprites,
daytona, test-support) to gate each implementation. The shell_quote()
helper is unified into a single shared implementation, eliminating four
duplicate copies.
fabro-agent now re-exports all sandbox types from fabro-sandbox for
backward compatibility. The four absorbed crates are removed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The DaytonaConfig struct had a skip_clone field that was missing from
both the OpenAPI spec and the conformance test initializer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two Daytona integration tests used std::env::set_current_dir to a temp
directory so detect_repo_info() would fail and skip cloning. Since cwd
is process-global, this poisoned concurrent tests. Replace with an
explicit skip_clone config flag that skips repo detection and cloning
during sandbox initialization.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fabro-api doesn't use `SandboxProvider::Exe` but was unconditionally
enabling `exedev` on fabro-workflows. Cargo feature unification made
the `Exe` variant exist while fabro-cli's cfg-gated match arms were
inactive, causing non-exhaustive pattern errors in workspace builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the self-contained hooks module (~2900 LOC) into its own crate to
clarify the dependency graph and make the hook system independently
reusable. The set_node convenience method is inlined at its two call
sites in parallel.rs since it depends on fabro-graphviz types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The interviewer module (trait + 7 implementations for human-in-the-loop
interactions) had zero dependencies on fabro-workflows internals, making
it a clean extraction. Consumers (fabro-api, fabro-slack) now depend on
fabro-interview directly instead of reaching through fabro-workflows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move DaytonaSandbox into its own crate, matching the pattern used by
fabro-exe, fabro-sprites, and fabro-ssh. The new crate internalizes
daytona_sdk::Client creation so callers never touch daytona-sdk directly:
- new() is now async and creates the client internally
- reconnect(name) replaces from_existing() + manual client/get boilerplate
- daytona-sdk and daytona-api-client removed as fabro-workflows dependencies
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move retro.rs and retro_agent.rs into a new fabro-retro crate to reduce
the size of fabro-workflows and clarify domain boundaries.
Key design changes:
- Add CompletedStage struct as a flat DTO that decouples retro derivation
from Checkpoint/Outcome types in the workflow engine
- derive_retro now takes Vec<CompletedStage> (owned) instead of &Checkpoint
- run_retro_agent takes an event_callback closure instead of EventEmitter,
pushing event filtering to the caller
- Shared build_completed_stages() in fabro-workflows::lib converts
Checkpoint → Vec<CompletedStage> for both run.rs and server.rs callers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the self-contained graph/ and parser/ modules into a new
fabro-graphviz crate so the Graphviz DOT parser can be used without
pulling in the full workflow engine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>