Commit graph

430 commits

Author SHA1 Message Date
Bryan Helmkamp
be72df55c8 Add arc setup interactive setup wizard
Automates first-time setup: generates server.toml, Ed25519 JWT keypair,
mTLS CA+server certificates, session secret, and .env file with proper
permissions. Includes pre-flight system dependency checks shared with
doctor, LLM provider API key collection, and optional doctor verification.

Also renames config file from arc.toml to server.toml across the codebase,
and loads ~/.arc/.env before CWD .env for centralized secret management.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 22:24:09 -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
d373ffd10f Clean up doctor types: ProbeOutcome enum, typed status structs, Ord
- Replace found/success/version bools with ProbeOutcome enum to
  eliminate impossible state (found=false, success=true)
- Remove DepProbeResult; check_system_deps takes DepSpec + ProbeOutcome
  directly, eliminating redundant field copying and the clone
- Use typed Vec<ApiAuthStrategy> and AuthProvider in ApiStatus/WebStatus
  instead of converting enums to strings at construction time
- Derive Ord on CheckStatus, replace manual severity-max with .max()
- Extract dep_issue helper to deduplicate required/optional formatting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:55:34 -05:00
Bryan Helmkamp
78a8f93bc5 Replace version tuples with semver::Version in doctor
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>
2026-03-03 21:47:08 -05:00
Bryan Helmkamp
71f7af267a Add URL context to API fetch errors for easier debugging
When the API server is unreachable, the raw "fetch failed" error gives
no indication of what URL was being requested. Wrapping the error
includes the target URL in the message while chaining the original
cause.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:41:35 -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
9243c94ded Replace fragile string filter with structural error tracking
The remediation list was derived by filtering details for strings not
containing ": valid", which could silently exclude real errors. Replace
with CryptoCheckState that accumulates errors structurally as they
occur, and unify all validation paths through record/record_unit/
push_error methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:25:27 -05:00
Bryan Helmkamp
d688a6c095 Simplify crypto validation in arc doctor after code review
- Extract record_validation() helper to deduplicate Ok/Err → detail handling
- Make expand_tilde public in tls.rs and reuse it in doctor instead of
  duplicating the tilde expansion logic
- Make now_epoch injectable in CryptoInput for deterministic tests
- Change tls_files to Option<Result<...>> to distinguish "not configured"
  from "files unreadable"
- Use struct update syntax in tests to reduce boilerplate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:21:34 -05:00
Bryan Helmkamp
64a6b0278a Bypass GitHub OAuth when auth provider is insecure_disabled
The app-shell and redirect-home loaders unconditionally required GitHub
OAuth, which broke demo mode. Now they check the auth provider config
and use a hardcoded demo user when auth is disabled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 20:36:30 -05:00
Bryan Helmkamp
dc7b0af2bc Add cryptographic key validation to arc doctor
Validates mTLS certs (PEM parsing, expiry), JWT public/private keys
(Ed25519 PEM with base64 support), and session secret (hex, 256-bit
minimum) when the corresponding auth strategies are configured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 20:35:36 -05:00
Bryan Helmkamp
2afd63ba5a Simplify system dependency checks after code review
- Consolidate 4 duplicate parser functions into one `parse_version(re, output)`
- Use `LazyLock<Regex>` statics (matching codebase patterns in arc-util, arc-workflows)
- Replace 5-element tuple with named `DepSpec` struct
- Replace `raw_output: Option<String>` with `found: bool` (content was never used)
- Remove unnecessary `pub` from internal types and functions
- Parse stdout/stderr separately instead of concatenating
- Consolidate 10 parser tests into 6 via shared `parse_version`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:52:37 -05:00
Bryan Helmkamp
510d8b6df6 Add system dependency checks to arc doctor
Checks openssl, node, gh, and dot for presence, version, and command
success. Reports errors for missing/broken required tools and warnings
for optional ones. Also fixes pre-existing build break from
ApiAuthenticationStrategy -> ApiAuthStrategy rename.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:49:20 -05:00
Bryan Helmkamp
eb15b5254c Simplify mTLS implementation after code review
- Replace boolean params (mtls_enabled, mtls_optional) with ClientAuth enum
- Move serve_tls from serve.rs into tls module (encapsulate TLS internals)
- Derive client auth mode from AuthMode (eliminate duplicate strategy checks)
- Build JWT Validation once at startup, store in AuthStrategy (not per-request)
- Add tilde expansion for TLS cert paths (~/.arc/certs/...)
- Remove wasted String allocations from try_jwt/try_mtls return values
- Remove duplicate rustls dev-dependency from Cargo.toml
- Integration tests reuse tls::serve_tls instead of duplicating accept loop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:43:14 -05:00
Bryan Helmkamp
e0b8da08f2 Add mTLS authentication to arc-api
Support mutual TLS as an authentication strategy alongside JWT.
The server accepts both auth methods on the same port — mTLS if a
client cert is presented, JWT via Bearer header otherwise.

