Commit graph

76 commits

Author SHA1 Message Date
Bryan Helmkamp
46232503dc
fix(api): resolve build spec path at runtime 2026-04-07 23:05:07 -04:00
Bryan Helmkamp
5ced931d1a
feat(artifacts): finish object-backed artifact uploads
Add scoped worker upload tokens and HTTP artifact upload clients.

Support manifest-first multipart stage artifact uploads with validation and checksums.

Gate artifact reads by run capability while preserving legacy scratch fallback.
2026-04-07 16:56:37 -04:00
Bryan Helmkamp
35593d0a11
refactor(storage): unify scratch paths and key schema
- 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
2026-04-06 10:13:37 -04:00
Bryan Helmkamp
8d2a3220f7
Simplify: rename internal AggregateUsageTotals to UsageAccumulator, add TODO
Eliminates confusing alias (`ApiAggregateUsageTotals`) by giving the
internal accumulator struct a distinct name. Adds a TODO for removing
the OAS 3.1→3.0 patch when progenitor gains 3.1 support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:24:36 -07:00
Bryan Helmkamp
a02148aacd
Rename fabro-api-types to fabro-api with progenitor client generation
Replace typify-only type generation with progenitor, which generates both
Rust types (in a `types` module) and a reqwest-based HTTP client from the
OpenAPI spec. Also upgrades reqwest 0.12→0.13 and rmcp 0.15→1.3 to align
dependency versions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:17:27 -07:00
Bryan Helmkamp
9a078df89c
Rename fabro-api crate to fabro-server
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:09 -04:00
Bryan Helmkamp
200a580009
Configure SlateDB flush_interval to 5ms for local storage
SlateDB defaults to 100ms flush_interval (tuned for S3 cost). For
local/in-memory object stores this adds unnecessary write latency.
Pass flush_interval through SlateStore::new() so callers control
the setting, and switch open_db() to use Db::builder().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:09 -04:00
Bryan Helmkamp
4301c34c81
Wire workflows and CLI to fabro-store 2026-03-29 13:47:09 -04:00
Bryan Helmkamp
48ea1cc4de
Consolidate integration tests under tests/it 2026-03-29 13:47:09 -04:00
Bryan Helmkamp
d97b82df65
Centralize sandbox variant handling 2026-03-29 13:47:09 -04:00
Bryan Helmkamp
007d716f2b
Rename *config* variables/params that hold *Settings types
Local variables and function parameters named with "config" but holding
*Settings types (FabroSettings, TlsSettings, ApiSettings, LlmSettings)
are renamed to use "settings" for consistency with the type system.
Module paths (cli_config::) and struct fields are unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:09 -04:00
Bryan Helmkamp
2708e2eb54
Enable 7 additional pedantic clippy lints
Enables char_lit_as_u8, collapsible_else_if, collapsible_if,
map_unwrap_or, match_same_arms, used_underscore_binding, and
if_not_else. Fixes all violations: combines duplicate match arms,
renames underscore-prefixed bindings that are actually used, rewrites
if-not-else patterns, and applies map_or where appropriate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
91a43854b2
Enable cast_possible_wrap clippy lint and fix violations
Replaces 14 unsigned-to-signed `as` casts with try_from().unwrap()
to panic on overflow instead of silently wrapping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
2f4fc23f3d
Enable additional pedantic clippy lints and fix violations
Enables cast_possible_truncation, cast_sign_loss, items_after_statements,
needless_pass_by_value, return_self_not_must_use, uninlined_format_args,
unreadable_literal, and unnested_or_patterns. Keeps doc_markdown disabled.

