Commit graph

25 commits

Author SHA1 Message Date
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]
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
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
0ab27e40e6
Improve hooks docs: multi-layer config, clearer matchers table, sandbox context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 21:52:25 -04:00
Bryan Helmkamp
ec9057a4c6
Add cargo-fmt post_tool_use hook and improve matcher docs
Add a blocking cargo-fmt hook to fabro.toml that auto-formats Rust
files after write_file, edit_file, or apply_patch tool calls. Improve
the hooks documentation with a detailed matcher field reference table,
tool name catalog, cross-field matching caveat, and additional examples.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 20:34:23 -04:00
Bryan Helmkamp
7292ab4079
Update docs for new CLI commands, GitHub token injection, and events
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 18:33:18 -04:00
arc-1e68f1[bot]
b61786ff30
Rename metadata branch from refs/fabro/{run_id} to fabro/meta/{run_id} (#3)
* fabro(01KKS6PG9929P116A2RRKXC738): toolchain (success)

Fabro-Run: 01KKS6PG9929P116A2RRKXC738
Fabro-Completed: 2
Fabro-Checkpoint: a274eab045

⚒️ Generated with [Fabro](https://fabro.sh)

* fabro(01KKS6PG9929P116A2RRKXC738): preflight_compile (success)

Fabro-Run: 01KKS6PG9929P116A2RRKXC738
Fabro-Completed: 3
Fabro-Checkpoint: 8ce709ecdb

⚒️ Generated with [Fabro](https://fabro.sh)

* fabro(01KKS6PG9929P116A2RRKXC738): preflight_lint (success)

Fabro-Run: 01KKS6PG9929P116A2RRKXC738
Fabro-Completed: 4
Fabro-Checkpoint: 4f4c237214

⚒️ Generated with [Fabro](https://fabro.sh)

* fabro(01KKS6PG9929P116A2RRKXC738): implement (success)

Fabro-Run: 01KKS6PG9929P116A2RRKXC738
Fabro-Completed: 5
Fabro-Checkpoint: baf4d48a0f

⚒️ Generated with [Fabro](https://fabro.sh)

* fabro(01KKS6PG9929P116A2RRKXC738): simplify (success)

Fabro-Run: 01KKS6PG9929P116A2RRKXC738
Fabro-Completed: 6
Fabro-Checkpoint: ddc0967c0b

⚒️ Generated with [Fabro](https://fabro.sh)

* fabro(01KKS6PG9929P116A2RRKXC738): verify (success)

Fabro-Run: 01KKS6PG9929P116A2RRKXC738
Fabro-Completed: 7
Fabro-Checkpoint: 2249924bb2

⚒️ 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-15 17:40:51 -04:00
Bryan Helmkamp
35bd79a2ed
Update docs, frontend, marketing, and skills for .fabro extension
Update 47 MDX doc pages, OpenAPI spec, SVG diagram, language
grammar, frontend demo data, marketing page, skills, and README
to use .fabro extension. Add "fabro" to fileTypes in language
grammars. Document stack.child_workflow alongside stack.child_dotfile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:38:25 -04:00
Bryan Helmkamp
28884ae093 rename Arc to Fabro in all Rust crates, symbols, env vars, and supporting files
- Rename 20 crate directories lib/crates/arc-* → fabro-*
- Update all Cargo.toml: crate names, dep paths, feature flags, bin name
- Rename arc_server module → fabro_server in fabro-llm
- ArcError → FabroError across 30+ files
- ARC_VERSION/ARC_GIT_SHA/ARC_BUILD_DATE → FABRO_* constants
- All use/qualified paths: arc_agent:: → fabro_agent::, etc. (~1500 occurrences)
- Env vars ARC_* → FABRO_* in string literals and shell scripts
- String literals: X-Arc-Demo, arc-bot, arc@local, arc-web, arc-mcp, etc.
- Path strings: .arc/ → .fabro/, arc.toml → fabro.toml, refs/arc/ → refs/fabro/
- arc-api.yaml → fabro-api.yaml (OpenAPI spec)
- skills/arc-create-workflow → fabro-create-workflow
- trycmd fixtures: $ arc → $ fabro
- Inline snapshots (insta) updated
- CI, Docker, install.sh, scripts, CLAUDE.md, AGENTS.md
- TypeScript app: env vars, headers, JWT issuer
- Docs: page slugs, git refs, config paths, sandbox names, repo URLs
- Repo references: brynary/arc → fabro-sh/fabro

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:25:58 -04:00
Bryan Helmkamp
d4fe6b72e0 docs: rename Arc to Fabro throughout docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:53:44 -04:00
Bryan Helmkamp
1dcad0529a Split ~/.arc/logs/ into logs/ and runs/
Per-run data now lives in ~/.arc/runs/ while daily CLI log files
stay in ~/.arc/logs/. Renames: logs_root → run_dir (RunConfig field,
Handler trait param, all handlers), logs_dir → run_dir (CLI arg,
local variables), default_logs_base → default_runs_base (path fn).
Adds DB migration 002 to rename workflow_runs.logs_dir → run_dir.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 09:40:03 -04:00
Bryan Helmkamp
ca124638ae Document MCP sandbox transport and workflow-level MCP configuration
- docs/agents/mcp.mdx: Remove pre-release warning. Add sandbox transport
  docs alongside stdio and HTTP. Restructure configuration section to
  cover both cli.toml and run config TOML. Replace filesystem example
  with Playwright browser automation example.
- docs/execution/run-configuration.mdx: Add [mcp_servers] section with
  field reference for all three transport types. Add to full example.
- docs/reference/cli-configuration.mdx: Add sandbox transport subsection.
  Cross-reference workflow-level MCP config.
- docs/integrations/daytona.mdx: Add MCP sandbox transport to feature table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 08:10:05 -04:00
Bryan Helmkamp
36ad1606ee Update docs for tool-level hooks, server mode, and auto-PR
- hooks.mdx: add pre_tool_use/post_tool_use/post_tool_use_failure events,
  tool-specific context fields, matcher support for tool names
- cli.mdx: add --mode and --server-url flags to arc exec
- run-configuration.mdx: add [pull_request] section
- github.mdx: add auto-PR to features table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:49:28 -04:00
Bryan Helmkamp
7f6f356bae TOML Config Format for MCP Servers (#2)
* arc(01KK6WHD2MEDZ0JVYTHEK9HFNF): implement (success)

Arc-Run: 01KK6WHD2MEDZ0JVYTHEK9HFNF
Arc-Completed: 2
Arc-Checkpoint: 25f71de745f9001a09e566706d62a6ac2ea6f827

* arc(01KK6WHD2MEDZ0JVYTHEK9HFNF): simplify (success)

Arc-Run: 01KK6WHD2MEDZ0JVYTHEK9HFNF
Arc-Completed: 3
Arc-Checkpoint: fed4325308110df4799171944ddb5170de59044c

* Fix Rust formatting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: arc <arc@local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:26:46 -04:00
Bryan Helmkamp
1825b61b0e Rename arc agent CLI subcommand to arc exec
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:38:03 -05:00
Bryan Helmkamp
130339ee87 Add filename titles to TOML code blocks in docs
Every TOML example now shows which config file it belongs to
(server.toml, cli.toml, or run.toml) via Mintlify's title annotation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:06:57 -05:00
Bryan Helmkamp
ce80cb6101 Extract outcome and failure_reason from LLM routing directives
The extract_status_fields function recognized "outcome" as a field for
detecting status JSON objects but never read its value — LLM responses
like {"outcome": "fail", "failure_reason": "tests failed"} were silently
ignored and the outcome was always Success.

Now extract_status_fields reads the outcome field to set the node status
and failure_reason to populate the failure detail. Also adds a fallback:
if no routing directives are found in the response text, the handler
reads status.json from the sandbox CWD (written by agents that prefer
file output over inline JSON). Response text always takes priority.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-07 09:38:16 -05:00
Bryan Helmkamp
21f9841623 Fill in tutorials, examples, and reference docs with content and SVGs
- Add SVG workflow diagrams for all tutorials and examples
- Fill in NLSpec Convergence and Semantic Port example content
- Add Solitaire example workflow
- Add error handling sections to tools and subagents docs
- Add context compaction and artifact offloading to context docs
- Add credential redaction note to observability docs
- Add workflow diagram Frame references to tutorials

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-05 22:14:02 -05:00
Bryan Helmkamp
4605f821e8 Add custom TextMate grammar for DOT syntax highlighting in docs
Revert the graphviz language identifier back to dot (Shiki doesn't
bundle either) and register a custom TextMate grammar via Mintlify's
styling.codeblocks.languages.custom config. The grammar (extracted from
apps/arc-web/app/data/dot-grammar.ts) highlights keywords, shape names,
attributes, strings, comments, and operators.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:41:54 -05:00
Bryan Helmkamp
6a98dcc246 Use graphviz language identifier for DOT code blocks, add titles to workflow examples
Changes ```dot to ```graphviz across all docs for better syntax highlighting
in Mintlify (Shiki). Full digraph blocks get a title derived from the workflow
name (e.g. title="hello.dot").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:26:45 -05:00
Bryan Helmkamp
598b5b7d19 Update docs: fill in administration, agents, execution, and reference pages; remove placeholder pages
Remove stub pages (bring-your-own-key, costs, monitoring, usage, artifacts,
ai-tools, extensions, hooks, llms) and flesh out remaining pages with real
content covering advanced setup, security, permissions, MCP, observability,
interviews, environments, CLI reference, architecture, and workflow stages.
Add permission-flow diagram and tutorials section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:25:23 -05:00
Bryan Helmkamp
5bdb67c51e Document agent backends (API vs CLI)
Add Backends section to agents page explaining the two execution
strategies, expand backend attribute descriptions in dot-language
and stylesheet references, and add API-only notes to tools and
sub-agents pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:00:21 -05:00
Bryan Helmkamp
3500d1436b Simplify Skills page, link to Agent Skills spec instead of duplicating
Remove the "Skill file format" and "Creating skills" sections which
duplicated content from the Agent Skills specification. Link to
agentskills.io for the format spec and introduction instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:19:29 -05:00
Bryan Helmkamp
24f0fa7ca0 Add Daytona network access control and fill in execution docs
- Add DaytonaNetwork enum (block/allow_all/allow_list) with custom serde
  Deserialize for TOML string-or-table syntax
- Wire network config through run_config defaults merging and base_params
- Document network access in sandboxing, environments, and run-configuration
- Fill in execution docs: checkpoints, environments, failures, interviews,
  run configuration, observability, retros
- Rename compounding.mdx → retros.mdx, insights.mdx → observability.mdx
- Use DaytonaConfig::default() in tests to reduce boilerplate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:31:19 -05:00
Bryan Helmkamp
d450695a20 Scaffold Mintlify docs site with full navigation structure
Replace boilerplate Mintlify starter with Arc docs outline:
- Switch to almond theme (sidebar search, card-based layout)
- Top nav: Documentation, Guides, API Reference, Changelog
- Documentation sidebar: Getting Started, Core Concepts, Defining
  Workflows, Executing Workflows, Agents, Administration, Deployment,
  Reference
- Guides tab with example workflows
- Get Started button in navbar
- 48 MDX stub pages across 9 directories

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 10:33:09 -05:00