Migrate all 7 CLI tables to cli-table, which measures column widths
correctly in the presence of ANSI escape codes, fixing misaligned
columns in `fabro ps`. Also fix DIRECTORY to show ~/relative paths
instead of just the last component, and compute elapsed duration for
running jobs instead of showing "-".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enable serde_json's preserve_order feature so Map uses insertion-order
IndexMap instead of sorted BTreeMap. Extract build_event_envelope()
from the on_event closure to deduplicate the envelope construction.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace assert_eq!/contains() chains with insta::assert_snapshot! in
dockerfile unit tests (11 inline snapshots) and CLI model/help tests
(7 file-based snapshots), making test output easier to read and update.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add release.yml: tag-triggered (v*) workflow that cross-compiles
for aarch64-apple-darwin and x86_64-unknown-linux-gnu, packages
archives with SHA256 checksums, and creates a GitHub Release
- Add workflow_dispatch, concurrency groups, and cache-on-failure
to rust.yml and typescript.yml
- Run clippy and test on both ubuntu-latest and macos-15
- Add release profile with thin LTO and strip to Cargo.toml
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cargo build / cargo build --release now only compiles arc-cli and its
transitive deps, skipping arc-api, arc-slack, arc-db, arc-types, sqlx,
axum, etc. Use --workspace to build everything.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updated: Cargo.toml workspace members, CI workflow paths, Dockerfile
COPY, AGENTS.md, skill mapping, and doc references.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a webhook subsystem that receives GitHub App webhooks when configured
in server.toml with [git.webhooks] strategy = "tailscale_funnel". On startup,
it binds a local HTTP listener on a random port, exposes it via `tailscale funnel`,
and patches the GitHub App webhook URL. Incoming webhooks are verified with
HMAC-SHA256 before processing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The toolbox API does not support envs in /process/execute, so the
SDK now matches the Go SDK: accepts env in options but does not send
it. Arc uses export prepending as the workaround.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The upstream SDK now passes env vars through ExecuteRequest.envs,
so we no longer need to prepend export statements to commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server is long-lived on a fixed host, so a persisted UUID at ~/.arc/.id is
appropriate. CLI runs ephemerally, so an MD5 of the MAC address avoids file
I/O and is stable per-machine. CLI falls back to ~/.arc/.id if it exists
for migration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New `arc-exe` crate that runs agent tool operations inside ephemeral
exe.dev VMs via SSH. Uses two SSH connections: a management plane
(`ssh exe.dev`) for VM lifecycle and a data plane (`ssh vmname.exe.xyz`)
for command execution and file I/O.
Includes SshRunner trait with MockSshRunner for unit tests and
OpensshRunner for real SSH, with raw_mode for the exe.dev management
plane's custom command handler.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements a complete Slack integration for the interviewer system using
Socket Mode (WebSocket-based, no public URL required). Supports all five
question types: YesNo, Confirmation, MultipleChoice, MultiSelect, and
Freeform (via thread replies with @mention).
Modules: config, client, blocks, interaction, socket, dispatch,
connection, threads. 72 unit tests + e2e example.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LLM responses were printing raw Markdown (bold markers, table pipes,
heading hashes). Use termimad to render with proper ANSI formatting
when color is enabled, falling back to plain text when NO_COLOR is set.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Use the semver crate's Version type instead of manual (u32, u32, u32)
tuples for version comparison and display, eliminating the custom
format_version helper in favor of Version's built-in Display and Ord.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
ULIDs are lexicographically sortable by creation time, making log
directories and run lists naturally ordered without extra metadata.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New `mcp` crate using rmcp v0.15.0 with stdio and HTTP transports.
MCP tools are registered as regular `RegisteredTool` instances in the
agent's `ToolRegistry`, sharing the same `execute_one_tool` path as
built-in tools. Tools are namespaced as `mcp__{server}__{tool}`.
Includes end-to-end test: real MCP server subprocess (Python echo
server) → mock LLM issues tool call → MCP bridge executes → result
flows back through the session loop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace eager Regex compilation in GitleaksEngine::build() with
OnceLock-based lazy compilation. Individual regexes (rule patterns,
allowlist patterns, global allowlist patterns) are now compiled on
first use rather than at startup. This drops dry-run time from ~1.4s
to ~0.5s since the common no-match path never compiles any regexes.
Also removes the warm_up() pre-loading function and its callers since
lazy compilation makes it unnecessary.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the `--docker` boolean flag with `--execution-env <local|docker|daytona>`
to support three execution environments. The new `DaytonaExecutionEnvironment`
uses the Daytona cloud sandbox SDK to run agent tools remotely, auto-cloning the
current git repo into the sandbox via `gh auth token` credentials.
Setup commands from TOML task configs now run inside the execution environment
(via `exec_command` after `initialize()`) rather than locally, so they work
correctly for both Docker and Daytona sandboxes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 306da8ff6de1
Support `attractor run task.toml` as an alternative to `.dot` files.
Auto-detects format by file extension. TOML bundles pipeline config
(graph path, model, setup commands, working directory) into a single
file with precedence: CLI flag > TOML > DOT graph attrs > defaults.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 8744d57d6053
Layered library for blob/tree/commit/ref operations without touching
the working directory. Four modules: gitobj (primitives), branchstore
(key-value on a branch), snapshot (working dir captures), trailerlink
(commit message trailers). 56 tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 1e40b3267885
Removed the workspace-level clippy lint config that enabled all, pedantic, nursery,
and cargo lint groups. Removed all #[allow(clippy::...)] annotations that were only
needed to suppress those extra lints, and fixed the few default clippy warnings that
were uncovered.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Interactive TTY sessions now use dialoguer widgets (Select, MultiSelect,
Confirm, Input) instead of raw eprintln/read_line. Non-TTY input falls
back to the existing line-based reader. Suppresses redundant "Stage
started" inform message for wait.human nodes since the prompt itself
serves as notification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Drop event_tx from ManagedPipeline when pipeline completes/cancels/fails so
SSE streams end promptly instead of blocking until timeout (3.5s → 0.02s)
- Switch reqwest from native-tls to rustls-tls to avoid 500ms macOS cert store
load per process (0.67s → 0.005s per OpenAI adapter test)
- Replace hardcoded sleep(500ms)/sleep(200ms)/sleep(100ms) in server and
integration tests with 10ms poll loops (0.2-0.5s → 0.02-0.03s each)
- Add env_clear() to ullm prompt tests to prevent .env from triggering real
Anthropic API calls (0.45s → 0.15s)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements ExecutionEnvironment trait backed by Docker containers via
bollard. Host working directory is bind-mounted; all file ops, commands,
grep, and glob execute inside the container via docker exec. Extracts
shared format_lines_numbered() helper from LocalExecutionEnvironment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Close spec compliance gaps:
- Add user_instructions to SessionConfig and ProviderProfile trait (spec Section 6.1 layer 5)
- Populate EnvContext with git branch, date, model name during Session::initialize()
- Expand all three profile system prompts with identity, tool guidance, coding practices
- Implement provider_options: Anthropic beta headers, OpenAI reasoning effort, Gemini safety settings
- Add register_subagent_tools() to all profiles for spawn_agent/send_input/wait/close_agent
- Add list_dir tool to Gemini profile (spec Section 3.6)
- Add chrono dependency for date formatting
20 new tests (170 → 190), all passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Abort now transitions to CLOSED state and returns Err(Aborted)
- Closed sessions no longer emit SessionStart before rejecting input
- Add set_reasoning_effort() for mid-session reasoning effort changes
- Fix spawn_agent truncation limit from 30k to spec-required 20k
- Add JSON Schema validation of tool arguments before execution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New crate `unified-llm-cli` with binary `ullm` providing:
- `prompt` command: generate text via streaming/non-streaming, with
system prompts, options (-o temperature=0.5), stdin piping, and
token usage display
- `models list` command: browse catalog models with --provider and
--query filters
- Auto-detects provider from catalog for correct API routing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add abort signal support using CancellationToken for cooperative cancellation
of generate() and stream() calls
- Fix max_tool_rounds=0 to skip tool execution entirely (was executing first round)
- Add StreamResult wrapper with response(), text_stream(), partial_response()
and multi-step tool loop support in high-level stream()
- Add OpenAI metadata and provider_options.openai pass-through to Responses API
- Add Gemini provider_options.gemini pass-through (safety settings, cached content)
- Add OpenAI-compatible provider_options.<name> pass-through using adapter name
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse x-ratelimit-* headers into RateLimitInfo for Anthropic, OpenAI, and
OpenAI-compatible providers (previously hardcoded to None)
- Add "not found"/"does not exist" and "unauthorized"/"invalid key" error
message classification patterns for ambiguous HTTP status codes
- Apply TimeoutConfig.total to wrap the entire multi-step generate() loop
(previously only per_step was used)
- Add metadata field to GenerateParams with builder method, pass through to
Request instead of hardcoding None
- Implement stream_object() for streaming structured output with incremental
JSON parsing via new ObjectStreamEvent type (Partial/Delta/Complete variants)
- Add OpenAI-compatible Chat Completions adapter for third-party endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared provider helpers (parse_error_body, send_and_read_body,
extract_system_prompt, ApiMessage) into providers/common.rs, eliminating
duplicated logic across all three providers. Simplify StepResult and
GenerateResult to derive fields from the embedded Response rather than
storing redundant copies. Remove stringly-typed ToolCall.r#type and
ResponseFormat.r#type in favor of proper enums. Remove unused dependencies
(hyper, clap, rayon, base64, etc.), use LazyLock for the model catalog,
and fix miscellaneous idiom issues (unnecessary Vec collects, inconsistent
error Display, module_name_repetitions).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable clippy::all, pedantic, nursery, and cargo lint groups at the
workspace level. Fix all resulting warnings: merge identical match arms,
add #[must_use] and doc sections, derive Eq, use clone_from, add type
alias for complex types, extract helpers to reduce function length, and
add crate metadata.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>