Commit graph

84 commits

Author SHA1 Message Date
Bryan Helmkamp
b6bc58073b Simplify create_ssh_access return type and signature
Return just the SSH command string instead of the full SshAccessDto,
and hardcode the 60-minute expiration internally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:22:39 -05:00
Bryan Helmkamp
e64f1e3c47 Add === Retro === section header before retro output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:15:12 -05:00
Bryan Helmkamp
932524dd98 Print retro summary inline in CLI output
Show smoothness rating, outcome, friction/open item counts, and file
path after retro completes instead of just the file path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:13:01 -05:00
Bryan Helmkamp
97d370b727 Add --ssh flag to arc run for Daytona SSH access
Creates SSH access after sandbox init and displays the connection
command in the progress output, aligned under the sandbox detail line.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:11:39 -05:00
Bryan Helmkamp
6dc359f867 Show parallel branches in progress UI
Handle ParallelBranchStarted/Completed events as nested entries under
the fork stage, using the same indented spinner styling as tool calls.
Branch bars persist after the stage completes so they remain visible
in the final output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 08:58:44 -05:00
Bryan Helmkamp
5ab740b9d3 Fix sandbox detail line positioning with insert_after
Use insert_after instead of add so the detail bar renders directly
below the sandbox bar, not at the bottom of the multi-progress.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 08:49:13 -05:00
Bryan Helmkamp
990b2e9124 Add sandbox details and hyperlink to progress output
Show sandbox name, CPU, and memory on a second indented detail line
beneath the "Sandbox: provider" line. Hyperlink the provider name to
its dashboard URL using OSC 8 terminal escape sequences (TTY only).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 08:45:42 -05:00
Bryan Helmkamp
bde59168c9 Fix sandbox cleanup race and improve warning formatting
Sandbox cleanup was spawned fire-and-forget in a scopeguard, causing DNS
resolution to be cancelled when the tokio runtime shut down before the
HTTP request completed. Now cleanup is awaited explicitly before
returning, with the scopeguard kept only as a safety net for panics.

Also: add blank line before the warning and color-code it yellow to
match other warnings. Update daytona-sdk to include full error source
chain in error messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 08:29:05 -05:00
Bryan Helmkamp
918847af91 Field-level merging for run config defaults
apply_defaults() previously did whole-struct replacement for llm, setup,
and sandbox sections. If run.toml specified only [llm] model, the entire
server.toml [llm] block (including provider) was lost. Now each field
merges individually: task values win per-field, with map-merge for labels
(like vars) and whole-struct semantics for snapshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 07:58:56 -05:00
Bryan Helmkamp
2a66e5fde5 Fix UTF-8 string slicing panics with floor_char_boundary helper
Add a shared floor_char_boundary() utility that rounds byte indices down
to the nearest char boundary, preventing panics on multi-byte UTF-8
characters like emoji. Applied to all 9 unsafe slice sites across
arc-agent and arc-workflows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 02:36:56 -05:00
Bryan Helmkamp
53dac89d1b Show model name and script command next to stage names in progress output
Display the LLM model ID (dim, bracketed) next to stage names as soon as
the first AssistantMessage arrives, and show the script command (dim,
truncated to 60 chars) for parallelogram/script stages from stage start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 02:05:25 -05:00
Bryan Helmkamp
c8a1693492 Use Checkpoint::load() instead of manual file read and parse
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:48:59 -05:00
Bryan Helmkamp
0a0f47b218 Print final stage output after run result summary
Reads the checkpoint to find the last stage with a response and
prints it under an "=== Output ===" header so users can see what
the workflow produced without digging into log files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:45:13 -05:00
Bryan Helmkamp
73c741e64e Reduce tool call indent to 2 spaces under stage name
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:34:12 -05:00
Bryan Helmkamp
c1ecbccb5c Add subagent demo and complete tool display name coverage
- Add demo/03-subagent.dot, renumber demos 04-08
- Add shell and spawn_agent to tool display name matcher
- Add list_dir, web_search, web_fetch, use_skill display args

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:29:58 -05:00
Bryan Helmkamp
4eea33b797 Enrich tool call display, emit exit node events, add --no-retro and demo
- Show tool args in dim parenthetical: read_file(CLAUDE.md)
- Shorten CWD-relative paths in tool call display
- Show elapsed time on completed tool calls
- Emit StageStarted/StageCompleted for terminal (exit) nodes
- Add --no-retro flag to skip retro generation
- Add demo/02-tool-use.dot, renumber existing demos 03-07

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:25:45 -05:00
Bryan Helmkamp
23a943efca Polish run output: tilde paths, retro timing, dim cost, goal spacing
- Shorten paths with ~ instead of full home directory
- Show retro duration right-aligned like stage lines
- Add "Running retro..." indicator before retro agent runs
- Dim the Cost/Tokens summary line
- Add blank line after Goal before progress section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:16:32 -05:00
Bryan Helmkamp
a71b9d0561 Keep duration on far right in stage completion lines
Swap cost and duration order so cost appears first and duration
stays consistently on the far right edge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:10:39 -05:00
Bryan Helmkamp
aa158ef6a5 Add blank line before human gate prompt
Insert a separator bar through indicatif before hiding progress bars
for interactive prompts, ensuring a visual gap between the spinner
and the dialoguer prompt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:08:54 -05:00
Bryan Helmkamp
81841d28eb Polish CLI run output: cleaner layout and less noise
- Increase indent from 2 to 4 spaces for progress UI lines
- Add blank line separators after Sandbox/Setup and before Retro output
- Dim Sandbox/Setup and workflow metadata lines
- Rename "Parsed workflow:" to "Workflow:"
- Remove redundant inform() calls for run/stage start/complete
- Remove Notes: and Logs: lines from end-of-run summary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:01:10 -05:00
Bryan Helmkamp
dc3867a3c4 Fix cargo fmt formatting across workspace
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:36:44 -05:00
Bryan Helmkamp
9447422e18 Simplify progress.rs: cache styles, fix UTF-8 safety, remove dead code
- Cache ProgressStyle and glyph strings with OnceLock (avoid repeated
  template parsing and allocations on every event)
