Bryan Helmkamp
3951464325
Bump version to 0.6.0
2026-03-16 23:38:20 -04:00
brynary-fabro[bot]
0530605fdb
Add -q/--quiet to fabro ps ( #64 )
...
Adds a `-q`/`--quiet` flag to `fabro ps`, mirroring the behavior of
`docker ps -q`. When specified, the command outputs only full run IDs,
one per line, with no headers, footers, or "no runs found"
messages—empty output simply means no matching runs exist.
The quiet flag takes precedence over JSON output, and it composes
naturally with other flags like `-a` (e.g., `fabro ps -qa` lists all run
IDs).
### Fabro Details
<details>
<summary>Ran 10 stages in 10m 13s for $1.09</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 0s | – | 0 |
| preflight_compile | 0s | – | 0 |
| preflight_lint | 0s | – | 0 |
| implement | 0s | $0.17 | 0 |
| simplify_opus | 0s | $0.30 | 0 |
| simplify_gemini | 0s | $0.30 | 0 |
| simplify_gpt | 0s | $0.32 | 0 |
| verify | 0s | – | 0 |
| fmt | 0s | – | 0 |
| **Total** | **10m 13s** | **$1.09** | **0** |
</details>
<details>
<summary>Ran <code>ImplementAndSimplify.fabro</code> (13 nodes and 16
edges)</summary>
```dot
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", goal_gate=true, max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh )
---------
Co-authored-by: Fabro <noreply@fabro.sh>
2026-03-16 22:00:20 -04:00
brynary-fabro[bot]
9197895f10
Add Sentry panic reporting to fabro CLI ( #35 )
...
This PR adds Sentry-based panic reporting to the fabro CLI and improves
the reliability of all background telemetry senders. When the CLI
panics, a Sentry event is serialized to a temp file and uploaded by a
fully detached subprocess, giving visibility into crashes that would
otherwise go unnoticed.
The core infrastructure change is a new `spawn_detached` utility that
uses the double-fork pattern on Unix (fork → setsid → close_fd → fork →
exec) to ensure background subprocesses survive parent exit and terminal
close. This replaces the previous simple `Command::spawn()` approach
used by the analytics sender, which was unreliable since the child could
be killed when the parent exits. Both the analytics sender
(`__send_analytics`) and the new panic sender (`__send_panic`) now share
this `spawn_fabro_subcommand` helper.
The panic module installs a hook early in `main()` that captures panic
info, builds a Sentry event with exception details, stacktrace, and OS
context, then spawns a detached `fabro __send_panic` subprocess to
upload it. It respects the telemetry level setting (no-ops when off),
prevents recursion by setting `FABRO_TELEMETRY=off` in the child,
filters benign "Broken pipe" panics from `| head` usage, and uses a
compile-time `SENTRY_DSN` so dev builds without the DSN set are
unaffected.
### Fabro Details
<details>
<summary>Ran 10 stages in 32m 34s for $8.13</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 0s | – | 0 |
| preflight_compile | 0s | – | 0 |
| preflight_lint | 0s | – | 0 |
| implement | 0s | $2.35 | 0 |
| simplify_opus | 0s | $2.23 | 0 |
| simplify_gemini | 0s | $1.75 | 0 |
| simplify_gpt | 0s | $1.80 | 0 |
| verify | 0s | – | 0 |
| fmt | 0s | – | 0 |
| **Total** | **32m 34s** | **$8.13** | **0** |
</details>
<details>
<summary>Ran <code>ImplementAndSimplify.fabro</code> (13 nodes and 16
edges)</summary>
```dot
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", goal_gate=true, max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh )
---------
Co-authored-by: Fabro <noreply@fabro.sh>
2026-03-16 22:00:11 -04:00
brynary-fabro[bot]
9d0a2a9a66
Move sandbox lifecycle into the engine ( #22 )
...
This PR moves sandbox lifecycle management (initialization, setup
commands, devcontainer phases, and cleanup) from the CLI's `run_command`
god function into the workflow engine. Two new engine methods are
introduced: `run_with_lifecycle()` orchestrates sandbox init, fires the
`SandboxReady` hook (now blocking by default), emits a new
`SandboxInitialized` event, handles remote git setup, runs setup
commands and devcontainer lifecycle phases, then delegates to the
existing `run_internal()` graph execution. `cleanup_sandbox()` fires the
`SandboxCleanup` hook and optionally tears down the sandbox. Both
`SandboxReady` and `SandboxCleanup` hook events were previously defined
but never fired — they now fire naturally within the engine alongside
all other hooks.
The CLI is simplified significantly: sandbox record persistence and
progress UI updates are handled via an event listener for
`SandboxInitialized` rather than inline code. The `run_from_branch`
resume path also benefits, gaining hook support and proper cleanup for
free. A new `LifecycleConfig` struct captures setup commands, timeouts,
and devcontainer phases, keeping the engine's API clean. The existing
`run()` method is unchanged, so API server and integration tests
continue working with pre-initialized sandboxes.
The `setup_remote_git` helper is moved from `cli/run.rs` into
`engine.rs` since it only depends on sandbox exec. Config is now passed
by mutable reference to `run_with_lifecycle` so the engine can fill in
remote git fields (base SHA, run branch) that downstream code needs.
Comprehensive tests verify event emission ordering, setup command
execution/failure, and cleanup behavior.
### Fabro Details
<details>
<summary>Ran 10 stages in 53m 27s for $14.42</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 0s | – | 0 |
| preflight_compile | 0s | – | 0 |
| preflight_lint | 0s | – | 0 |
| implement | 0s | $6.22 | 0 |
| simplify_opus | 0s | $2.63 | 0 |
| simplify_gemini | 0s | $2.73 | 0 |
| simplify_gpt | 0s | $2.84 | 0 |
| verify | 0s | – | 0 |
| fmt | 0s | – | 0 |
| **Total** | **53m 27s** | **$14.42** | **0** |
</details>
<details>
<summary>Ran <code>ImplementAndSimplify.fabro</code> (13 nodes and 16
edges)</summary>
```dot
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", goal_gate=true, max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh )
---------
Co-authored-by: Fabro <noreply@fabro.sh>
Co-authored-by: Bryan Helmkamp <bryan@brynary.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:00:05 -04:00
brynary-fabro[bot]
74dae0a342
Refactor: Collapse pull_request fields on RunConfig into Option<PullRequestConfig> ( #21 )
...
This refactoring collapses four flat `pull_request_*` fields on
`RunConfig` (`pull_request_enabled`, `pull_request_draft`,
`pull_request_auto_merge`, `pull_request_merge_strategy`) into a single
`pull_request: Option<PullRequestConfig>` field. This better represents
the natural tree structure of the configuration: `None` means PR
creation is disabled, while `Some(config)` carries all PR settings
directly.
The PR creation logic in `run.rs` is restructured to use `if let
Some(ref pr_cfg) = config.pull_request` instead of checking a boolean
flag, and construction is simplified to filter out disabled configs at
build time via `.filter(|p| p.enabled).cloned()`. All test constructors
across `engine.rs`, `integration.rs`, `daytona_integration.rs`,
`server.rs`, and `manager_loop.rs` are updated from two lines
(`pull_request_enabled: false, pull_request_draft: false/true`) to a
single `pull_request: None`.
### Fabro Details
<details>
<summary>Ran 10 stages in 20m 32s for $6.62</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 0s | – | 0 |
| preflight_compile | 0s | – | 0 |
| preflight_lint | 0s | – | 0 |
| implement | 0s | $1.71 | 0 |
| simplify_opus | 0s | $1.63 | 0 |
| simplify_gemini | 0s | $1.74 | 0 |
| simplify_gpt | 0s | $1.55 | 0 |
| verify | 0s | – | 0 |
| fmt | 0s | – | 0 |
| **Total** | **20m 32s** | **$6.62** | **0** |
</details>
<details>
<summary>Ran <code>ImplementAndSimplify.fabro</code> (13 nodes and 16
edges)</summary>
```dot
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", goal_gate=true, max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh )
---------
Co-authored-by: Fabro <noreply@fabro.sh>
Co-authored-by: Bryan Helmkamp <bryan@brynary.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:55:41 -04:00
brynary-fabro[bot]
469b5d4670
Fix: Stage durations always show 0s in PR descriptions ( #20 )
...
This PR fixes a bug where stage durations in PR descriptions always
displayed `0s`. The root cause was a key mismatch in
`extract_stage_durations()`: the function was building its HashMap using
`node_label` (human-readable names like `"Preflight Compile"`), but all
three lookup sites were querying by `node_id` (DOT graph identifiers
like `"preflight_compile"`). Every lookup missed and fell back to the
default value of `0`.
The fix changes the HashMap key from `node_label` to `node_id` so that
it matches what the callers actually use for lookups. Additionally, the
existing test is updated so that `node_label` and `node_id` values
differ from each other (e.g., `"plan"` vs `"Plan"`), ensuring the test
would have caught this mismatch before the fix rather than silently
passing due to both fields being identical.
### Fabro Details
<details>
<summary>Ran 10 stages in 7m 46s for $1.28</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 0s | – | 0 |
| preflight_compile | 0s | – | 0 |
| preflight_lint | 0s | – | 0 |
| implement | 0s | $0.21 | 0 |
| simplify_opus | 0s | $0.35 | 0 |
| simplify_gemini | 0s | $0.35 | 0 |
| simplify_gpt | 0s | $0.38 | 0 |
| verify | 0s | – | 0 |
| fmt | 0s | – | 0 |
| **Total** | **7m 46s** | **$1.28** | **0** |
</details>
<details>
<summary>Ran <code>ImplementAndSimplify.fabro</code> (13 nodes and 16
edges)</summary>
```dot
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", goal_gate=true, max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh )
---------
Co-authored-by: Fabro <noreply@fabro.sh>
2026-03-16 21:39:01 -04:00
brynary-fabro[bot]
d29c1d817e
Wire up missing hook invocations ( #19 )
...
This PR wires up three `HookEvent` variants—`StageRetrying`,
`ParallelStart`, and `ParallelComplete`—that were defined in the enum
and documented but never actually invoked by the engine. `StageRetrying`
hooks now fire at both retry sites in `execute_with_retry` (error-retry
and explicit-Retry-status paths) immediately before the backoff sleep.
`ParallelStart` and `ParallelComplete` hooks fire in the parallel
handler after their corresponding event emissions, using a new
`EngineServices::run_hooks()` convenience method since the handler
doesn't have direct access to the engine's hook method.
The two remaining unwired events, `SandboxReady` and `SandboxCleanup`,
are marked as reserved with doc comments on the enum variants and
annotated in the docs table, since wiring them requires sandbox
lifecycle changes outside the engine's scope. A small
`HookContext::set_node()` helper is introduced to reduce repeated field
assignment across all hook call sites, and existing
`StageStart`/`StageComplete` hook calls are refactored to use it.
### Fabro Details
<details>
<summary>Ran 10 stages in 25m 6s for $5.60</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 0s | – | 0 |
| preflight_compile | 0s | – | 0 |
| preflight_lint | 0s | – | 0 |
| implement | 0s | $1.04 | 0 |
| simplify_opus | 0s | $1.51 | 0 |
| simplify_gemini | 0s | $1.44 | 0 |
| simplify_gpt | 0s | $1.62 | 0 |
| verify | 0s | – | 0 |
| fmt | 0s | – | 0 |
| **Total** | **25m 6s** | **$5.60** | **0** |
</details>
<details>
<summary>Ran <code>ImplementAndSimplify.fabro</code> (13 nodes and 16
edges)</summary>
```dot
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", goal_gate=true, max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh )
---------
Co-authored-by: Fabro <noreply@fabro.sh>
2026-03-16 21:38:53 -04:00
brynary-fabro[bot]
50c032576d
Style SVG output from fabro graph and API ( #18 )
...
This PR styles the SVG output from `fabro graph` and the API graph
endpoints to match the polished look of the documentation SVGs. It
introduces two internal functions in `graph.rs`:
`inject_dot_style_defaults`, which inserts DOT-level defaults
(transparent background, teal `#357f9e` node strokes, gray `#666666`
edges, Helvetica font) after the first `{` in any DOT source, and
`postprocess_svg`, which removes the Graphviz-generated white background
polygon and injects a `<style>` block with `prefers-color-scheme: dark`
media queries for automatic dark mode support.
The `render_dot` function is updated to apply both transformations (DOT
defaults before rendering, SVG post-processing after), and is made `pub`
so the API layer can reuse it. Both `get_graph` in `server.rs` and
`get_run_graph` in `demo/mod.rs` are simplified from ~30 lines of inline
Graphviz process management down to a single call to a shared
`render_dot_svg` helper that delegates to `render_dot` on a blocking
thread.
Six new unit tests validate the styling pipeline: default injection with
and without braces, white background removal, dark mode style insertion,
and the existing SVG integration test is extended to assert styled
output. PNG output is unaffected by the SVG post-processing step.
### Fabro Details
<details>
<summary>Ran 10 stages in 23m 31s for $5.48</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 0s | – | 0 |
| preflight_compile | 0s | – | 0 |
| preflight_lint | 0s | – | 0 |
| implement | 0s | $1.15 | 0 |
| simplify_opus | 0s | $1.55 | 0 |
| simplify_gemini | 0s | $1.65 | 0 |
| simplify_gpt | 0s | $1.13 | 0 |
| verify | 0s | – | 0 |
| fmt | 0s | – | 0 |
| **Total** | **23m 31s** | **$5.48** | **0** |
</details>
<details>
<summary>Ran <code>ImplementAndSimplify.fabro</code> (13 nodes and 16
edges)</summary>
```dot
digraph ImplementAndSimplify {
graph [
goal="Implement and simplify",
model_stylesheet="
* { backend: api; model: claude-opus-4-6;}
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gemini [label="Simplify (Gemini)", prompt="@prompts/simplify.md", model="gemini-3.1-pro-preview-customtools"]
simplify_gpt [label="Simplify (GPT-54)", prompt="@prompts/simplify.md", model="gpt-54"]
verify [label="Verify", shape=parallelogram, script="cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo fmt --all 2>&1", goal_gate=true, max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=success"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=success"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=success"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gemini -> simplify_gpt -> verify
verify -> fmt [condition="outcome=success"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh )
---------
Co-authored-by: Fabro <noreply@fabro.sh>
Co-authored-by: Bryan Helmkamp <bryan@brynary.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:38:47 -04:00
Bryan Helmkamp
c7c6d2999a
Remove AI slop from introducing-fabro blog post
...
Replace "leveraging" buzzword and "This is the key insight:" trope.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:38:14 -04:00
Bryan Helmkamp
09ee73e1a0
Hide Showcase from homepage navigation
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:34:18 -04:00
Bryan Helmkamp
5de39fc398
Update marketing site fonts to Razor Geometric treatment
...
Switch from Space Grotesk / DM Sans / JetBrains Mono to
Outfit / Lexend / Fira Code for a tighter, sharper aesthetic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:22:14 -04:00
Bryan Helmkamp
f375073355
Rewrite "Introducing Fabro" blog post with founder voice
...
Expanded from a 1-min stub to a full introductory post with
problem framing, workflow graph example, model stylesheet syntax,
verification gates, checkpoint/resume, and install CTA.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:21:24 -04:00
Bryan Helmkamp
f8dc3446a4
Hide Showcase from marketing site navigation
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:19:01 -04:00
Bryan Helmkamp
3e34ad5d78
Record GPT-5.4 20min timeout: 65.7% on SWE-Bench-Lite ($718.62)
...
Best resolve rate at 197/300 but 3.3x more expensive than Opus.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:55:59 -04:00
Bryan Helmkamp
f382f2764f
Showcase: render workflow graphs as SVGs, add nav, fix prompt
...
- Render DOT workflow definitions as visual SVG diagrams at build time
using @viz-js/viz, replacing raw code blocks on show pages and
placeholder first-letter thumbnails on index cards
- Collapse models/skills/languages into a compact metadata strip on
show pages instead of separate boxed sections
- Fix prompt expand/collapse to use a single DOM element with max-height
animation instead of duplicating the text in two swapped containers
- Add prev/next navigation links at the bottom of show pages
- Extract duplicated langIcons data into shared src/lib/langIcons.ts
- Use varied reveal animation types (reveal-scale, reveal-left)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:55:31 -04:00
Bryan Helmkamp
f416643a48
Update roadmap and standardize on Graphviz terminology
...
Roadmap: replace placeholder items with current shipped/building/planned
features. Use real dates for sorting instead of manual sortOrder. Fix
UTC timezone rendering for date display.
Terminology: replace all standalone "DOT" references with "Graphviz" or
"Graphviz DOT" across docs, marketing, README, AGENTS.md, and OpenAPI
spec. Changelogs left unchanged as historical records.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:01:33 -04:00
Bryan Helmkamp
b116c07ea7
Update /discord redirect to use invite link
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 19:50:29 -04:00
Bryan Helmkamp
f80f52920b
Add Showcase section to marketing site
...
Gallery of workflow recipes with index grid and detail pages.
Three sample entries: PR Review Bot, Test Generator, Docs Sync.
Add Roadmap link to shared Nav component and homepage nav.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 19:11:05 -04:00
Bryan Helmkamp
dcad7059d4
Docs: add auto-merge config, auto-merge to GitHub features, turn-level retries
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 19:06:15 -04:00
Bryan Helmkamp
610aff7446
Add March 16 changelog and update March 15 with new entries
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 19:03:47 -04:00
Bryan Helmkamp
aa8ff368df
Roadmap: replace inline shipped descriptions with hover tooltip
...
Saves vertical space by showing only date + title in shipped rows,
with an info icon that reveals the description on hover.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 18:27:58 -04:00
Bryan Helmkamp
124894d0eb
Add blog and redesign blog/roadmap pages
...
- Add blog collection (content config, prose styles, introducing-fabro post)
- Add Blog link to homepage nav and footer
- Make Layout description prop dynamic for per-page meta/OG tags
- Extract shared Nav, Footer, PageScripts components from duplicated markup
- Blog index: compact header, featured card for latest post, row list for older posts
- Blog post: clean reading surface (no grid/noise overlay), reading time, better header
- Roadmap: improved card contrast with tinted backgrounds, conditional section rendering
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 18:26:10 -04:00
Bryan Helmkamp
f13310dfc4
Reduce default patch generation concurrency to 75
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 16:05:24 -04:00
Bryan Helmkamp
1af5193a82
Handle assistant output replay on stream retries
2026-03-16 15:59:00 -04:00
Bryan Helmkamp
335da2318d
Fix typos in docs: "appliction" and "an Fabro"
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 15:57:33 -04:00
Bryan Helmkamp
b907896907
Fix broken link and stale badge label in README
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 15:25:31 -04:00
Bryan Helmkamp
76dc5f72a4
Add turn-level retry for stream-ended-without-Finish errors
...
When an LLM stream drops mid-response (e.g. under high concurrency with
OpenAI), retry the same turn up to 3 times instead of failing the entire
agent session. Conversation history is preserved across retries.
Previously this killed the whole stage and restarted from scratch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 15:16:35 -04:00
Bryan Helmkamp
b18521058a
Record Opus 4.6 20min timeout: 58.0% on SWE-Bench-Lite ($218.65)
...
100% patch rate, 0 timeouts. Only +1 instance over Sonnet at 4x the cost.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 14:43:20 -04:00
Bryan Helmkamp
cf77d2b19f
Update install instructions to show Claude Code, Codex, and Bash methods
...
Match the marketing website's tabbed install widget across README, docs
quick-start, and CLAUDE.md. Add marketing site build/deploy commands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 14:03:53 -04:00
Bryan Helmkamp
29cf519e99
Add tabbed install widget (Claude/Codex/Bash) with copy buttons, show hero screenshot on load
...
Replace single curl command with a tabbed install widget defaulting to Claude,
with Codex and Bash alternatives. Each tab has a copy-to-clipboard button.
Remove scroll-reveal animation from hero screenshot so it's visible immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:56:42 -04:00
Bryan Helmkamp
7799d59514
Record Sonnet 4.6 20min timeout: 57.7% on SWE-Bench-Lite ($55.22)
...
20min timeout vs 10min: 173 vs 167 resolved (+6), patch rate 99% vs 94%.
Also fixes: revert to v4 snapshots, concurrency default to 100, preflight
uses actual 4 CPU per sandbox.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:36:26 -04:00
Bryan Helmkamp
9c011cc722
Move install files to apps/marketing/public, symlink from repo root
...
Vercel deploys only the apps/marketing/ subtree, so the real files
need to live there. Repo root now symlinks into marketing/public.
Also add .vercel to gitignore.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:23:58 -04:00
Bryan Helmkamp
fec037c546
Temporarily hide Roadmap from nav while content is being written
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:51:55 -04:00
Bryan Helmkamp
08b74863fa
Improve marketing site mobile layout: reduce hero top spacing and hide curl command
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:46:22 -04:00
Bryan Helmkamp
4cd9e301ea
Fix snapshot CPU mismatch: use v4 snapshots (4 CPU), reduce concurrency to 100
...
Daytona bakes CPU/memory at snapshot creation time. v4 snapshots have
4 CPU / 8 GB. Preflight now checks against 4 CPU per sandbox.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:44:14 -04:00
Bryan Helmkamp
33a2d32fae
Reduce default concurrency to 150, increase default timeout to 20min
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:32:18 -04:00
Bryan Helmkamp
684f4070e0
Add llms.txt and additional meta tags for marketing site
...
- Add llms.txt with structured overview of Fabro docs for LLM consumption
- Add canonical link, application-name, apple-mobile-web-app-title
- Add twitter:image dimensions
- Make og:url dynamic per page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:30:16 -04:00
Bryan Helmkamp
fe6ce15c20
Add OG image and meta tags for link sharing, remove comma from tagline
...
- Add 1200x630 branded OG image matching Mintlify docs card style
- Add Open Graph and Twitter Card meta tags to Layout.astro
- Save og-image-template.html for easy regeneration
- Remove comma from "open source, dark software factory" everywhere
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:24:58 -04:00
Bryan Helmkamp
1a258242bd
Fix marketing site mobile layout: responsive nav and content overflow
...
Nav links, icons, and CTA button overflowed the viewport on mobile.
Text in Workflow-as-Code and Multi-model sections was clipped because
wide SVG/pre children caused CSS grid blowout (min-width: auto default).
- Add hamburger menu for mobile nav on both pages (hidden md:, toggle JS)
- Add overflow-x-hidden to html/body/main to prevent horizontal scroll
- Add .grid > * { min-width: 0 } to prevent grid children from expanding
beyond their container
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:23:35 -04:00
Bryan Helmkamp
8101f948fc
Add Daytona CPU preflight check before starting eval runs
...
Checks running sandboxes against the 500 CPU org limit with 20% buffer.
Exits with a suggested --max-workers value if capacity is insufficient.
Default concurrency set to 200 (safe with 2 CPU per sandbox).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:20:36 -04:00
Bryan Helmkamp
6c596fe027
Migrate roadmap data to Astro content collections
...
Replace inline arrays with a `roadmap` collection using glob loader
and Zod schema. Each item is a YAML file in src/content/roadmap/ with
title, description, status, date, and sortOrder fields.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:17:31 -04:00
Bryan Helmkamp
6f5b5daeba
Add REPL Handoff example workflow to docs
...
Documents the pattern of planning interactively in Claude Code and
delegating implementation to Fabro via the /fabro-implement slash
command, with multi-model simplification and verification gates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:13:05 -04:00
Bryan Helmkamp
571dac721d
Add /roadmap page to marketing site with timeline layout
...
Shipped/Building/Next sections with sample content, vertical timeline,
scroll reveal animations, and matching dark factory aesthetic. Linked
from top nav and footer on both pages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:04:48 -04:00
Bryan Helmkamp
322be8a0b8
Update marketing site: copyright to Qlty Software Inc. and allow ngrok hosts
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:58:29 -04:00
Bryan Helmkamp
b45483ae4a
Record timeout and sandbox resources in scoreboard metadata
...
Adds --timeout, --sandbox-cpu, --sandbox-memory flags to record_results.py.
Re-recorded both existing runs with the new fields.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:24:56 -04:00
Bryan Helmkamp
002468316d
Record Sonnet 4.6 baseline: 55.7% on SWE-Bench-Lite ($39.78)
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:23:23 -04:00
Bryan Helmkamp
951a37faf8
Add install.md for AI agent-driven installation
...
Self-contained installation instructions following the install.md spec.
Decoupled from install.sh — handles platform detection, binary download,
PATH setup in shell dotfiles, and verification independently. Prompts
the user to run `fabro install` interactively to complete setup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:07:21 -04:00
Bryan Helmkamp
811f10f586
Skip shell config modification in non-interactive mode
...
Prevents install.sh from silently writing to dotfiles (.zshrc, .bashrc,
config.fish) when run non-interactively (e.g. by an AI coding agent).
In non-interactive mode, it now prints the manual PATH export instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:01:42 -04:00
Bryan Helmkamp
4245ab86a4
Add status.py for quick progress checks on generation and eval runs
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:59:49 -04:00
Bryan Helmkamp
4520fd2001
Add Discord and Changelog links to marketing site nav and footer
...
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:56:10 -04:00