Commit graph

1144 commits

Author SHA1 Message Date
Bryan Helmkamp
d5236dcda2
Fix doctor trycmd test: move env vars to [env.add] section
trycmd's Env struct requires env vars under [env.add], not directly
under [env]. Vars placed directly under [env] are silently ignored by
serde, so the subprocess ran with a fully cleared env. On CI this caused
dirs::home_dir() to fall back to passwd, loading the real cli.toml
(with app_id) but without GITHUB_APP_PRIVATE_KEY → partial config error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 17:28:44 -04:00
Bryan Helmkamp
1e7fd59c69
Add fabro run --detach to fork workflows as background processes
Pre-generates a ULID in the parent, passes it to the child via hidden
`--run-id` arg, prints the ULID to stdout, and exits immediately.
Child stdout/stderr go to `{run_dir}/detach.log`. Uses `setsid()` on
unix to detach from the controlling terminal. Existing `fabro ps` and
`fabro logs` work with no changes since `run.pid` and `conclusion.json`
are written by the child as usual.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 17:18:50 -04:00
Bryan Helmkamp
84932eb3a8
Fix doctor dry-run trycmd test on CI by setting HOME to nonexistent path
`inherit = false` clears HOME but `dirs::home_dir()` falls back to the
passwd database, picking up the runner's ~/.fabro/cli.toml. The loaded
app_id without GITHUB_APP_PRIVATE_KEY triggers a partial-config error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 17:06:35 -04:00
Bryan Helmkamp
312bef9b87
Add routing context to EdgeSelected event: reason, status, hints
Emit reason (condition/preferred_label/suggested_next/unconditional/
jump/fallback), stage_status, preferred_label, suggested_next_ids,
and is_jump so logs explain why an edge was chosen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:47:28 -04:00
Bryan Helmkamp
008fdb03dc
Add inherit = false to all trycmd test envs to prevent CI flakiness
The doctor dry-run test was failing in CI because it inherited the host
environment. With no LLM API keys set, the doctor reported errors and
exited non-zero. Adding `inherit = false` to all 18 .toml test files
ensures deterministic behavior regardless of the host environment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:43:23 -04:00
Bryan Helmkamp
81adcefd57
Tweak fabro logs --pretty styling: increase indent, dim model brackets
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:32:03 -04:00
Bryan Helmkamp
6b03562749
Fix fabro logs --pretty wrapping past terminal edge on assistant messages
Markdown was rendered at full terminal width then indented, pushing lines
past the right edge. Now wraps to terminal_width minus indent first.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:30:03 -04:00
Bryan Helmkamp
94652907b0
Store workflow slug in manifest so resolve_run can match by directory name
When running `fabro run smoke`, the slug "smoke" was used to locate the
workflow but never persisted. If the DOT graph name diverged from the
directory name (e.g. workflows/foo/ contains digraph Bar), resolve_run
couldn't find the run by slug. Now the slug is extracted from the
workflow path, stored in the manifest, and matched in resolve_run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:14:06 -04:00
Bryan Helmkamp
f58e02c8df
Add instability warning to run directory docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:11:24 -04:00
Bryan Helmkamp
5a1109f66a
Make resolve_run match workflow slugs and display names
Workflow names in manifests are PascalCase (e.g. "LegacyTool") but
users expect to type the slug (e.g. "legacy-tool"). resolve_run now
compares case-insensitively and with hyphens/underscores stripped,
so both forms work.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:00:14 -04:00
Bryan Helmkamp
5b82cea0e1
Add fabro logs command to view workflow run event logs
Supports raw JSONL output (pipeable to jq) and --pretty mode with
colored, formatted output showing stages, tool calls, and assistant
messages. Includes --follow, --since, and --tail filtering options.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:55:58 -04:00
Bryan Helmkamp
6cc5512ead
Add resolve_run() that accepts run ID prefix or workflow name
Subcommands like cp, diff, preview, ssh, and pr previously only
accepted run ID prefixes. The new resolve_run() tries run ID prefix
first, then falls back to workflow name (most recent run), making
these commands more ergonomic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:42:03 -04:00
Bryan Helmkamp
68b088d322
Reorganize docs nav: merge Server Mode into Deployment, move Comparison and Dark Factory
- Merge core-concepts/server-mode into administration/deploy-server
- Move Comparison from Getting Started to Reference
- Move Dark Factory from Getting Started to Core Concepts
- Update all internal links to server-mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:39:08 -04:00
Bryan Helmkamp
25ec842a7f
Fix detect_binary test to work on Ubuntu (dash) sandboxes
`sh --version` exits non-zero on dash (Ubuntu default), so the test
only passed on macOS where sh is bash. Use `git` instead which
reliably supports --version on all platforms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:31:27 -04:00
Bryan Helmkamp
c5df9176b3
Extend smoke workflow to run linting and tests, add python3 to sandbox
Add python3 to the Daytona Dockerfile so MCP integration tests can run
their test server. Update the smoke workflow to verify fmt, clippy,
cargo test, typecheck, and bun test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:28:38 -04:00
Bryan Helmkamp
6db816e8b3
Fix empty run_id on sandbox events in progress.jsonl
The JSONL listener's run_id was initialized to "" and only populated
when WorkflowRunStarted fired, but sandbox events emit before that.
Seed it with the already-generated ULID so all events carry the run_id.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:00:40 -04:00
Bryan Helmkamp
e6f59cf426
Add Daytona sandbox defaults to fabro.toml and smoke workflow
Set Daytona as the project-level default sandbox so workflows that don't
specify their own sandbox config run on Daytona automatically. Add a
smoke workflow that verifies the sandbox toolchain (git, rustc, bun).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:53:53 -04:00
Bryan Helmkamp
12e71e3464
Add fabro workflow create <name> subcommand to scaffold new workflows
Writes a starter workflow.fabro (DOT graph) and workflow.toml into the
project's workflows directory. Supports --goal flag and derives the
digraph name from the workflow name using PascalCase conversion. Also
defaults the `graph` field in workflow.toml to "workflow.fabro" so it
can be omitted from generated configs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:32:00 -04:00
Bryan Helmkamp
79c602cc7f
Extract RunDefaults::merge_overlay to replace inline field-by-field merge
The inline merge in run_command() duplicated the structure of
apply_defaults() with shallower (inconsistent) semantics. This extracts
a proper merge_overlay method that deep-merges compound fields (vars,
hooks, mcp_servers, sandbox sub-fields) consistently with apply_defaults.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:23:23 -04:00
Bryan Helmkamp
76fde62234
Fix logo SVG viewBox clipping the right edge of the O
The scale(1.25) transform pushed the O's rightmost extent to ~x=1488,
past the old viewBox width of 1455.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:11:36 -04:00
Bryan Helmkamp
2220b9194d
Extend fabro.toml with project-level run defaults
Add project-level run defaults to fabro.toml so sandbox, LLM, hooks,
MCP servers, and other settings can be shared across workflows instead
of duplicated in each workflow.toml. Precedence: workflow.toml >
fabro.toml > cli.toml/server.toml.