- Fix unsafe byte-based string slicing in tool_display_name (use chars)
- Parse status via StageStatus enum instead of raw string comparison
- Remove unused started_at and logs_bar fields
- Extract shared finish_stage method from duplicate completed/failed logic
- Simplify match arms to if-let where only TTY branch has work

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:09:44 -05:00
Bryan Helmkamp
c374ceb391 Add indicatif-based progress UI for arc run start (non-verbose)
Replace plain dimmed text output with cargo/BuildKit-style progress bars
using indicatif MultiProgress. Shows spinners during active stages and
tool calls, right-aligned timers, green/red glyphs for completion status,
and stage costs. Falls back to simple eprintln for non-TTY. Verbose mode
is unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:58:43 -05:00
Bryan Helmkamp
7b39b42fda Add 87 unit tests for uncovered pure logic in arc-workflows
Cover format_cost, format_tokens_human, compute_stage_cost, all
format_event_summary variants, validate_command, context_diff, and
parse_label_filters with fast unit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:42:34 -05:00
Bryan Helmkamp
7660cea15c Restore abbreviated token formatting (1.2k, 3.4m) instead of HumanCount
HumanCount's comma-separated output (1,234) is less scannable for token
counts. Restore k/m suffix formatting with added millions support. Remove
indicatif dependency from arc-agent since it no longer uses it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:11:47 -05:00
Bryan Helmkamp
66d3f62131 Use indicatif formatters for human-readable durations, tokens, and bytes
Replace hand-rolled format_duration_human, format_tokens_human, and
format_token_count with indicatif's HumanDuration, HumanCount, and
HumanBytes. Token counts now display as comma-separated (e.g. "1,234")
instead of abbreviated (e.g. "1.2k"), and byte counts show units
(e.g. "1.50 KiB").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:09:18 -05:00
Bryan Helmkamp
3e28e6acda Reduce stall watchdog test sleep times for faster test runs
Shrink timeouts and handler durations by ~5-10x. The tests verify
the same relative timing behavior (keepalive interval < stall timeout,
hung handler outlasts timeout) with smaller absolute values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:41:09 -05:00
Bryan Helmkamp
01ddeadaf0 Enforce semantic color scheme across CLI output
Add magenta, underline, bold_green, and bold_red styles to Styles struct.
Fix color semantics: server address uses cyan (info, not success), status
lines use bold_green/bold_red, preflight verdict uses bold variants, and
file paths are underlined instead of dim.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 16:09:03 -05:00
Bryan Helmkamp
c2ea8b3084 Replace DIY terminal color with console crate
Styles fields change from &'static str (raw ANSI escape codes) to
console::Style, removing unsafe Send/Sync impls and manual reset
handling. The console crate handles TTY detection and NO_COLOR natively.