Config changes:
- Replace `authentication_strategy` (singular) with
  `authentication_strategies` (list of "jwt" and/or "mtls")
- Add `[api.tls]` section for cert, key, and CA paths

New files: tls.rs (rustls ServerConfig builder)
Modified: server_config.rs, jwt_auth.rs, serve.rs, lib.rs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:36:22 -05:00
Bryan Helmkamp
518b6ab9ac Fix JWT sub claim to use GitHub profile URL instead of API URL
The sub claim was set to https://api.github.com/user/{id} (numeric ID),
but the API-side username extractor splits on '/' expecting a login name.
Use https://github.com/{login} so the extracted segment matches the
allowed_usernames config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 16:41:33 -05:00
Bryan Helmkamp
fca63cb2e7 Enforce allowed_usernames at arc-api level via JWT sub claim
The API now extracts the GitHub username from the JWT sub claim
(last path segment of the profile URL) and checks it against
allowed_usernames from arc.toml. Fails closed: empty allowed list
or missing sub claim returns 403.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 16:33:04 -05:00
Bryan Helmkamp
07a765f5a2 Simplify doctor --live: share HTTP client, concurrent LLM probes, extract helper
- Extract apply_live_result() helper to deduplicate connectivity-result
  handling across check_api, check_web, and check_brave_search
- Merge probe_api/probe_web into single probe_url function
- Share one reqwest::Client across all HTTP probes
- Run LLM probes concurrently via futures::future::join_all instead of
  sequential loop (saves wall-clock time with multiple providers)
