From b604bc4b600c7c57fee551632f18ecbb53216bd2 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 15 Mar 2026 20:36:32 -0400 Subject: [PATCH] Designate retros as experimental, disable by default via [features] flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move retro control from [fabro] retro to [features] retros in project config. Default changes from true to false — retros are now opt-in. Add retros field to server config Features struct, OpenAPI spec, TypeScript client, and web app config. Update docs with experimental warning and new enablement instructions. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/fabro-web/app/lib/config.server.ts | 2 + docs/administration/server-configuration.mdx | 14 +++++++ docs/api-reference/fabro-api.yaml | 3 ++ docs/execution/retros.mdx | 27 +++++++++---- lib/crates/fabro-api/src/demo/mod.rs | 1 + .../fabro-api/tests/openapi_conformance.rs | 1 + .../fabro-workflows/src/cli/project_config.rs | 38 ++++++++++++------- .../fabro-api-client/src/models/features.ts | 4 ++ 8 files changed, 68 insertions(+), 22 deletions(-) diff --git a/apps/fabro-web/app/lib/config.server.ts b/apps/fabro-web/app/lib/config.server.ts index dc22d99c1..f5d75b283 100644 --- a/apps/fabro-web/app/lib/config.server.ts +++ b/apps/fabro-web/app/lib/config.server.ts @@ -22,6 +22,7 @@ interface GitConfig { interface Features { session_sandboxes: boolean; + retros: boolean; } interface WebConfig { @@ -60,6 +61,7 @@ const GIT_DEFAULTS: GitConfig = { const FEATURES_DEFAULTS: Features = { session_sandboxes: false, + retros: false, }; export const FABRO_CONFIG_PATH = join(homedir(), ".fabro", "server.toml"); diff --git a/docs/administration/server-configuration.mdx b/docs/administration/server-configuration.mdx index 80d2d56df..8d58899e6 100644 --- a/docs/administration/server-configuration.mdx +++ b/docs/administration/server-configuration.mdx @@ -71,6 +71,9 @@ auto_stop_interval = 60 [sandbox.daytona.labels] team = "platform" +[features] +retros = true + [checkpoint] exclude_globs = ["**/node_modules/**", "**/.cache/**"] @@ -138,6 +141,17 @@ Configure checkpoint behavior for all runs. Exclude globs from `server.toml` and run configs are merged (union, deduplicated). See [Run Configuration — Checkpoint](/execution/run-configuration#checkpoint) for per-run configuration. +### `[features]` section + +Toggle experimental or opt-in features. All features default to `false`. + +| Key | Description | +|---|---| +| `retros` | Enable automatic [retro](/execution/retros) generation after workflow runs (experimental) | +| `session_sandboxes` | Enable session sandboxes in the web UI | + +The same `[features]` section can be set in `fabro.toml` (project-level) to enable features per-project. + ## Environment variables Fabro reads environment variables from a `.env` file in the working directory (if present) and from the shell environment. Provider API keys are required for the models you want to use; everything else is optional. diff --git a/docs/api-reference/fabro-api.yaml b/docs/api-reference/fabro-api.yaml index a50736272..800d0d69b 100644 --- a/docs/api-reference/fabro-api.yaml +++ b/docs/api-reference/fabro-api.yaml @@ -4505,6 +4505,9 @@ components: session_sandboxes: type: boolean description: Enable session sandboxes. + retros: + type: boolean + description: "Experimental: enable automatic retro generation after workflow runs." # ── Discovery Schemas ──────────────────────────────────────────────── diff --git a/docs/execution/retros.mdx b/docs/execution/retros.mdx index 2ac396474..5720c9607 100644 --- a/docs/execution/retros.mdx +++ b/docs/execution/retros.mdx @@ -3,7 +3,11 @@ title: "Retros" description: "Automatic retrospectives that analyze every workflow run" --- -After every workflow run, Fabro generates a **retro** — a structured retrospective that captures what happened, what went well, and what didn't. Retros combine deterministic metrics extracted from the run's checkpoint with a qualitative narrative produced by an LLM agent that analyzes the full event stream. + +**Experimental feature.** Retros are disabled by default. Enable them with `[features] retros = true` in your project config or server config. + + +After every workflow run, Fabro can generate a **retro** — a structured retrospective that captures what happened, what went well, and what didn't. Retros combine deterministic metrics extracted from the run's checkpoint with a qualitative narrative produced by an LLM agent that analyzes the full event stream. The goal is continuous improvement. Retros give you a searchable history of how your workflows perform over time, surface friction patterns that would otherwise go unnoticed, and identify follow-up work before it falls through the cracks. @@ -116,19 +120,26 @@ Retro: smooth — Successfully implemented the feature Retro saved to ~/fabro-logs/01JKXYZ.../retro.json ``` -To skip retro generation for a single run, pass `--no-retro`: +To enable retros for your project, set `retros = true` in the `[features]` section of your `fabro.toml`: + +```toml title="fabro.toml" +version = 1 + +[features] +retros = true +``` + +To skip retro generation for a single run when retros are enabled, pass `--no-retro`: ```bash fabro run workflow.fabro --no-retro ``` -To disable retros project-wide, set `retro = false` in your `fabro.toml`: +Retros can also be enabled server-wide in `server.toml`: -```toml title="fabro.toml" -version = 1 - -[fabro] -retro = false +```toml title="server.toml" +[features] +retros = true ``` ### API diff --git a/lib/crates/fabro-api/src/demo/mod.rs b/lib/crates/fabro-api/src/demo/mod.rs index c64b32a9c..d056854ff 100644 --- a/lib/crates/fabro-api/src/demo/mod.rs +++ b/lib/crates/fabro-api/src/demo/mod.rs @@ -3284,6 +3284,7 @@ mod settings { }, features: Features { session_sandboxes: false, + retros: false, }, log: Default::default(), run_defaults: fabro_workflows::cli::run_config::RunDefaults { diff --git a/lib/crates/fabro-api/tests/openapi_conformance.rs b/lib/crates/fabro-api/tests/openapi_conformance.rs index 2ffb44ac2..b4c144cff 100644 --- a/lib/crates/fabro-api/tests/openapi_conformance.rs +++ b/lib/crates/fabro-api/tests/openapi_conformance.rs @@ -272,6 +272,7 @@ fn fully_populated_server_config() -> ServerConfig { }, features: Features { session_sandboxes: true, + retros: false, }, log: LogConfig { level: Some("debug".into()), diff --git a/lib/crates/fabro-workflows/src/cli/project_config.rs b/lib/crates/fabro-workflows/src/cli/project_config.rs index 43c66e5f5..a4ccb2367 100644 --- a/lib/crates/fabro-workflows/src/cli/project_config.rs +++ b/lib/crates/fabro-workflows/src/cli/project_config.rs @@ -19,6 +19,8 @@ pub struct ProjectConfig { pub version: u32, #[serde(default)] pub fabro: ProjectFabroConfig, + #[serde(default)] + pub features: ProjectFeatures, #[serde(alias = "directory")] pub work_dir: Option, pub llm: Option, @@ -60,27 +62,29 @@ impl ProjectConfig { pub struct ProjectFabroConfig { #[serde(default = "default_root")] pub root: String, - #[serde(default = "default_retro")] - pub retro: bool, } fn default_root() -> String { ".".to_string() } -fn default_retro() -> bool { - true -} - impl Default for ProjectFabroConfig { fn default() -> Self { Self { root: default_root(), - retro: default_retro(), } } } +/// Feature flags for the project. All features default to `false` (opt-in). +#[derive(Debug, Default, Deserialize, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ProjectFeatures { + /// Experimental: enable automatic retro generation after workflow runs. + #[serde(default)] + pub retros: bool, +} + /// Parse a project config from a TOML string. pub fn parse_project_config(content: &str) -> anyhow::Result { let config: ProjectConfig = @@ -342,12 +346,13 @@ fn resolve_workflow_from( } /// Check whether retros are enabled in the project config. -/// Returns `true` (the default) if no config is found or on error. +/// Returns `false` (the default) if no config is found or on error. +/// Retros are an experimental feature gated behind `[features] retros = true`. pub fn is_retro_enabled() -> bool { let start = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); match discover_project_config(&start) { - Ok(Some((_path, config))) => config.fabro.retro, - _ => true, + Ok(Some((_path, config))) => config.features.retros, + _ => false, } } @@ -375,7 +380,6 @@ mod tests { version: 1, fabro: ProjectFabroConfig { root: ".".to_string(), - retro: true, }, ..Default::default() } @@ -389,9 +393,15 @@ mod tests { } #[test] - fn parse_retro_false() { - let config = parse_project_config("version = 1\n[fabro]\nretro = false\n").unwrap(); - assert!(!config.fabro.retro); + fn parse_retros_default_false() { + let config = parse_project_config("version = 1\n").unwrap(); + assert!(!config.features.retros); + } + + #[test] + fn parse_retros_enabled() { + let config = parse_project_config("version = 1\n[features]\nretros = true\n").unwrap(); + assert!(config.features.retros); } #[test] diff --git a/lib/packages/fabro-api-client/src/models/features.ts b/lib/packages/fabro-api-client/src/models/features.ts index 75e01c2cf..ee3916a3e 100644 --- a/lib/packages/fabro-api-client/src/models/features.ts +++ b/lib/packages/fabro-api-client/src/models/features.ts @@ -22,5 +22,9 @@ export interface Features { * Enable session sandboxes. */ 'session_sandboxes'?: boolean; + /** + * Experimental: enable automatic retro generation after workflow runs. + */ + 'retros'?: boolean; }