Also adds live connectivity probes to arc doctor (--live flag).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 16:02:10 -05:00
Bryan Helmkamp
d101892bdf Switch LLM chat input to dialoguer and use ColorfulTheme everywhere
Replace raw stdin.lock().lines() in run_chat with dialoguer::Input
using spawn_blocking for TTY, with a stdin fallback for non-TTY.
Apply ColorfulTheme::default() to all dialoguer widgets in both
arc-llm and arc-workflows ConsoleInterviewer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 15:40:24 -05:00
Bryan Helmkamp
2737e6164e Add colored output to models list and test, fix clippy warnings
Add ANSI color to `arc models` and `arc models test` output when stdout
is a TTY: bold model IDs, dim provider/aliases, cyan speed, green/red
test results. Add `Styles::detect_stdout()` to arc-util.

Also fix pre-existing clippy warnings: derive Default instead of manual
impls for enums in server_config, remove unused FailureDetail imports
in arc-workflows error tests, inline print literal in test_models header.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 14:49:02 -05:00
Bryan Helmkamp
7c8ef76d4c Use claude-haiku-4-5 alias instead of dated snapshot ID
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 14:31:38 -05:00
Bryan Helmkamp
8168c85ac9 Extract sandbox/daytona resolution helpers, fix preflight defaults bug
Extract parse_sandbox_provider, resolve_sandbox_provider, and
resolve_daytona_config helpers to eliminate 4 near-identical sandbox
parsing chains. Compute sandbox_provider once with proper error handling
instead of twice (preview silently swallowed errors). Fix bug where
run_preflight did not fall back to run_defaults for daytona config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 01:34:36 -05:00
Bryan Helmkamp
e3fa99eba1 Add run defaults to server config for workflow run inheritance
Rename AppConfig → ServerConfig with flattened RunDefaults so users can
set default llm, sandbox, setup, directory and vars in ~/.arc/arc.toml.
Precedence: CLI flags > workflow TOML > server config defaults > DOT
graph attrs > hardcoded defaults. Vars merge (defaults first, task
config overwrites collisions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 01:26:41 -05:00
Bryan Helmkamp
c888ab8be5 Rename TaskConfig → WorkflowRunConfig, task → goal
Better reflects domain semantics: the config describes a workflow run,
and the free-text field is the run's goal, not a generic "task".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:44:24 -05:00
Bryan Helmkamp
3b2c0de11a Simplify preflight: remove dead RunMode enum, fix stringly-typed provider matching
- Remove RunMode enum (only Preflight was checked; DryRun/Normal unused)
  — use args.preflight directly
- Switch default_model_for_provider() to take Provider enum instead of
  Option<&str> for exhaustive matching; adds missing Inception default
- Extract sandbox init/cleanup into creation + single check pattern,
  eliminating 3x copy-paste of identical init/cleanup boilerplate
- Replace setup_commands Vec clone with direct count (only .len() used)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:54:02 -05:00
Bryan Helmkamp
74cd6bc791 Add --preflight flag to arc run start for config validation without execution
Verifies sandbox boot (local/docker/daytona), LLM provider availability,
and model/provider resolution chain, then prints a structured report.

Extracts model/provider resolution into reusable helpers
(default_model_for_provider, resolve_model_provider) with tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:42:54 -05:00
Bryan Helmkamp
ffac356c7b Add pass numbering to parallel branch names to prevent overwrites on retry
Parallel branches now include the node visit count (pass1, pass2, etc.)
in their ref names, preventing silent overwrite when a parallel node is
re-executed via retry or loop_restart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 22:02:43 -05:00
Bryan Helmkamp
e911a60220 Fix useless format! clippy warning in asset_snapshot
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 22:00:55 -05:00
Bryan Helmkamp
cffb00bcdb Carry typed errors through the entire stack instead of stringifying early
- AgentError gains Clone + Serialize/Deserialize with tagged serde format
- ArcError::Handler/Engine become struct variants with eager FailureClass
  classification via smart constructors handler()/engine()
- Outcome replaces failure_reason: Option<String> with failure: Option<FailureDetail>
  carrying message, failure_class, and failure_signature together
- AgentEvent::Error/LlmRetry/SubAgentFailed carry typed AgentError/SdkError
  instead of pre-stringified error messages
- WorkflowRunEvent::WorkflowRunFailed carries ArcError; StageFailed/StageCompleted
  carry FailureDetail instead of separate string fields
- classify_outcome() trivially reads from FailureDetail; circuit breaker reads
  failure_signature from FailureDetail instead of context_updates hack
- flatten_event() decomposes structured errors into flat fields for progress.jsonl
  backward compatibility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 21:53:23 -05:00
Bryan Helmkamp
00145424a5 Consolidate artifacts and assets under unified directory layout
Rename node visit suffix from `-attempt_{V}` to `-visit_{V}` and move
asset collection under `artifacts/assets/` alongside artifact values in
`artifacts/values/`. Retry directories use `retry_{N}` instead of the
ambiguous `attempt_{N}`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:31:21 -05:00
Bryan Helmkamp
67652ad480 Add generic asset snapshot collection for workflow node outputs
Automatically discovers and collects well-known output files (test reports,
screenshots, trace files) from each node's execution into its log directory.
Works across all three sandbox types (local, Docker, Daytona) via a new
`download_file_to_local` trait method that handles binary files correctly.

- New `asset_snapshot` module with pure functions for find command generation,
  output parsing, candidate matching, and budget enforcement
- `Sandbox::download_file_to_local` implemented for Local (fs::copy),
  Docker (host bind-mount resolution), and Daytona (SDK download)
- `AssetsCaptured` event variant with DEBUG-level tracing
- Engine integration: baseline snapshot before handler, collection after
  (both success and error paths), non-fatal on errors
- E2e tests for local sandbox (2 tests), Docker (#[ignore]), Daytona (#[ignore])

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:58:08 -05:00
Bryan Helmkamp
c560c608e2 Rename progress.jsonl fields for clarity
Add node_id to Stage* enum variants so both the programmatic ID and
display label are available. Add rename_fields() post-processing in
flatten_event() to give flattened JSONL fields self-describing names:

- timestamp → ts (save space)
- name → node_label (Stage*), workflow_name, snapshot_name
- index → stage_index, branch_index, command_index
- stage → node_id (Agent.*, Interview*, Prompt)
- branch → node_id (ParallelBranch*)
- node → node_id (StallWatchdogTimeout)
- from_node/to_node → from_node_id/to_node_id
- start_node → start_node_id
- provider → sandbox_provider (Sandbox.*)
- text → prompt_text (Prompt)
- Insert node_label defaulting to node_id where only an id exists

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:11:33 -05:00
Bryan Helmkamp
b4f1495982 Avoid data loss in SubAgentEvent flattening
Instead of flattening the inner event's fields into the top level
(which causes collisions when SubAgentEvent wraps SubAgentEvent —
losing inner agent_id, depth, and nested event body), keep the inner
event as a `nested_event` JSON value. The dot-notation event name
still reflects the inner type for easy filtering.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 18:29:28 -05:00
Bryan Helmkamp
eb195a0be9 Skip envelope-colliding keys when merging flattened event fields
WorkflowRunStarted and GitCheckpoint have a `run_id` field that
collides with the envelope's top-level `run_id`. Filter out
`timestamp`, `run_id`, and `event` from event fields to avoid
duplicate keys in the JSONL output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 18:26:54 -05:00
Bryan Helmkamp
62b54c8f4d Flatten progress.jsonl event format to top-level fields
Event data was nested inside a tagged enum (`"event": {"StageStarted": {fields}}`).
Now `event` is a string name and fields merge into the top-level object
(`"event": "StageStarted", "name": "plan", ...`).

Nested events use dot notation:
- Agent wrapper: "Agent.ToolCallStarted" with stage at top level
- Sandbox wrapper: "Sandbox.Initializing" with fields at top level
- SubAgentEvent: "Agent.SubAgentEvent.ToolCallStarted" flattened one level

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 18:25:27 -05:00
Bryan Helmkamp
effe165f31 Simplify -v flag from two verbosity levels to a single boolean
The `-vv` (full detail) mode was not useful in practice. This collapses
the two-tier `-v`/`-vv` into a single `--verbose` boolean and removes
the now-dead `format_event_detail` function and its tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 12:29:29 -05:00
Bryan Helmkamp
6dd422186e Rename progress.ndjson to progress.jsonl
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 11:46:31 -05:00
Bryan Helmkamp
79d97ebb5c Fix stale labels, grammar, and comments from sandbox rename
- Fix display label `image:` → `name:` for SnapshotPulling/SnapshotPulled
  in format_event_detail
- Fix grammar: "an Sandbox" → "a Sandbox" in README and parallel.rs
- Fix typo: "sandboxs" → "sandboxes" in parallel.rs
- Update remaining "execution environment" comments to "sandbox"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-02 11:43:34 -05:00
Bryan Helmkamp
d0c8bd3eed Rename ExecutionEnvironment to Sandbox across the codebase
Adopt cleaner terminology: Sandbox (resource providing disk + execution),
SandboxProvider (Local/Docker/Daytona), SandboxEvent (lifecycle events),
and Snapshot (pre-built environment images). Flatten DaytonaSandboxConfig
into DaytonaConfig, rename CLI flag to --sandbox, and update TOML config
sections from [execution] to [sandbox].

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