Replace hardcoded /home/daytona/workspace/.arc-parallel path with
{working_directory}/.arc/logs/{run_id}/parallel/{node_id}/{branch_key},
matching the host worktree layout and scoping worktrees per-run.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OpenAI requires max_output_tokens >= 16, and slower providers like
Gemini Pro need more than 10s to respond.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update CLI tests for restructured commands (models → top-level, run → run start)
- Remove sync-related tests (command was removed)
- Fix clone_on_copy clippy warnings in arc-api server
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create openapi/arc-api.yaml as source of truth for all API endpoints
- Add arc-types crate with build.rs using typify to generate Rust structs
from the spec's component schemas
- Refactor server.rs to use generated types instead of hand-written ones
- Add route coverage conformance test validating router matches spec
- Add openapi-typescript to arc-web for TypeScript type generation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add `labels: HashMap<String, String>` to RunConfig, written to manifest.json
- Add `--label KEY=VALUE` flag to `arc run` (repeatable)
- New `arc runs` command: list pipeline runs with table or --json output
- New `arc runs prune` command: delete old runs with --before, --pipeline,
--label, --orphans filters (dry-run by default, --yes to confirm)
- 13 new tests covering scan_runs, filter_runs, prune, and manifest labels
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A background tokio task polls EventEmitter.last_event_at(). When idle
time exceeds the graph-level stall_timeout (default 600s), it cancels
a CancellationToken that races against execute_with_retry via
tokio::select!, dropping the hung handler future.
- EventEmitter: AtomicI64 last_event_at field, touch() to seed, emit()
auto-updates
- Graph::stall_timeout(): reads Duration attr, defaults 600s, None for 0
- StallWatchdogTimeout event variant with warn-level trace()
- Engine: watchdog spawn before main loop, select! at handler call,
shutdown after loop
- CLI: format arms for summary and detail views
- Unit tests for emitter, graph accessor, event serialization, and
engine watchdog behavior (hung, keepalive, disabled)
- E2e integration tests: DOT-parsed pipelines with 100-200ms stall
timeouts verifying trigger, keepalive, disable, and timing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Inner events are already traced at origin by the sub-agent's own
EventEmitter, so the SubAgentEvent wrapper should not re-trace them.
This matches the pattern used by PipelineEvent::Agent and
PipelineEvent::ExecutionEnv.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every emitted event now produces a structured tracing log line so
developers can debug after the fact via ~/.arc/logs/. Each event
variant gets an appropriate log level (info/debug/warn/error) with
structured fields. Streaming noise variants (TextDelta,
ToolCallOutputDelta) are no-ops, and wrapper variants (Agent,
ExecutionEnv on PipelineEvent) delegate to the inner event's trace.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SdkError now produces hand-crafted signature hints (e.g.
"api_deterministic|openai|authentication") that are identical regardless
of error message wording, replacing fragile regex-normalized signatures
for API errors. ArcError.to_fail_outcome() centralizes fail outcome
construction with failure_class and failure_signature context_updates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Guard loop_restart edges to only allow transient_infra failures, matching
Kilroy's behavior. Non-transient failures (deterministic, structural,
budget_exhausted, canceled, compilation_loop) are now blocked immediately
instead of getting restart attempts before the circuit breaker fires.
Fix normalize_failure_reason truncation to use floor_char_boundary(240)
instead of a raw byte slice, preventing panics on multi-byte UTF-8 chars.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
max_node_visits used > while signature circuit breakers used >=, creating
an inconsistency where "limit" meant different things depending on the
mechanism. Kilroy uses >= for all three checks. This aligns Arc to match.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tracing events (e.g. 13 calls in arc-mcp) were silently dropped because
no subscriber was configured. This adds a file-based tracing subscriber
that logs to ~/.arc/logs/YYYY-MM-DD.log with INFO as the default level,
controllable via the ARC_LOG env var.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add wall_clock_timeout field to SessionConfig that spawns a tokio timer
to cancel the session after a duration, reusing existing Aborted path
- Set 120s wall-clock timeout on retro agent to prevent unbounded runs
- Replace silent `let _ =` with logged warnings for checkpoint load and
retro save failures
- Reuse LLM client from initial from_env() call instead of creating a
second one for the retro agent
- Extract retro generation into generate_retro() helper and call it from
both run_command and run_from_branch (resume path)
- Tolerate mutex poisoning in retro agent with unwrap_or_else
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add git_cmd() helper disabling maintenance.auto and gc.auto on all
host-side git commands; add GIT_REMOTE constant for remote commands
- Use --force on branch creation for idempotent retry/resume
- Add replace_worktree() that does best-effort remove before add
- Add reset_hard() after parallel worktree setup for deterministic state
- Add sanitize_ref_component() to clean node IDs in branch names
- Add git_replace_worktree_remote() for remote sandbox environments
- Add tests for sanitize_ref_component, replace_worktree, reset_hard
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces durable storage so pipeline run data survives restarts.
The new arc-db crate provides SQLite connection helpers, a
PRAGMA user_version migration system, and a WorkflowRun model.
AppConfig (arc.toml) controls data_dir; the server initializes
the DB at startup and threads the pool through AppState.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of skipping the retro agent entirely in dry-run, use a
placeholder narrative so derive → apply_narrative → save all run.
This catches bugs in the merge/persistence path without LLM calls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After each pipeline run, auto-derive stats from the checkpoint (stages,
retries, cost, files touched) then run an Opus agent session that
explores progress.ndjson to produce qualitative analysis: smoothness
rating, intent, outcome, learnings, friction points, and open items.
Backend:
- retro.rs: data model, save/load, derive_retro(), extract_stage_durations()
- retro_agent.rs: post-pipeline agent session with submit_retro tool
- cli/run.rs: hook retro generation after final.json, before engine_result?
- server.rs: GET /pipelines/{id}/retro endpoint, auto-derive on completion
Frontend:
- data/retros.ts: TS types + mock data + smoothness color config
- routes/retros.tsx: list page with smoothness badges
- routes/run-retro.tsx: detail view (stats, intent, stages, learnings)
- routes.ts + run-detail.tsx: wire up retro route and tab
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Populated input/output cost per million tokens for OpenAI, Gemini,
Kimi, ZAI, MiniMax, and Inception models based on current public
API pricing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parallel branches now get isolated git worktrees so concurrent file
writes don't collide. Works across Local, Docker (bind-mount), and
Daytona (remote exec_command) environments.
Key changes:
- git.rs: add create_branch_at() and merge_ff_only() helpers
- engine.rs: add GitState struct, remote worktree helpers
(git_create_branch_at_remote, git_add_worktree_remote, etc.)
- handler/mod.rs: add git_state field to EngineServices (RwLock)
- handler/parallel.rs: WorktreeEnv wrapper, per-branch worktree
setup/teardown, checkpoint commits per branch, ff-merge winner
before returning to engine
- handler/fan_in.rs: ff-merge to winner's HEAD, set best_head_sha
- E2E tests for Host (local) and Daytona (remote) modes
When git_state is None, behavior is unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevents truncation of large tool calls (e.g. write_file with big
content) when neither agent config nor model catalog provides a value.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LLM-authored output can set failure_class to non-canonical strings like
"retryable", "transient", or "permanent". Expand FromStr to accept 30+
aliases with case-insensitive trimmed matching, matching Kilroy's
normalizedFailureClass(). Unknown values fail-closed to Deterministic
instead of returning Err.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Absolute `cd` paths in shell commands (script/tool_command attributes) silently
override the engine's worktree CWD, breaking portability across machines,
containers, and worktrees. Ported from kilroy (danshapiro/kilroy d9c1fec).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix 4 test failures: add unconditional fallback edges to branching.dot
and conditions.dot to satisfy all_conditional_edges validation rule
- Fix clippy await_holding_lock: scope MutexGuard before await in
daytona_integration.rs
- Fix clippy unnecessary_get_then_check: use contains_key in script.rs
- Fix clippy expect_fun_call: use unwrap_or_else in integration.rs
- Run cargo fmt across entire workspace
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 8 missing transient_infra patterns (crates.io registry, toolchain,
cross-device link errors), 2 structural hints (write_scope_violation
variants), and reorder heuristic priority to check transient_infra
before budget_exhausted to match Kilroy's classification behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Raise the Anthropic adapter fallback from 4096 to 16384 to prevent
truncation of large tool call JSON when the model isn't in the catalog.
Add max_tokens as a configurable DOT node attribute that flows through
SessionConfig to LLM requests, following the same pattern as
reasoning_effort. Priority: node attribute > catalog > provider default.
Ported from kilroy (danshapiro/kilroy) commits 99a5cd7 and 78fadad.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract hint patterns into const arrays (TRANSIENT_INFRA_HINTS,
BUDGET_EXHAUSTED_HINTS, STRUCTURAL_HINTS) and add 28 new patterns
from Kilroy to prevent transient/budget failures from misclassifying
as deterministic. Add comprehensive regression test per pattern plus
count-guard tests to catch accidental additions/removals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AttractorError → ArcError across 30 source files
- .attractor/ → .arc/ for artifacts and skills paths
- ATTRACTOR_NODE_ID → ARC_NODE_ID env var
- attractor-rust → arc in Cargo.toml repository URLs
- attractor-spec.md → arc-spec.md with content updates
- Update server banner, test comments, README examples, and docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move HTTP server (Axum routes, JWT auth, serve CLI command, server
config) from arc-workflows into a dedicated arc-api crate. This
improves separation — arc-workflows is a pipeline engine library,
not a web server.
- Create crates/arc-api with server.rs, jwt_auth.rs, serve.rs,
server_config.rs and their integration tests
- Remove server feature flag and optional deps from arc-workflows
- Update arc-cli to depend on arc-api for ServeArgs and serve_command
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces server_config.rs with a TOML-based ServerConfig struct
(version + url) following the same patterns as TaskConfig.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change GitCheckpointMode::Remote to Remote(PathBuf) so both variants
carry a repo path for MetadataStore shadow commits
- Unify init_run and shadow write logic to work with either Host or
Remote mode, eliminating Host-only gates
- Add trailers (Arc-Run, Arc-Completed, Arc-Checkpoint) to remote
checkpoint commits via write_file + git commit -F to avoid shell
escaping issues with multi-line messages
- Wire up meta_branch for Daytona in run.rs (was only set for worktree)
- Fix sandbox name collisions by adding random hex suffix
- Fix pre-existing build_router() test compilation errors from JWT auth
- Add E2E tests for Host shadow branch and Daytona shadow branch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a bare_string parser that accepts values containing hyphens and
dots like gpt-5.2-codex-spark and gemini-3-flash-preview. These are
common in kilroy DOT files for model names but were previously rejected
by arc's strict identifier parser.
All 14 kilroy DOT files now parse successfully.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ed25519 asymmetric JWT: arc-web signs with private key, arc-attractor verifies
with public key. Adds AuthenticatedService axum extractor to all routes, jose
dependency for TypeScript signing, and key generation script.
Startup behavior: ARC_JWT_PUBLIC_KEY set → enforce JWT auth; not set +
ARC_INSECURE_DISABLE_AUTHENTICATION=true → allow unauthenticated; neither →
refuse to start with clear error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy 14 DOT workflow files from the kilroy project and add tests proving
arc can parse them. 11 files parse successfully, exercising features
including subgraphs, fan-out/fan-in, conditional routing, goal gates,
model stylesheets, and large 40+ node workflows.
3 batch test files (batch_*.dot) document a parser gap: arc requires
quoted values for strings with hyphens/dots (e.g., "gpt-5.2") while
kilroy's parser accepts them unquoted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Aligns with the kilroy implementation of the Attractor spec. A default
of 50 retries is far too aggressive for most workflows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Provider::ALL constant for iterating all variants in tests
- Add catalog guardrail tests: every provider has models, provider strings
round-trip, as_str round-trips through from_str
- Add arc-agent guardrail tests: every default_model exists in catalog,
profile context_window matches catalog for default models
- Fix context window drift: profiles now look up catalog instead of
hardcoding sizes, with conservative fallbacks for unknown models
- Add #[serde(deny_unknown_fields)] to config structs so typos like
[lmm] instead of [llm] produce parse errors
- Extract DEFAULT_BASE_URL constant in OpenAI adapter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- all_conditional_edges (ERROR): fires when a node has outgoing edges but
all are conditional with no unconditional fallback, preventing silent
fall-through to arbitrary edge selection.
- orphan_custom_outcome (WARNING): fires when outcome-based routing lacks
an unconditional fallback edge, catching typos in outcome values.
- Enhanced condition_syntax rule to also validate via parse_condition(),
catching malformed expressions that pass static checks (e.g. empty key).
- Updated integration test graph to use unconditional fallback edge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spawn failures (binary not found) and timeouts are infrastructure issues,
not domain failures. Return them as Err(AttractorError::Handler(...)) so
the engine can distinguish them from script exit-code failures and
potentially retry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Register Inception Labs' Mercury diffusion LLM as a new provider using
the OpenAI-compatible adapter at api.inceptionlabs.ai. Adds mercury and
mercury-coder to the model catalog and wires up all exhaustive match
arms across arc-llm, arc-agent, and arc-attractor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Warn when DOT reserved keywords (graph, digraph, subgraph, node, edge,
strict, if) are used as node IDs since they cause silent routing failures.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three separate binaries are replaced by a single `arc` CLI with subcommands:
arc llm prompt/models, arc agent, arc run, arc validate, arc serve
Extract public CLI modules (arc_llm::cli, arc_agent::cli::AgentArgs/run_with_args)
so the new arc-cli crate can dispatch to each library. Integration tests migrate
to crates/arc-cli/tests/cli.rs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>