- Rename `directory` → `work_dir` with backwards-compat serde alias
- Add `hooks` and `mcp_servers` to `RunDefaults` with merge logic
- Extend `ProjectConfig` with all run-defaults fields + `into_run_defaults()`
- Remove duplicate `McpServerEntry` from fabro-config (use run_config's)
- Move `hook_config` from ServerConfig into `run_defaults.hooks`
- Wire project config merge and hooks/mcp fallbacks in run_command()
- Update OpenAPI spec and regenerate TypeScript client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:11:16 -04:00
Bryan Helmkamp
36ed218ce0
Update docs for rewind, workflow list, daytona, and validation
Fix changelog rewind syntax to use positional args instead of flags.
Clarify Daytona snapshot note to distinguish configured-but-missing vs
unconfigured cases. Add rewind/workflow-list CLI reference sections,
checkpoints rewind guide, thread_id validation rule, and human gate
behavior details.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 13:51:57 -04:00
Bryan Helmkamp
72865245a4
Add ~/.fabro/ fallback for @ file references
When an @file reference can't be resolved against the workflow's
directory, fall back to ~/.fabro/ so users can share prompt files
across workflows without duplication. The workflow directory keeps
higher precedence so project-specific overrides still win.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 13:44:16 -04:00
Bryan Helmkamp
69e7f415d8
Add changelog entries for March 13-14 and update March 12
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:24:04 -04:00
Bryan Helmkamp
4ee215cada
Rename arc/ to fabro/ in git branch prefixes and workflow paths
Complete the rebrand by replacing hardcoded "arc/run/" branch prefixes
with a RUN_BRANCH_PREFIX constant ("fabro/run/") and updating
fabro init to create workflows under fabro/workflows/ instead of
arc/workflows/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:20:07 -04:00
Bryan Helmkamp
39191be1a5
Use daytona-medium snapshot as default Daytona sandbox
The bare ubuntu:22.04 image lacks git and other tooling, causing git
checkpoints to fail. Switch to the daytona-medium snapshot which has
standard dev tools pre-installed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:10:50 -04:00
Bryan Helmkamp
29bd80824b
Improve workflow diagram with LR layout and docs styling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:10:35 -04:00
Bryan Helmkamp
0347d5bf0d
Add workflow diagram and update doc URLs in README
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:08:10 -04:00
Bryan Helmkamp
52475dde28
Add Dark Factory docs page and rebrand as "dark software factory"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:05:35 -04:00
Bryan Helmkamp
178677a9a9
Backfill missing git_commit_sha from run branch commit messages
The engine writes git_commit_sha to on-disk checkpoint.json but not to the
metadata branch. When the metadata checkpoint lacks this field, walk the
run branch and match commits by message pattern to fill in the SHAs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 11:52:33 -04:00
Bryan Helmkamp
9e3d2d0688
Add fabro rewind command to rewind workflow runs to earlier checkpoints
Enables rewinding both the metadata branch and run branch refs to a
target checkpoint, allowing resume from an earlier point with
`fabro run --run-branch`. Supports targeting by node name, node@visit,
or @ordinal, with parallel interior snap-back and optional remote push.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 11:38:17 -04:00
Bryan Helmkamp
d207c4b1f7
Improve workflow list output with grouped sections, descriptions, and tests
Show workflows grouped by User/Project with directory paths in headings,
aligned NAME/DESCRIPTION columns, truncated goal snippets, and (none)
for empty sections. Add tests for list_workflows_detailed, read_workflow_goal,
and truncate_str.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 11:19:08 -04:00
Bryan Helmkamp
2bc211f267
Add fabro workflow list command
Adds a new `workflow` subcommand group with a `list` command that
discovers available workflows via `fabro.toml` and prints their names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 09:58:03 -04:00
Bryan Helmkamp
f6da846523
Add user-level workflow lookup in ~/.fabro/workflows/
`fabro run NAME` now checks ~/.fabro/workflows/ as a fallback when the
workflow isn't found in the project directory, letting users have
personal workflows available across all projects. Project workflows
take precedence over user workflows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 23:16:18 -04:00
Bryan Helmkamp
e7017eb127
Fix remaining .dot test references in integration.rs
Update two test TOML graph references from test.dot to test.fabro.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:39:58 -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
8cb6c4f26f
Rename .dot files to .fabro and update all references
Rename 79 workflow files from .dot to .fabro extension across
fabro/workflows/, test/, test/docs/, and files-internal/demo/.
Update TOML configs, Rust production code, test code, and shell
scripts. Backward compat tests in test/attractor/ are unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:27:19 -04:00
Bryan Helmkamp
c4dc2f09c8
Add graph.fabro as primary filename with graph.dot fallback
Write graph.fabro in run dirs and metadata branches. Read with
graph.dot fallback for backward compatibility with existing runs.
Add stack.child_workflow attribute with stack.child_dotfile fallback.
No files renamed yet — fallback paths handle everything.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 22:16:10 -04:00
Bryan Helmkamp
0ee5b079c5
Add thread_id_requires_fidelity_full lint rule
Warn when thread_id is set without fidelity=full, since session reuse
only works with full fidelity. Checks node-level, edge-level, and
graph-level default_thread attributes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 20:58:08 -04:00
Bryan Helmkamp
714c6f5eaf
Regenerate TypeScript API client from updated OpenAPI spec
Picks up Arc-to-Fabro rename and new ssh-configuration model.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 20:43:25 -04:00
Bryan Helmkamp
20bfbb939f
Rename Arc to Fabro in user-facing strings, comments, and tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 20:43:21 -04:00
Bryan Helmkamp
707c5fbfe3
Fix relative path in fabro-api-client generate script
The path was two levels up (../../) but needs three (../../../) since
the package lives at lib/packages/fabro-api-client.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 20:42:45 -04:00
Bryan Helmkamp
ff2e2fbf42
add comparison 2026-03-13 18:52:20 -04:00
Bryan Helmkamp
858bdc3788 Split trycmd into per-subcommand tests and remove live-probe doctor fixtures
Split the single cli_tests trycmd function into 14 per-subcommand test
functions so nextest can parallelize them. Delete header.toml and
verbose.toml doctor fixtures that ran live network probes — the existing
dry-run-flag.toml and help.trycmd already cover the same output assertion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 18:03:23 -04:00
Bryan Helmkamp
cb21dc8096 Fix slow unit tests (>5s) by removing unnecessary production delays
- doctor_no_color test: add --dry-run flag to skip live network probes (11s -> <1s)
- retry tests: set retry_policy=linear for 500ms delay instead of 5s default backoff
- cli_backend tests: make poll_interval configurable on AgentCliBackend, use 10ms in tests
- doctor TOML fixtures: remove status.code=1 now that dry-run doctor exits 0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 17:59:43 -04:00
Bryan Helmkamp
1b3d3d900b Move git SHA/build date from fabro-util to fabro-cli build.rs
fabro-util is a low-level crate depended on by almost everything, so its
build.rs reruns cascaded through the whole workspace. fabro-cli is the
leaf binary — nothing depends on it, so rebuilds are limited to just
that one crate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 15:03:12 -04:00
Bryan Helmkamp
cdbfc72719 Fix fabro-util build.rs rerun-if-changed path to prevent constant recompilation
The relative path to .git/HEAD was wrong (../../ instead of ../../../),
pointing to a nonexistent file. Cargo reruns build scripts when a
rerun-if-changed target doesn't exist, causing a full workspace rebuild
on every invocation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:53:11 -04:00
Bryan Helmkamp
82dd6a8c04 Bump version to 0.4.0 2026-03-13 13:18:49 -04:00
Bryan Helmkamp
2117d31d55 Cargo.lock 2026-03-13 13:18:39 -04:00
Bryan Helmkamp
4920f6e959 Fix assemble_narrative_only test to expect branding footer
The assemble_pr_body function unconditionally appends the "Generated
with Fabro" footer, but this test was asserting the bare narrative.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 13:05:59 -04:00