- Compute daytona_configured once before the live/offline branch
- Move live flag from DoctorReport struct field to render() parameter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 16:19:39 -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
859da7d035 Add user identity (sub claim) to JWT for arc-web → arc-api auth
The JWT now includes a `sub` claim containing the authenticated user's
GitHub profile URL (e.g. https://github.com/brynary), enabling the
backend to identify which user is making each request.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 15:38:03 -05:00
Bryan Helmkamp
84b2003a5a Add [web] config section and arc doctor command
Move auth config under [web.auth] in arc.toml to group web-specific
settings together. Add WebConfig with url field (default localhost:5173).
Add `arc doctor` command with checks for config, API, web, LLM providers,
Brave Search, sandbox, and GitHub App. Extract Provider::api_key_env_vars
and has_api_key to deduplicate validation logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 15:17:41 -05:00
Bryan Helmkamp
f9e30c7ae0 allow dead code in arc-devcontainer for now 2026-03-03 14:49:22 -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
d5b98af6d1 Support base64-encoded PEM for ARC_JWT_PUBLIC_KEY and ARC_JWT_PRIVATE_KEY
Some deployment environments (e.g. container orchestrators) make it
easier to pass secrets as single-line base64 strings rather than
multi-line PEM. Both env vars now auto-detect the format: if the value
starts with "-----" it's treated as raw PEM, otherwise base64-decoded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 14:39:49 -05:00
Bryan Helmkamp
b7f69a6b13 Add estimated output speed (tok/s) to model catalog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 14:38:50 -05:00
Bryan Helmkamp
cff594b422 Add context and cost columns to models test, tighten column widths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 14:36:43 -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
e3b31f50e1 Improve models list table: human-readable context, cost columns
Format context window as 1m/200k/128k instead of raw token counts.
Add input/output cost per million tokens column.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 14:28:26 -05:00
Bryan Helmkamp
43356dabb1 Update Inception model catalog: mercury → mercury-2
Replace mercury and mercury-coder with mercury-2 (128K context,
reasoning support, $0.75/M output). Remove mercury-edit (code editing
model not needed in catalog).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 14:13:49 -05:00
Bryan Helmkamp
72d71525f5 agent-design-memo.md 2026-03-03 12:44:28 -05:00
Bryan Helmkamp
ead284cc39 Add icons to sidebar groups, move Deployment to Guides
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 10:35:32 -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
Bryan Helmkamp
864cb5d853 Fix 3 feature spec bugs: shorthand version, option env names, install user vars
- Normalize string option values ("1.18") to {"version": "1.18"} so
  shorthand syntax correctly sets the VERSION env var
- Add option_id_to_env_name() to convert option IDs like "node-version"
  to NODE_VERSION per the dev container spec
- Emit _REMOTE_USER, _CONTAINER_USER, _REMOTE_USER_HOME, and
  _CONTAINER_USER_HOME in feature install snippets, threading remoteUser
  from devcontainer.json through resolve_features/generate_layer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 10:07:23 -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
c8c1ec6916 Fix stale config after setup and extract shared config path
Add reloadAppConfig() so setup-callback refreshes the in-memory config
after writing TOML, fixing a bug where the login redirect would fail.
Export ARC_CONFIG_PATH to eliminate duplicated path construction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 01:11:46 -05:00
Bryan Helmkamp
ae41f1c2c3 Move GitHub App ID and Client ID from env vars to TOML config
Non-secret config (app_id, client_id) now lives in [git] section of
~/.arc/arc.toml. Secrets remain in .env. Setup callback writes
non-secrets to TOML and secrets to .env.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 01:05:48 -05:00
Bryan Helmkamp
eab81aee99 Simplify feature fetch functions: extract shared helpers
- Extract read_feature_metadata(), extract_tgz(), and create_feature_dir()
  helpers to eliminate copy-paste across fetch_feature_oci/local/https
- Move ensure_oras() out of per-feature calls into a once-per-resolve
  check via oras_checked flag
- Simplify dockerfile::generate() to take &HashMap instead of
  &Option<HashMap>, removing an unnecessary clone in the caller

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:59:41 -05:00
Bryan Helmkamp
ba2b6faef3 Add e2e tests for 5 devcontainer spec gaps using local features
Create a local-features fixture with 3 local feature directories that
exercise all gap fixes through the full DevcontainerResolver pipeline:
- dependsOn auto-injection (base-utils not in features map, injected)
- feature containerEnv merge (3 features contribute env vars)
- feature lifecycle hooks (appended after devcontainer.json commands)
- local path feature references (all features use ./ paths)
- install ordering (dependsOn/installsAfter edges respected)

Also fix a concurrency bug: resolve_features now uses a unique temp
dir per invocation instead of a shared /tmp/devcontainer-features/
that caused parallel test corruption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:51:26 -05:00
Bryan Helmkamp
9748d2e3fe Update Cargo.lock for reqwest dependency in arc-devcontainer
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:48:30 -05:00
Bryan Helmkamp
cf05084f7c Fix clippy collapsible_if warning in topo_sort
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:46:23 -05:00
Bryan Helmkamp
afaffa2538 Update DEVCONTAINER-COMPATIBILITY.md for 5 new spec gaps
Document support for: feature dependsOn, feature containerEnv, feature
lifecycle hooks (onCreateCommand/postCreateCommand/postStartCommand),
subdirectory file discovery, and local path/HTTPS feature references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:45:44 -05:00
Bryan Helmkamp
f17c457a15 Add local path and HTTPS feature references to arc-devcontainer
Features can now be referenced as local paths (./feature or ../feature)
or HTTPS URLs (https://example.com/feature.tgz) in addition to OCI
registry references. A dispatch function routes fetches based on the
feature ID prefix. The oras CLI is only required for OCI refs.

Also updates dir_name_from_id to handle local paths (strip ./) and
URLs (strip .tgz extension), and passes devcontainer_dir to
resolve_features instead of build_context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:45:17 -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
62b4e9df74 Add subdirectory file discovery to arc-devcontainer
When neither .devcontainer/devcontainer.json nor .devcontainer.json
exists, scan .devcontainer/ for subdirectories containing a
devcontainer.json. Subdirectories are sorted alphabetically and the
first match is used. Standard locations still take priority.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:42:34 -05:00
Bryan Helmkamp
d437f038d0 Add feature lifecycle hooks to arc-devcontainer
Features can now declare onCreateCommand, postCreateCommand, and
postStartCommand lifecycle hooks. These are collected in install order
via ResolvedFeatures and appended after the devcontainer.json lifecycle
commands during resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:41:21 -05:00
Bryan Helmkamp
22e992d8ed Add feature containerEnv support to arc-devcontainer
Add containerEnv field to FeatureMetadata and introduce ResolvedFeatures
struct that collects container_env from each feature in install order.
Feature containerEnv is merged with devcontainer.json containerEnv
(devcontainer.json wins on conflicts) before generating the Dockerfile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:38:49 -05:00
Bryan Helmkamp
88508a4b5f Add feature dependsOn support to arc-devcontainer
Add dependsOn field to FeatureMetadata for declaring hard feature
dependencies per the devcontainer spec. The topo_sort function now
handles both installsAfter and dependsOn edges with deduplication.
Missing dependsOn targets are auto-injected (fetched and added to
the sorted feature set with the specified options).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:36:39 -05:00