Replaces unsafe `as` casts with try_from().unwrap() throughout, using
#[allow] only for f64-to-integer casts which have no try_from equivalent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
1dc0ebce52
Enable clippy pedantic lints and restriction lints workspace-wide
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>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
5c215033c1
Apply rustfmt 2024 style edition across workspace
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
891957e29b
Enforce no-inline-qualified-paths via clippy absolute_paths lint
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>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
50041fb261
Enforce no-wildcard-imports via clippy workspace lint
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>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
b032ae32b4
Create fabro-types and rewire shared types 2026-03-29 13:47:08 -04:00
Bryan Helmkamp
8b148d06e4
Rename fabro-types to fabro-api-types
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>
2026-03-29 13:47:08 -04:00
Bryan Helmkamp
6a0f571571
Refactor workflow operations and config resolution 2026-03-29 13:47:07 -04:00
Bryan Helmkamp
dd815a3ab3
Tighten workflows request context and launcher cleanup 2026-03-29 13:47:07 -04:00
Bryan Helmkamp
25df708760
Thin CLI run commands and move execution into workflows operations 2026-03-29 13:47:07 -04:00
Bryan Helmkamp
33f4da33c1
Clean up resolved settings interfaces 2026-03-29 13:47:07 -04:00
Bryan Helmkamp
8a256bb68e
Refactor config layering into combine plus settings 2026-03-29 13:47:07 -04:00
Bryan Helmkamp
126ece3d71
Rename --run-dir to --storage-dir, unify with data_dir
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>
2026-03-29 13:47:07 -04:00
Bryan Helmkamp
833574ec4b
Add goal_file and labels to FabroConfig
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>
2026-03-29 13:47:07 -04:00
Bryan Helmkamp
0e076d5594
Fix verification regressions after runtime init refactor 2026-03-29 13:47:07 -04:00
Bryan Helmkamp
205d40d687
Refactor workflow runtime initialization 2026-03-29 13:47:07 -04:00
Bryan Helmkamp
1a91a9b916
refactor: rename local variables/fields to align with Options suffix
Follow-up to f37345d5. 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>
2026-03-29 13:47:07 -04:00
Bryan Helmkamp
f3bc47e9f0
refactor: rename Settings/Config structs to Options suffix
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>
2026-03-29 13:47:07 -04:00
Bryan Helmkamp
a8fa5256b4
refactor(operations): make create own the full create lifecycle
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>
2026-03-29 13:47:07 -04:00
Bryan Helmkamp
b57bc52416
Add workflow persist stage 2026-03-29 13:47:06 -04:00
Bryan Helmkamp
2203bb8d9e
refactor(sandbox): move SandboxProvider from fabro-workflows to fabro-sandbox
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>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
1dfcc699c6
refactor(workflows): merge cost.rs into outcome.rs
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>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
365461e51d
refactor(workflows): move checkpoint, run_record, start_record, sandbox_record into records/
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>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
0c5bbf5bc1
refactor(graphviz): move graph_render module from fabro-workflows to fabro-graphviz
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
937ff79575
style: sort import statements alphabetically
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
6fae59a9a5
refactor(workflows): move backend module to handler/llm
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>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
83161d92d6
refactor(workflows): remove legacy engine module 2026-03-29 13:47:06 -04:00
Bryan Helmkamp
6ba28531ad
Refactor workflow lifecycle into operations 2026-03-29 13:47:06 -04:00
Bryan Helmkamp
cc7ab268aa
Clean up RunSettings migration: fix naming, dedup, error handling
- 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>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
7b7a7d829b
Replace RunConfig with RunSettings 2026-03-29 13:47:06 -04:00
Bryan Helmkamp
f487fc0959
Align run persistence with run record plan 2026-03-29 13:47:06 -04:00
Bryan Helmkamp
88ec53e632
Complete remaining RunRecord plan gaps: run_from_record, TOML rename, API RunRecord
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>
2026-03-29 13:47:06 -04:00
Bryan Helmkamp
790d8f27e2
Unify CliConfig, ServerConfig, ProjectConfig, WorkflowRunConfig, RunDefaults into FabroConfig
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>
2026-03-29 13:47:05 -04:00
Bryan Helmkamp
50b1776607
Remove dead selected_options field from Answer struct
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>
2026-03-23 16:07:26 -04:00
Bryan Helmkamp
0acda783b1
Add ReasoningEffort enum to replace raw Option<String>
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>
2026-03-23 12:50:42 -04:00
Bryan Helmkamp
c7703fc9a0
Flatten LanguageModel trait + ModelInfo into struct Model
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>
2026-03-23 11:48:55 -04:00
Bryan Helmkamp
d9b00ec8bc
Redesign fabro-model with LanguageModel trait, Catalog struct, and ModelRef (#121)
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>
2026-03-23 11:15:40 -04:00