Commit graph

178 commits

Author SHA1 Message Date
Cole Medin
cb44b96f7b
feat(providers/pi): interactive flag binds UIContext for extensions (#1299)
* feat(providers/pi): interactive flag binds UIContext for extensions

Adds `interactive: true` opt-in to Pi provider (in `.archon/config.yaml`
under `assistants.pi`) that binds a minimal `ExtensionUIContext` stub to
each session. Without this, Pi's `ExtensionRunner.hasUI()` reports false,
causing extensions like `@plannotator/pi-extension` to silently auto-approve
every plan instead of opening their browser review UI.

Semantics: clamped to `enableExtensions: true` — no extensions loaded
means nothing would consume `hasUI`, so `interactive` alone is silently
dropped. Stub forwards `notify()` to Archon's event stream; interactive
dialogs (select/confirm/input/editor/custom) resolve to undefined/false;
TUI-only setters (widgets/headers/footers/themes) no-op. Theme access
throws with a clear diagnostic — Pi's theme singleton is coupled to its
own `Symbol.for()` registry which Archon doesn't own.

Trust boundary: only binds when the operator has explicitly enabled
both flags. Extensions gated on `ctx.hasUI` (plannotator and similar)
get a functional UI context; extensions that reach for TUI features
still fail loudly rather than rendering garbage.

Includes smoke-test workflow documenting the integration surface.
End-to-end plannotator UI rendering requires plan-mode activation
(Pi `--plan` CLI flag or `/plannotator` TUI slash command) which is
out of reach for programmatic Archon sessions — manual test only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(providers/pi): end-to-end interactive extension UI

Three fixes that together get plannotator's browser review UI to actually
render from an Archon workflow and reach the reviewer's browser.

1. Call resourceLoader.reload() when enableExtensions is true.
   createAgentSession's internal reload is gated on `!resourceLoader`, so
   caller-supplied loaders must reload themselves. Without this,
   getExtensions() returns the empty default, no ExtensionRunner is built,
   and session.extensionRunner.setFlagValue() silently no-ops.

2. Set PLANNOTATOR_REMOTE=1 in interactive mode.
   plannotator-browser.ts only calls ctx.ui.notify(url) when openBrowser()
   returns { isRemote: true }; otherwise it spawns xdg-open/start on the
   Archon server host — invisible to the user and untestable from bash
   asserts. From the workflow runner's POV every Archon execution IS
   remote; flipping the heuristic routes the URL through notify(), which
   the ExtensionUIContext stub forwards into the event stream. Respect
   explicit operator overrides.

3. notify() emits as assistant chunks, not system chunks.
   The DAG executor's system-chunk filter only forwards warnings/MCP
   prefixes, and only assistant chunks accumulate into $nodeId.output.
   Emitting as assistant makes the URL available both in the user's
   stream and in downstream bash/script nodes via output substitution.

Plus: extensionFlags config pass-through (equivalent to `pi --plan` on the
CLI) applied via ExtensionRunner.setFlagValue() BEFORE bindExtensions
fires session_start, so extensions reading flags in their startup handler
actually see them. Also bind extensions with an empty binding when
enableExtensions is on but interactive is off, so session_start still
fires for flag-driven but UI-less extensions.

Smoke test (.archon/workflows/e2e-plannotator-smoke.yaml) uses
openai-codex/gpt-5.4-mini (ChatGPT Plus OAuth compatible) and bumps
idle_timeout to 600000ms so plannotator's server survives while a human
approves in the browser.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(providers/pi): keep Archon extension-agnostic

Remove the plannotator-specific PLANNOTATOR_REMOTE=1 env var write from
the Pi provider. Archon's provider layer shouldn't know about any
specific extension's internals. Document the env var in the plannotator
smoke test instead — operators who use plannotator set it via their shell
or per-codebase env config.

Workflow smoke test updated with:
- Instructions for setting PLANNOTATOR_REMOTE=1 externally
- Simpler assertion (URL emission only) — validated in a real
  reject-revise-approve run: reviewer annotated, clicked Send Feedback,
  Pi received the feedback as a tool result, revised the plan (added
  aria-label and WCAG contrast per the annotation), resubmitted, and
  reviewer approved. Plannotator's tool result signals approval but
  doesn't return the plan text, so the bash assertion now only checks
  that the review URL reached the stream (not that plan content flowed
  into \$nodeId.output — it can't).
- Known-limitation note documenting the tool-result shape so downstream
  workflow authors know to Write the plan separately if they need it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(providers/pi): keep e2e-plannotator-smoke workflow local-only

The smoke test is plannotator-specific (calls plannotator_submit_plan,
expects PLAN.md on disk, requires PLANNOTATOR_REMOTE=1) and is better
kept out of the PR while the extension-agnostic infra lands.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* style(providers/pi): trim verbose inline comments

Collapse multi-paragraph SDK explanations to 1-2 line "why" notes across
provider.ts, types.ts, ui-context-stub.ts, and event-bridge.ts. No
behavior change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(providers/pi): wire assistants.pi.env + theme-proxy identity

Two end-to-end fixes discovered while exercising the combined
plannotator + @pi-agents/loop smoke flow:

- PiProviderDefaults gains an optional `env` map; parsePiConfig picks
  it up and the provider applies it to process.env at session start
  (shell env wins, no override). Needed so extensions like plannotator
  can read PLANNOTATOR_REMOTE=1 from config.yaml without requiring a
  shell export before `archon workflow run`.

- ui-context-stub theme proxy returns identity decorators instead of
  throwing on unknown methods. Styled strings flow into no-op
  setStatus/setWidget sinks anyway, so the throw was blocking
  plannotator_submit_plan after HTTP approval with no benefit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(providers/pi): flush notify() chunks immediately in batch mode

Batch-mode adapters (CLI) accumulate assistant chunks and only flush on
node completion. That broke plannotator's review-URL flow: Pi's notify()
emitted the URL as an assistant chunk, but the user needed the URL to
POST /api/approve — which is what unblocks the node in the first place.

Adds an optional `flush` flag on assistant MessageChunks. notify() sets
it, and the DAG executor drains pending batched content before surfacing
the flushed chunk so ordering is preserved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: mention Pi alongside Claude and Codex in README + top-level docs

The AI assistants docs page already covers Pi in depth, but the README
architecture diagram + docs table, overview "Further Reading" section,
and local-deployment .env comment still listed only Claude/Codex.

Left feature-specific mentions alone where Pi genuinely lacks support
(e.g. structured output — Claude + Codex only).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: note Pi structured output (best-effort) in matrix + workflow docs

Pi gained structured output support via prompt augmentation + JSON
extraction (see packages/providers/src/community/pi/capabilities.ts).
Unlike Claude/Codex, which use SDK-enforced JSON mode, Pi appends the
schema to the prompt and parses JSON out of the result text (bare or
fenced). Updates four stale references that still said Claude/Codex-only:

- ai-assistants.md capabilities matrix
- authoring-workflows.md (YAML example + field table)
- workflow-dag.md skill reference
- CLAUDE.md DAG-format node description

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(providers/pi): default extensions + interactive to on

Extensions (community packages like @plannotator/pi-extension and
user-authored ones) are a core reason users pick Pi. Defaulting
enableExtensions and interactive to false previously silenced installed
extensions with no signal, leading to "did my extension even load?"
confusion.

Opt out in .archon/config.yaml when you want the prior behavior:

  assistants:
    pi:
      enableExtensions: false   # skip extension discovery entirely
      # interactive: false       # load extensions, but no UI bridge

Docs gain a new "Extensions (on by default)" section in
getting-started/ai-assistants.md that documents the three config
surfaces (extensionFlags, env, workflow-level interactive) and uses
plannotator as a concrete walk-through example.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 07:37:40 -05:00
Rasmus Widing
28908f0c75
feat(paths/cli/setup): unify env load + write on three-path model (#1302, #1303) (#1304)
* feat(paths/cli/setup): unify env load + write on three-path model (#1302, #1303)

Key env handling on directory ownership rather than filename. `.archon/` (at
`~/` or `<cwd>/`) is archon-owned; anything else is the user's.

- `<repo>/.env` — stripped at boot (guard kept), never loaded, never written
- `<repo>/.archon/.env` — loaded at repo scope (wins over home), writable via
  `archon setup --scope project`
- `~/.archon/.env` — loaded at home scope, writable via `--scope home` (default)

Read side (#1302):
- New `@archon/paths/env-loader` with `loadArchonEnv(cwd)` shared by CLI and
  server entry points. Loads both archon-owned files with `override: true`;
  repo scope wins.
- Replaced `[dotenv@17.3.1] injecting env (0) from .env` (always lied about
  stripped keys) with `[archon] stripped N keys from <cwd> (...)` and
  `[archon] loaded N keys from <path>` lines, emitted only when N > 0.
  `quiet: true` passed to dotenv to silence its own output.
- `stripCwdEnv` unchanged in semantics — still the only source that deletes
  keys from `process.env`; now logs what it did.

Write side (#1303):
- `archon setup` never writes to `<repo>/.env`. Writing there was incoherent
  because `stripCwdEnv` deletes those keys on every run.
- New `--scope home|project` (default home) targets exactly one archon-owned
  file. New `--force` overrides the merge; backup still written.
- Merge-only by default: existing non-empty values win, user-added custom keys
  survive, `<path>.archon-backup-<ISO-ts>` written before every rewrite. Fixes
  silent PostgreSQL→SQLite downgrade and silent token loss in Add mode.
- One-time migration note emitted when `<cwd>/.env` exists at setup start.

Tests: new `env-loader.test.ts` (6), extended `strip-cwd-env.test.ts` (+4 for
the log line), extended `setup.test.ts` (+10 for scope/merge/backup/force/
repo-untouched), extended `cli.test.ts` (+5 for flag parsing).

Docs: configuration.md, cli.md, security.md, cli-internals.md, setup skill —
all updated to the three-path model.

* fix(cli/setup): address PR review — scope/path/secret-handling edge cases

- cli: resolve --scope project to git repo root so running setup from a
  subdir writes to <repo-root>/.archon/.env (what loadArchonEnv reads at
  boot), not <subdir>/.archon/.env. Fail fast with a useful message when
  --scope project is used outside a git repo.
- setup: resolveScopedEnvPath() now delegates to @archon/paths helpers
  (getArchonEnvPath / getRepoArchonEnvPath) so Docker's /.archon home,
  ARCHON_HOME overrides, and the "undefined" literal guard all behave
  identically between the loader and the writer.
- setup: wrap the writeScopedEnv call in try/catch so an fs exception
  (permission denied, read-only FS, backup copy failure) stops the clack
  spinner cleanly and emits an actionable error instead of a raw stack
  trace after the user has completed the entire wizard.
- setup: checkExistingConfig(envPath?) — scope-aware existing-config read.
  Add/Update/Fresh now reflects the actual write target, not an
  unconditional ~/.archon/.env.
- setup: serializeEnv escapes \r (was only \n) so values with bare CR or
  CRLF round-trip through dotenv.parse without corruption. Regression
  test added.
- setup: merge path treats whitespace-only existing values ('   ') as
  empty, so a copy-paste stray space doesn't silently defeat the wizard
  update for that key forever. Regression test added.
- setup: 0o600 mode on the written env file AND on backup copies —
  writeFileSync+copyFileSync default to 0o666 & ~umask, which can leave
  secrets group/world-readable on a permissive umask.
- docs/cli.md + setup skill: appendix sections that still described the
  pre-#1303 two-file symlink model now reflect the three-path model.

* fix(paths/env-loader): Windows-safe assertion for home-scope load line

The test asserted the log line contained `from ~/`, which is opportunistic
tilde-shortening that only happens when the tmpdir lives under `homedir()`.
On Windows CI the tmpdir is on `D:\\` while homedir is `C:\\Users\\...`, so
the path renders absolute and the `~/` never appears.

Match on the count and the archon-home tmpdir segment instead — robust on
both Unix tilde-short paths and Windows absolute paths.
2026-04-20 12:49:14 +03:00
jinglesthula
3dedc22537
Fix incorrect substep numbering in setup.md (#1013)
Substeps for Step 4 were: 4a, 4b, 5c, 5d

Co-authored-by: Jon Anderson <jonathan.anderson@byu.edu>
2026-04-15 12:15:35 +03:00
Rasmus Widing
81859d6842
fix(providers): replace Claude SDK embed with explicit binary-path resolver (#1217)
* feat(providers): replace Claude SDK embed with explicit binary-path resolver

Drop `@anthropic-ai/claude-agent-sdk/embed` and resolve Claude Code via
CLAUDE_BIN_PATH env → assistants.claude.claudeBinaryPath config → throw
with install instructions. The embed's silent failure modes on macOS
(#1210) and Windows (#1087) become actionable errors with a documented
recovery path.

Dev mode (bun run) remains auto-resolved via node_modules. The setup
wizard auto-detects Claude Code by probing the native installer path
(~/.local/bin/claude), npm global cli.js, and PATH, then writes
CLAUDE_BIN_PATH to ~/.archon/.env. Dockerfile pre-sets CLAUDE_BIN_PATH
so extenders using the compiled binary keep working. Release workflow
gets negative and positive resolver smoke tests.

Docs, CHANGELOG, README, .env.example, CLAUDE.md, test-release and
archon skills all updated to reflect the curl-first install story.

Retires #1210, #1087, #1091 (never merged, now obsolete).
Implements #1176.

* fix(providers): only pass --no-env-file when spawning Claude via Bun/Node

`--no-env-file` is a Bun flag that prevents Bun from auto-loading
`.env` from the subprocess cwd. It is only meaningful when the Claude
Code executable is a `cli.js` file — in which case the SDK spawns it
via `bun`/`node` and the flag reaches the runtime.

When `CLAUDE_BIN_PATH` points at a native compiled Claude binary (e.g.
`~/.local/bin/claude` from the curl installer, which is Anthropic's
recommended default), the SDK executes the binary directly. Passing
`--no-env-file` then goes straight to the native binary, which
rejects it with `error: unknown option '--no-env-file'` and the
subprocess exits code 1.

Emit `executableArgs` only when the target is a `.js` file (dev mode
or explicit cli.js path). Caught by end-to-end smoke testing against
the curl-installed native Claude binary.

* docs: record env-leak validation result in provider comment

Verified end-to-end with sentinel `.env` and `.env.local` files in a
workflow CWD that the native Claude binary (curl installer) does not
auto-load `.env` files. With Archon's full spawn pathway and parent
env stripped, the subprocess saw both sentinels as UNSET. The
first-layer protection in `@archon/paths` (#1067) handles the
inheritance leak; `--no-env-file` only matters for the Bun-spawned
cli.js path, where it is still emitted.

* chore(providers): cleanup pass — exports, docs, troubleshooting

Final-sweep cleanup tied to the binary-resolver PR:

- Mirror Codex's package surface for the new Claude resolver: add
  `./claude/binary-resolver` subpath export and re-export
  `resolveClaudeBinaryPath` + `claudeFileExists` from the package
  index. Renames the previously single `fileExists` re-export to
  `codexFileExists` for symmetry; nothing outside the providers
  package was importing it.
- Add a "Claude Code not found" entry to the troubleshooting reference
  doc with platform-specific install snippets and pointers to the
  AI Assistants binary-path section.
- Reframe the example claudeBinaryPath in reference/configuration.md
  away from cli.js-only language; it accepts either the native binary
  or cli.js.

* test+refactor(providers, cli): address PR review feedback

Two test gaps and one doc nit from the PR review (#1217):

- Extract the `--no-env-file` decision into a pure exported helper
  `shouldPassNoEnvFile(cliPath)` so the native-binary branch is unit
  testable without mocking `BUNDLED_IS_BINARY` or running the full
  sendQuery pathway. Six new tests cover undefined, cli.js, native
  binary (Linux + Windows), Homebrew symlink, and suffix-only matching.
  Also adds a `claude.subprocess_env_file_flag` debug log so the
  security-adjacent decision is auditable.

- Extract the three install-location probes in setup.ts into exported
  wrappers (`probeFileExists`, `probeNpmRoot`, `probeWhichClaude`) and
  export `detectClaudeExecutablePath` itself, so the probe order can be
  spied on. Six new tests cover each tier winning, fall-through
  ordering, npm-tier skip when not installed, and the
  which-resolved-but-stale-path edge case.

- CLAUDE.md `claudeBinaryPath` placeholder updated to reflect that the
  field accepts either the native binary or cli.js (the example value
  was previously `/absolute/path/to/cli.js`, slightly misleading now
  that the curl-installer native binary is the default).

Skipped from the review by deliberate scope decision:

- `resolveClaudeBinaryPath` async-with-no-await: matches Codex's
  resolver signature exactly. Changing only Claude breaks symmetry;
  if pursued, do both providers in a separate cleanup PR.
- `isAbsolute()` validation in parseClaudeConfig: Codex doesn't do it
  either. Resolver throws on non-existence already.
- Atomic `.env` writes in setup wizard: pre-existing pattern this PR
  touched only adjacently. File as separate issue if needed.
- classifyError branch in dag-executor for setup errors: scope creep.
- `.env.example` "missing #" claim: false positive (verified all
  CLAUDE_BIN_PATH lines have proper comment prefixes).

* fix(test): use path.join in Windows-compatible probe-order test

The "tier 2 wins (npm cli.js)" test hardcoded forward-slash path
comparisons, but `path.join` produces backslashes on Windows. Caused
the Windows CI leg of the test suite to fail while macOS and Linux
passed. Use `path.join` for both the mock return value and the
expectation so the separator matches whatever the platform produces.
2026-04-14 17:56:37 +03:00
Rasmus Widing
39c6f05bad docs: consolidate Claude guidance into CLAUDE.md 2026-04-12 20:21:16 +03:00
Rasmus Widing
a7b3b94388 refactor: simplify provider rename follow-through
- ProviderDefaults → CodexProviderDefaults (symmetric with ClaudeProviderDefaults)
- Fix stale "AI client" comments in orchestrator-agent.ts and orchestrator.test.ts
- Remove dead createMockAgentProvider in test/mocks/streaming.ts (zero importers, wrong method names)
- Fix irregular whitespace in .claude/rules/workflows.md
2026-04-12 13:51:45 +03:00
Rasmus Widing
b9a70a5d17 refactor: complete provider rename in config types, logger domains, and docs
- AssistantDefaults → ProviderDefaults, ClaudeAssistantDefaults → ClaudeProviderDefaults
- Logger domains: client.claude → provider.claude, client.codex → provider.codex
- Fix stale JSDoc, error messages, and references in architecture docs, CHANGELOG, testing rules
2026-04-12 13:47:05 +03:00
Rasmus Widing
91c184af57 refactor: rename IAssistantClient to IAgentProvider
Rename the core AI provider interface and all related types, classes,
factory functions, and directory from clients/ to providers/.

Rename map:
- IAssistantClient → IAgentProvider
- ClaudeClient → ClaudeProvider
- CodexClient → CodexProvider
- getAssistantClient → getAgentProvider
- AssistantRequestOptions → AgentRequestOptions
- IWorkflowAssistantClient → IWorkflowAgentProvider
- AssistantClientFactory → AgentProviderFactory
- WorkflowAssistantOptions → WorkflowAgentOptions
- packages/core/src/clients/ → packages/core/src/providers/

NOT renamed (user-facing/DB-stored): assistant config key,
DEFAULT_AI_ASSISTANT env var, ai_assistant_type DB column.

No behavioral changes — purely naming.
2026-04-12 13:11:21 +03:00
Cole Medin
6da994815c
fix: strip CWD .env leak, remove subprocess allowlist, add first-event timeout (#1067, #1030, #1098, #1070)
* fix: strip CWD .env leak, enable platform adapters in serve, add first-event timeout (#1067)

Three bugs fixed: (1) Bun auto-loads CWD .env files before user code, leaking
non-overlapping keys into the Archon process — new stripCwdEnv() boot import
removes them before any module reads env. (2) archon serve hardcoded
skipPlatformAdapters:true, preventing Slack/Telegram/Discord from starting.
(3) Claude SDK query had no first-event timeout, causing silent 30-min hangs
when the subprocess wedges — new withFirstMessageTimeout wrapper races the
first event against a configurable deadline (default 60s).

Changes:
- Add @archon/paths/strip-cwd-env and strip-cwd-env-boot modules
- Import boot module as first import in CLI entry point
- Remove skipPlatformAdapters: true from serve.ts
- Add withFirstMessageTimeout + diagnostics to ClaudeClient
- Add CLAUDECODE=1 nested-session warning to CLI
- Add 9 unit tests (6 strip-cwd-env + 3 timeout)

Fixes #1067

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address review findings for PR #1092

Fixed:
- Clear setTimeout timer in withFirstMessageTimeout finally block (HIGH-1)
- Add strip-cwd-env-boot to server/src/index.ts for direct dev:server path (MEDIUM-1)
- Warn to stderr on non-ENOENT errors in stripCwdEnv (MEDIUM-2)
- Update stale configuration.md docs for new env-loading mechanism (HIGH-2)
- Add ARCHON_CLAUDE_FIRST_EVENT_TIMEOUT_MS and ARCHON_SUPPRESS_NESTED_CLAUDE_WARNING env vars to docs
- Add nested Claude Code hang troubleshooting entry
- Fix boot module JSDoc: "CLI and server" → "CLI" only
- Fix stripCwdEnv JSDoc: remove stale "override: true" reference
- Update .claude/rules/cli.md startup behavior section
- Update CLAUDE.md @archon/paths description with new exports

Tests added:
- Assert controller.signal.aborted on timeout
- Handle generator that completes immediately without yielding
- Strip distinct keys from different .env files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* simplify: replace string sentinel with typed error class in withFirstMessageTimeout

Replace the '__timeout__' string sentinel used to identify timeout rejections
with a dedicated FirstEventTimeoutError class. instanceof checks are more
explicit and robust than string comparison on error messages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: address review findings — dotenv version, docs, server warning, marker strip, tests

1. Align dotenv to ^17 (was ^16, rest of monorepo uses ^17.2.3)
2. Remove incorrect SUBPROCESS_ENV_ALLOWLIST claim from docs — the SDK
   bypasses the env option and uses process.env directly (#1097)
3. Add CLAUDECODE=1 warning to server entry point (was only in CLI)
4. Add diagnostic payload content test for withFirstMessageTimeout
5. Integrate #1097's finding: strip CLAUDECODE + CLAUDE_CODE_* session
   markers (except auth vars) + NODE_OPTIONS + VSCODE_INSPECTOR_OPTIONS
   from process.env at entry point. Pattern-matched on CLAUDE_CODE_*
   prefix rather than hardcoding 6 names, so future Claude Code markers
   are handled automatically. Auth vars (CLAUDE_CODE_OAUTH_TOKEN,
   CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX) are preserved.

   Root cause per #1097: the Claude Agent SDK leaks process.env into the
   spawned child regardless of the explicit env option, so the only way
   to prevent the nested-session deadlock is to delete the markers from
   process.env at the entry point.

Validation: bun run validate passes, 125 paths tests (6 new marker
tests), 60 claude tests (1 new diagnostic test), DATABASE_URL leak
verified stripped (target repo .env DATABASE_URL does not affect Archon
DB selection).

* refactor: remove SUBPROCESS_ENV_ALLOWLIST — trust user config, strip only CWD

The allowlist was wrong for a single-developer tool:
- It blocked keys the user intentionally set in ~/.archon/.env
  (ANTHROPIC_API_KEY, AWS_*, CLAUDE_CONFIG_DIR, MiniMax vars, etc.)
- It was bypassed by the SDK anyway (process.env leaks to subprocess
  regardless of the env option — see #1097)
- It attracted a constant stream of PRs adding keys (#1060, #1093, #1099)

New model: CWD .env keys are the only untrusted source. stripCwdEnv()
at entry point handles that. Everything in ~/.archon/.env + shell env
passes through to the subprocess. No filtering, no second-guessing.

Changes:
- Delete env-allowlist.ts and env-allowlist.test.ts
- Simplify buildSubprocessEnv() to return { ...process.env } with
  auth-mode logging (no token stripping — user controls their config)
- Replace 4 allowlist-based tests with 1 pass-through test
- Remove env-allowlist.test.ts from core test batch
- Update security.md and cli.md docs to reflect the new model

The CLAUDECODE + CLAUDE_CODE_* marker strip and NODE_OPTIONS strip
remain in stripCwdEnv() at entry point — those are process-level
safety (not per-subprocess filtering) and are needed regardless.

* fix: restore override:true for archon env, add integration tests

The integration tests caught a real issue: without override:true, the
~/.archon/.env load doesn't win over shell-inherited env vars. If the
user's shell profile exports PORT=9999 and ~/.archon/.env has PORT=3000,
the user expects Archon to use 3000.

stripCwdEnv() handles CWD .env files (untrusted). override:true handles
shell-inherited vars (trusted but less specific than ~/.archon/.env).
Different concerns, both needed.

Also adds 6 integration tests covering the full entry-point flow:
1. Global auth user with ANTHROPIC_API_KEY in CWD .env — stripped
2. OAuth token in archon env + random key in CWD — CWD stripped, archon kept
3. General leak test — nothing from CWD reaches subprocess
4. Same key in both CWD and archon — archon value wins
5. CLAUDECODE markers stripped even when not from CWD .env
6. CLAUDE_CODE_OAUTH_TOKEN survives marker strip

* test: add DATABASE_URL leak scenarios to env integration tests

* fix: move CLAUDECODE warning into stripCwdEnv, remove dead useGlobalAuth logic

Review findings addressed:

1. CLAUDECODE warning was dead code — the boot import deleted CLAUDECODE
   from process.env before the warning check in cli.ts/server/index.ts
   could fire. Moved the warning into stripCwdEnv() itself, emitted
   BEFORE the deletion. Removed duplicate warning code from both entry
   points.

2. useGlobalAuth token stripping removed (intentional, not regression) —
   the old code stripped CLAUDE_CODE_OAUTH_TOKEN and CLAUDE_API_KEY when
   useGlobalAuth=true. Per design discussion: the user controls
   ~/.archon/.env and all keys they set are intentional. If they want
   global auth, they just don't set tokens. Simplified buildSubprocessEnv
   to log auth mode for diagnostics only, no filtering.

3. Docs "no override needed" corrected — cli.md and configuration.md
   now reflect the actual code (override: true).

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Rasmus Widing <rasmus.widing@gmail.com>
2026-04-12 12:11:16 +03:00
Rasmus Widing
bbdcc65722 fix: address review — error handling, typing, stale docs 2026-04-10 16:01:41 +03:00
Rasmus Widing
eff8b0dc60 fix: sync all workspace versions from root and automate in release skill 2026-04-10 15:31:43 +03:00
Rasmus Widing
572b23e806
feat: auto-resolve Codex native binary in compiled builds (#995) (#1012)
* Investigate issue #978: one-command web UI install via archon serve

* fix: fail fast when Codex is used from compiled binary (#995)

The @openai/codex-sdk uses createRequire(import.meta.url) to resolve its
native platform binary, which breaks in bun --compile builds where
import.meta.url is frozen to the build host's path. Instead of a cryptic
createRequire crash, throw an actionable error directing users to install
from source or switch to the Claude provider.

Fixes #995

* fix: move binary guard to top of sendQuery, add beforeEach mock clear

Addresses code review: guard now fires before env-leak scanner to avoid
confusing error ordering, and MockCodex.mockClear() prevents cumulative
call counts across tests.

* feat: auto-resolve Codex native binary in compiled builds (#995)

Replace the fail-fast guard with full Codex binary resolution using the
SDK's codexPathOverride constructor option. In compiled binary mode, the
resolver checks (in order): CODEX_BIN_PATH env var, config
assistants.codex.codexBinaryPath, ~/.archon/vendor/codex/ cache, then
auto-downloads from npm registry.

In dev mode (bun link), returns undefined so the SDK uses its normal
node_modules-based resolution.

Adds codexBinaryPath config option so users can point to their own
Codex CLI install location.

Fixes #995

* fix: check env/config paths before platform detection for Windows CI

Move CODEX_BIN_PATH and config codexBinaryPath checks ahead of platform
detection so user-supplied paths work on any platform. Add win32-x64 and
win32-arm64 to the platform map for auto-download support.

* fix: normalize path separators in vendor test for Windows CI

* fix: remove auto-download, simplify resolver, fix review findings

- Remove ~100 lines of auto-download/checksum/extraction code from
  codex-binary-resolver.ts. Binary mode now throws with clear install
  instructions instead of silently downloading ~112 MB from npm.
- Fix init-promise leak: clear codexInitPromise on rejection so next
  call can retry after user installs Codex.
- Simplify Codex constructor call (remove conditional spread).
- Replace PLATFORM_BINARY_SUBPATH map with getVendorBinaryName() function
  that encodes the simple rule: Windows gets .exe, everything else gets
  codex. Rejects unsupported architectures explicitly.
- Restore specific log event name for env-leak gate config failure.
- Move codex-binary-resolver-dev.test.ts to its own bun test batch
  (mock.module isolation).
- Add tests: rejected-promise recovery, undefined-resolver result,
  binary-not-found-anywhere.
- Document CODEX_BIN_PATH in .env.example, codexBinaryPath in CLAUDE.md
  config example, vendor/codex/ in directory tree.
2026-04-10 14:59:03 +03:00
Rasmus Widing
6f1b72e131
feat: add automatic update check notification for binary users (#1039)
* feat: add automatic update check notification for binary users

Cache-based update check triggered by CLI commands and Web UI page load.
Fetches latest release from GitHub API with 24h cache staleness and 3s
timeout. CLI prints one-liner to stderr (suppressed by --quiet, skipped
for source builds). Web UI shows pulsing badge in TopNav linking to
release page. Also fixes release skill asset count (6 -> 7).

* fix: address review findings for update check notification

- Add BUNDLED_IS_BINARY guard to /api/update-check server route to
  prevent unintended GitHub API calls from source/dev builds
- Replace hand-crafted UpdateCheckResult interface with generated
  OpenAPI type (components['schemas']['UpdateCheckResponse'])
- Add staleness + checkedAt validation to getCachedUpdateCheck,
  matching readCache behavior
- Add debug-level logging to all bare catch blocks in update-check.ts
  for --verbose diagnostics
- Add releaseUrl guard in TopNav to prevent empty href links
- Fix SKILL.md: correct CI scope claim (Step 10 only, not 10-11) and
  clarify merge commit sync note
- Add tests: non-200 HTTP response, stale cache for getCachedUpdateCheck,
  missing checkedAt, and cache content verification
- Document /api/update-check endpoint and update-check.json cache file
  in CLAUDE.md and docs-web
- Regenerate api.generated.d.ts with UpdateCheckResponse schema

* refactor: simplify update check code

- Deduplicate getCachedUpdateCheck by delegating to readCache
- Extract shared noUpdate fallback object in server route
- Move guard clause outside try block in printUpdateNotice
- Fix cachePath variable scoping in readCache catch block
2026-04-10 14:10:33 +03:00
Rasmus Widing
2994d56861
fix: Promise.any race condition in validator script check (#1007) (#1010)
* Investigate issues #1001, #1002, #1003: interactive-prd workflow bugs

* fix: replace Promise.any with Promise.all in validator script check (#1007)

Promise.any resolves with the first fulfilled promise regardless of value.
Since fileExists always fulfills (never rejects), Promise.any could return
false even when a later extension check would return true — a race condition
that flaked on Windows CI.

Fixes #1007
2026-04-09 19:42:48 +03:00
Rasmus Widing
50f96f870e
feat: script node type for DAG workflows (bun/uv runtimes) (#999)
* feat: add ScriptNode schema and type guards (US-001)

Implements US-001 from the script-nodes PRD.

Changes:
- Add scriptNodeSchema with script, runtime (bun|uv), deps, and timeout fields
- Add ScriptNode type with never fields for mutual exclusivity
- Add isScriptNode type guard
- Add SCRIPT_NODE_AI_FIELDS constant (same as BASH_NODE_AI_FIELDS)
- Update dagNodeSchema superRefine and transform to handle script: nodes
- Update DagNode union type to include ScriptNode
- Add script node dispatch stub in dag-executor.ts (fails fast until US-003)
- Export all new types and values from schemas/index.ts
- Add comprehensive schema tests for ScriptNode parsing and validation

* feat: script discovery from .archon/scripts/

Implements US-002 from PRD.

Changes:
- Add ScriptDefinition type and discoverScripts() in script-discovery.ts
- Auto-detect runtime from file extension (.ts/.js->bun, .py->uv)
- Handle duplicate script name conflicts across extensions
- Add bundled defaults infrastructure (empty) for scripts
- Add tests for discovery, naming, and runtime detection

* feat: script execution engine (inline + named)

Implements US-003 from PRD.

Changes:
- Add executeScriptNode() in dag-executor.ts following executeBashNode pattern
- Support inline bun (-e) and uv (run python -c) execution
- Support named scripts via bun run / uv run
- Wire ScriptNode dispatch replacing 'not yet implemented' stub
- Capture stdout as node output, stderr as warning
- Handle timeout and non-zero exit
- Pass env vars for variable substitution
- Add tests for inline/named/timeout/failure cases

* feat: runtime availability validation at load time

Implements US-004 from PRD.

Changes:
- Add checkRuntimeAvailable() utility for bun/uv binary detection
- Extend validator.ts with script file and runtime validation
- Integrate script validation into parseWorkflow flow in loader.ts
- Add tests for runtime availability detection

* feat: dependency installation for script nodes

Implements US-005 from PRD.

Changes:
- Support deps field for uv nodes: uvx --with dep1... for inline
- Support uv run --with dep1... for named uv scripts
- Bun deps are auto-installed at runtime via bun's native mechanism
- Empty/omitted deps field produces no extra flags
- Add tests for dep injection into both runtimes

* test: integration tests and validation for script nodes

Implements US-006 from PRD.

Changes:
- Fill test coverage gaps for script node feature
- Add script + command mutual exclusivity schema test
- Add env var substitution tests ($WORKFLOW_ID, $ARTIFACTS_DIR in scripts)
- Add stderr handling test (stderr sent to user as platform message)
- Add missing named script file validation tests to validator.test.ts
- Full bun run validate passes

* fix: address review findings in script nodes

- Extract isInlineScript to executor-shared.ts (was duplicated in
  dag-executor.ts and validator.ts)
- Remove dead warnMissingScriptRuntimes from loader.ts (validator
  already covers runtime checks)
- Remove path traversal fallback in executeScriptNode — error when
  named script not found instead of executing arbitrary file paths
- Memoize checkRuntimeAvailable to avoid repeated subprocess spawns
- Add min(1) to scriptNodeSchema.script field for consistency
- Replace dynamic import with static import in validator.ts

* fix(workflows): address review findings for script node implementation

Critical fixes:
- Wrap discoverScripts() in try-catch inside executeScriptNode to prevent
  unhandled rejections when script discovery fails (e.g. duplicate names)
- Add isScriptNode to isNonAiNode check in loader.ts so AI-specific fields
  on script nodes emit warnings (activates SCRIPT_NODE_AI_FIELDS)

Important fixes:
- Surface script stderr in user-facing error messages on non-zero exit
- Replace uvx with uv run --with for inline uv scripts with deps
- Add z.string().min(1) validation on deps array items
- Remove unused ScriptDefinition.content field and readFile I/O
- Add logging in discoverAvailableScripts catch block
- Warn when deps is specified with bun runtime (silently ignored)

Simplifications:
- Merge BASH_DEFAULT_TIMEOUT and SCRIPT_DEFAULT_TIMEOUT into single
  SUBPROCESS_DEFAULT_TIMEOUT constant
- Use scriptDef.runtime instead of re-deriving from extname()
- Extract shared formatValidationResult helper, deduplicate section comments

Tests:
- Add isInlineScript unit tests to executor-shared.test.ts
- Add named-script-not-found executor test to dag-executor.test.ts
- Update deps tests to expect uv instead of uvx

Docs:
- Add script: node type to CLAUDE.md node types and directory structure
- Add script: to .claude/rules/workflows.md DAG Node Types section
2026-04-09 14:48:02 +03:00
Rasmus Widing
9adc54afdd
fix(release): wire release workflow to scripts/build-binaries.sh (#986) (#987)
* Investigate issue #986: release workflow bypasses build-binaries.sh

* fix(release): wire release workflow to scripts/build-binaries.sh (#986)

The release workflow called `bun build --compile` inline, bypassing the
build-time-constants rewrite in scripts/build-binaries.sh. Released binaries
shipped with BUNDLED_IS_BINARY=false, causing `archon version` to crash with
"package.json not found (bad installation?)" on v0.2.13 and v0.3.0.

Changes:
- Refactor scripts/build-binaries.sh to support single-target mode via
  TARGET/OUTFILE env vars; preserve multi-target local-dev mode unchanged.
  Always --minify; skip --bytecode for Windows targets.
- Update .github/workflows/release.yml to call the script with the matrix
  target/outfile, stripping the 'v' prefix and shortening the SHA.
- Add a post-build smoke test on bun-linux-x64 that asserts the binary
  reports "Build: binary" and the tag version (would have caught both
  broken releases).
- Document local CI-equivalent build invocation in the test-release skill.

Fixes #986

* chore: archive investigation for issue #986

* skill(release): document Homebrew formula SHA sync and verification

The release skill previously stopped at tag creation and GitHub release
creation. Formula updates were happening manually outside the skill and
consistently drifting — v0.3.0's homebrew/archon.rb had the correct
version string but SHAs from v0.2.13, because whoever updated it did so
before the release workflow had built the v0.3.0 binaries.

Add three new steps to close the gap:

- Step 10: wait for release workflow, fetch checksums.txt, update
  homebrew/archon.rb atomically with new version AND new SHAs in a
  single commit. The formula is regenerated from a template rather
  than edited in place, eliminating the risk of partial updates.
- Step 11: sync the rewritten formula to coleam00/homebrew-archon
  tap repo (the file users actually install from). Fails loudly if
  push access is missing instead of silently skipping.
- Step 12: run /test-release brew and /test-release curl-mac to
  verify the install path actually works end-to-end before announcing
  the release. A release that installs but crashes is worse than no
  release at all.

Also:
- Add a prominent warning at the top about the chicken-and-egg
  relationship between version and SHAs (they must move atomically,
  and SHAs can only be known after binaries exist).
- Add three new rules to "Important Rules":
  * never update version without also updating SHAs
  * never skip the tap sync (main repo formula is just a template)
  * never announce a release that failed /test-release

Related to #986 (release workflow bypasses build-binaries.sh) — both
bugs block the next working release; fixing only one leaves the
install path broken.

* fix(release): address review feedback on smoke test and restore trap

- release.yml: use inputs.version on workflow_dispatch so the build step
  doesn't embed the branch name as the binary version
- release.yml: compare smoke-test version against the stripped semver
  instead of the raw ref, so the check doesn't rely on the CLI re-adding
  a 'v' prefix
- release.yml: fail fast if the binary crashes on first invocation
  instead of falling through to the 'wrong build type' branch
- release.yml: add a second smoke step that runs 'workflow list' in a
  temp repo to catch the class of bug where bundled defaults fail to
  embed in the binary
- build-binaries.sh: drop '2>/dev/null' on the EXIT trap so restore
  failures surface in the log with a clear WARNING
- test-release skill: fix the single-target verification path
2026-04-08 15:02:09 +03:00
Rasmus Widing
4579422e41 skill(test-release): add smoke-test skill for released binaries
Automates release verification via three install paths: brew (Homebrew
tap), curl-mac (install.sh to a sandboxed tmp dir on macOS), and
curl-vps (install.sh on a remote Linux VPS). Runs a fixed suite
(version, workflow list, assist workflow, env-leak gate, isolation
list), captures SHA256 of the tested binary, and cleans up on exit
so the dev bun-link binary is never disturbed.

Use when cutting a new release or reproducing a user bug report on
the released version. NOT for testing dev changes — those use
bun run validate or direct source invocation.

See issue (to be filed) for the release workflow fix that unblocks
the brew and curl-mac paths end-to-end.
2026-04-08 14:36:34 +03:00
Rasmus Widing
5d4979e72d fix: address review findings from PR #1015
- Update /init and /worktree error messages to reference /register-project instead of removed /clone and /setcwd commands
- Update .claude/rules/orchestrator.md: fix deterministic gate count (7→10), add /commands, /init, /worktree to table, remove 9 deleted commands, fix getTriggerForCommand example, update TransitionTrigger values list, fix anti-pattern count
- Add isError handling to environments query in ProjectDetail.tsx, matching the established pattern used by the conversations and runs queries
2026-04-06 20:08:55 +03:00
Rasmus Widing
591e234d80
Merge pull request #1001 from dynamous-community/feat/docs-dir-variable
feat: add $DOCS_DIR variable for configurable documentation path
2026-04-06 17:27:58 +03:00
Rasmus Widing
e4a011e483 fix: address review findings for $DOCS_DIR variable
- Fix YAML injection in setup.ts: quote docs path value to prevent
  malformed config from special characters
- Add try/catch around file I/O in setup.ts (matches skill-install pattern)
- Add user feedback when docs: key already exists in config
- Add defensive fallback in substituteWorkflowVariables (docsDir || 'docs/')
- Add warn log for whitespace-only docs.path in config-loader
- Add $DOCS_DIR to CLAUDE.md variable list and config example
- Add $DOCS_DIR to .claude/rules/workflows.md variable table
- Add $DOCS_DIR to all docs-web variable tables (6 pages)
- Add config-loader tests for docsPath (propagation, trim, undefined)
- Add executor tests for docsPath default resolution
- Add executor-shared test for empty-string docsDir fallback
2026-04-06 17:25:37 +03:00
Rasmus Widing
c99a020681
Merge pull request #996 from dynamous-community/archon/task-fix-dead-streaming-config
fix: remove dead GITHUB_STREAMING_MODE config
2026-04-06 16:49:31 +03:00
Rasmus Widing
94a12f6d85 fix: address review findings for ANTHROPIC_API_KEY removal
- Add deprecation warning when ANTHROPIC_API_KEY is set but neither
  CLAUDE_CODE_OAUTH_TOKEN nor CLAUDE_API_KEY is present, so users
  migrating from direct Anthropic SDK usage get a clear hint
- Clarify JSDoc: replace "(backwards compatibility)" with more precise
  "Auto-detect — use explicit tokens if present, otherwise fall back
  to global auth" to avoid implying a legacy alias still exists
- Add regression test: ANTHROPIC_API_KEY alone falls through to global
  auth path (hasExplicitTokens=false), preventing silent re-introduction
  of the startup warning bug
- Update .claude/agents/sdk-verifier.md: replace stale ANTHROPIC_API_KEY
  checklist reference with CLAUDE_CODE_OAUTH_TOKEN/CLAUDE_API_KEY
2026-04-06 16:34:45 +03:00
Rasmus Widing
bf0022815f fix: remove remaining GITHUB_STREAMING_MODE / streaming.github references
- Remove `github` field from `safeConfigSchema` to match `SafeConfig` interface
- Remove `GITHUB_STREAMING_MODE` from GitHub skill guide checklist and example env block
- Remove `streaming.github` row and `GITHUB_STREAMING_MODE` row from config skill guide tables
- Remove `streaming.github: batch` line from new-developer-guide.md config diagram
2026-04-06 16:30:58 +03:00
Rasmus Widing
7e0bb63ef4
Merge pull request #906 from dynamous-community/archon/thread-ff3f81a2
feat: add docker-extend skill for Docker user customization
2026-04-06 15:24:53 +03:00
Rasmus Widing
00f5e6d0dc fix: address review findings for file upload feature
- Fix client-server MIME allowlist mismatch: add extension-based fallback
  to server's isAllowedUploadType() for files with empty browser MIME types
- Normalize MIME type (strip parameters) before storing in AttachedFile
  to prevent prompt injection via crafted Content-Type headers
- Sanitize filenames in error responses before display
- Log rollback errors instead of silently swallowing with .catch(() => undefined)
- Add warn-level logs to parseBody() and JSON parse catch blocks
- Surface server error details (4xx) in UI instead of generic message
- Collect all file rejection reasons and show them together
- Guard meta.files mapping against malformed entries in message history
- Add .max(5) to multipart schema for OpenAPI spec accuracy
- Remove dual content-type from OpenAPI route (causes validation conflicts)
- Simplify fileMeta/addMessage branching and conditional spreads
- Update CLAUDE.md and isolation-patterns.md with uploads/ directory
2026-04-06 15:19:36 +03:00
Rasmus Widing
2de90071a8 feat: migrate all docs to Starlight content collections
- Migrate 38 docs across 6 categories: getting-started (5), guides (9),
  adapters (5), deployment (6), reference (7), contributing (6)
- Apply accuracy fixes: old project name, wrong isolation paths,
  missing CLI commands, stale workflow names, outdated migration lists
- Fix frontmatter schema errors (invalid area values, env code blocks)
- Add .claude/rules for dx-quirks and isolation-patterns
- 45 pages build successfully with Pagefind search index
2026-04-06 12:19:56 +03:00
Leex
d35a603269 feat: add docker-extend skill for Docker user customization
Adds interactive skill that guides users through setting up
Dockerfile.user and docker-compose.override.yml for personal
Docker tool customization. Depends on #920 for the example files.
2026-04-05 22:00:37 +02:00
Cole Medin
ae346c2a67 feat: prepare for open-source migration to coleam00/Archon
- Replace all dynamous-community/remote-coding-agent references with coleam00/Archon
- Replace all ghcr.io/dynamous-community/remote-coding-agent with ghcr.io/coleam00/archon
- Change license from proprietary Dynamous to MIT
- Fix cd directory name in docs (remote-coding-agent → Archon)
- Remove hardcoded local paths from skills and docs
- Add Windows x64 binary to release pipeline (cross-compiled from Linux)
- Add --minify --bytecode flags to binary compilation
- Create PowerShell install script (scripts/install.ps1)
- Fix isBinaryBuild() detection for Bun 1.3.5+ (use import.meta.dir virtual FS check)
- Scaffold Astro Starlight docs site at website/ (Astro 6 + Starlight 0.38)
- Add deploy-docs.yml workflow for GitHub Pages
- Update test.yml branch triggers (develop → dev)
- Add install section with curl/PowerShell/Homebrew/Docker to README
- Add badges and archon.diy docs link to README
- Create SECURITY.md with vulnerability disclosure policy
- Update CONTRIBUTING.md for public audience
- Add website/ and eslint ignores for Astro-generated files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 10:47:22 -05:00
Cole Medin
21b6811a2e ux: update handoff wording to prompt user to confirm when finished
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:36:05 -05:00
Cole Medin
1b9e70a78f ux: make setup spawn failure feel like a natural handoff, not an error
Replace console.error + alarming "Failed to open terminal" message with
calm instructional text guiding the user to run archon setup manually.
Update the AI guide (setup.md) to present both auto-spawn and manual
paths as equally valid, not success/failure.

Closes #965

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:32:29 -05:00
Cole Medin
3f2eea6cf8 fix: extract PR number from URL path instead of first digits in message
Usernames containing digits (e.g., coleam00) caused the fetch-pr bash
node to extract the wrong number, failing `gh pr view`. Now matches
`/pull/<number>` specifically. Also hardened the example dag-workflow
fetch-issue node with a similar URL-first extraction.

Closes #958

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 07:52:03 -05:00
Rasmus Widing
1a6e07842e docs(rules): document chat vs forge adapter handler patterns 2026-04-02 10:19:03 +03:00
Cole Medin
fd74979427 docs(skills): add interactive workflow relay protocol reference
Add references/interactive-workflows.md teaching Claude Code to act as a
transparent pipe during interactive workflows — show output verbatim, pass
input verbatim, no commentary or summarization.

Update SKILL.md routing table to direct interactive workflow invocations
to the new reference doc, and mark archon-piv-loop and archon-interactive-prd
in the workflow selection table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 12:21:05 -05:00
Cole Medin
9244fd80df
docs: document agent-browser as optional dependency for E2E workflows (#876)
* docs: document agent-browser as optional dependency for E2E workflows (#787)

agent-browser is used by archon-validate-pr, validate-ui skill, and replicate-issue
skill but installation requirements were not documented. Users hitting these workflows
got confusing errors.

Changes:
- Added installation section to .claude/skills/agent-browser/SKILL.md
- Created docs/e2e-testing.md general cross-platform setup guide
- Added agent-browser as optional dependency in README.md prerequisites
- Added E2E troubleshooting section to docs/troubleshooting.md
- Added cross-reference from docs/e2e-testing-wsl.md to general guide

Fixes #787

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: format + fix test references for OpenAPIHono migration

Prettier auto-formatted two files and fixed 5 test cases that referenced
`Hono` instead of `OpenAPIHono` after the OpenAPI route refactor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(docs): accurately describe agent-browser fallback as prompt instruction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 16:24:46 -05:00
Cole Medin
20ac7248ce fix: address review findings for /update-project and /remove-project
- Add rowCount check to updateCodebase() so it throws on missing record
  instead of silently no-oping (consistent with updateConversation/updateSession)
- Wrap updateCodebase call in try/catch with user-friendly error message
- Fix log event names to follow {domain}.{action}_{state} convention
  (project.register_completed, project.update_completed, project.remove_completed)
- Add deterministic_command debug log for all three project commands
- Update .claude/rules/orchestrator.md to reflect 7 deterministic commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 08:41:28 -05:00
Rasmus Widing
68bbeaa3eb
feat(cli): add archon validate workflows/commands (#832)
* feat(cli): add `archon validate workflows/commands` for workflow validation

Adds Level 3 resource resolution validation on top of the existing Level 1-2
(syntax + structure) checks in parseWorkflow(). The new `validate` CLI
command creates a self-correcting feedback loop for AI agents authoring
workflows: write → validate → read actionable errors → fix → re-validate.

New files:
- packages/workflows/src/validator.ts: Core validation (command resolution,
  MCP config checks, skill directory checks, provider compat warnings,
  Levenshtein "did you mean?" suggestions)
- packages/cli/src/commands/validate.ts: CLI command with human-readable
  and --json output formats

Also:
- Extract findMarkdownFilesRecursive to @archon/paths for cross-package use
- Update skill references (workflow-dag.md, cli-commands.md) with validate docs

Closes #829

* fix: address review findings for validate workflows/commands

- Fix process.env.HOME → homedir() for reliable skill path resolution
- Make WorkflowValidationResult.filename optional, remove fabricated
  filename for L3-validated workflows, add makeWorkflowResult factory
- Narrow catch blocks to ENOENT-only in findMarkdownFilesRecursive,
  buildValidationConfig, and discoverAvailableCommands
- Remove dead try/catch around findMarkdownFilesRecursive calls
- Fix totalWarnings count to use issue-level check instead of
  overlapping with valid count
- Add validator.test.ts with 31 tests covering levenshtein, findSimilar,
  command/MCP/workflow resource validation, and command discovery
- Update CLAUDE.md, cli-user-guide.md, authoring-workflows.md with
  validate commands documentation
2026-03-26 13:58:12 +02:00
Rasmus Widing
d6022e9948
docs: fix skill reference accuracy issues from post-merge review of #786 (#830)
Address 10 documentation accuracy issues found during post-merge review:

- Add context: shared as valid value alongside context: fresh
- Fix clearContext: true to context: fresh (nonexistent field)
- Include bash nodes in retry scope (was command/prompt only)
- Remove stale Steps/Loops columns from variables scope table
- Add all missing FATAL and TRANSIENT error classification patterns
- Remove unverifiable SDK retry internals claim
- Add clarifying comment for assistant vs defaultAssistant config keys
- Fix stale deprecation notice for removed steps format
- Fix frontmatter field optionality in docs/authoring-commands.md
- Document context default behavior for parallel vs sequential layers
2026-03-26 13:17:13 +02:00
Rasmus Widing
bb7ebf4465
feat(skill): expand archon skill into self-contained meta-skill (#786)
* feat(skill): expand archon skill into self-contained meta-skill

Rewrites the archon skill from a run-only workflow dispatcher into a
complete CLI operator skill that teaches Claude Code how to create
workflows, author commands, manage configs, and operate the full Archon
ecosystem from any repository with only the CLI installed.

New reference files cover all three workflow modes (steps, loop, DAG),
DAG advanced features (hooks, MCP, skills, structured output), command
file authoring, variable substitution, CLI commands, and repo init.

Includes working YAML/MD examples for each mode that can be used as
starting points. All fields verified against types.ts and executor code.

* refactor(skill): update meta-skill for DAG-only workflow engine

Remove deprecated step-based and loop-based workflow references.
The workflow engine now uses a single format (nodes/DAG) with four
node types: command, prompt, bash, and loop.

Changes:
- Delete workflow-steps.md and workflow-loops.md references
- Delete step-workflow.yaml and loop-workflow.yaml examples
- Rewrite workflow-dag.md as the single workflow authoring guide
  covering all four node types including loop nodes
- Add provider compatibility table to dag-advanced.md
- Update SKILL.md routing and quick-start for single workflow type
- Update dag-workflow.yaml example to show all four node types
- Add clear guidance that examples are starting points, not templates

* docs(skill): add Claude vs Codex provider comparison for MCP/skills

Explains how each provider handles MCP servers and skills:
- Claude: per-node via workflow YAML (mcp: and skills: fields)
- Codex: globally via ~/.codex/config.toml and ~/.agents/skills/

The Codex CLI picks these up automatically since Archon inherits the
full process environment. No Archon-specific configuration needed.

* fix(skill): address PR review — stale refs, incomplete routing table

- Fix archon-fix-github-issue-dag → archon-fix-github-issue in resume example
- Remove stale steps: YAML example from authoring-commands.md
- Expand workflow routing table from 5 to 14 workflows (all defaults)
- Remove "step-based" reference from retry section in dag-advanced.md
2026-03-26 13:04:02 +02:00
Rasmus Widing
ef04321eef
refactor(workflows)!: remove sequential execution mode, DAG becomes sole format (#805)
* refactor(workflows)!: remove sequential execution mode, DAG becomes sole format

Remove the steps-based (sequential) workflow execution mode entirely.
All workflows now use the nodes-based (DAG) format exclusively.

- Convert 8 sequential default workflows to DAG format
- Delete archon-fix-github-issue sequential (DAG version absorbs triggers)
- Remove SingleStep, ParallelBlock, StepWorkflow types and guards
- Gut executor.ts from ~2200 to ~730 lines (remove sequential loop)
- Remove step_started/completed/failed and parallel_agent_* events
- Remove logStepStart/Complete and logParallelBlockStart/Complete
- Delete SequentialEditor, StepProgress, ParallelBlockView components
- Remove sequential mode from workflow builder and execution views
- Delete executor.test.ts (4395 lines), update ~45 test fixtures
- Update CLAUDE.md and docs to reflect DAG-only format

BREAKING CHANGE: Workflows using `steps:` format are no longer supported.
Convert to `nodes:` (DAG) format. The loader provides a clear error message
directing users to the migration guide.

* fix: address review findings — guard errors, remove dead code, add tests

- Guard logNodeSkip/logWorkflowError against filesystem errors in dag-executor
- Move mkdir(artifactsDir) inside try-catch with user-friendly error
- Remove startFromStep dead parameter from executeWorkflow signature
- Remove isDagWorkflow() tautology and all callers (20+ sites)
- Remove dead BuilderMode/mode state from frontend components
- Remove vestigial isLoop, selectedStep, stepIndex, step_index fields
- Remove "DAG" prefix from user-facing resume/error messages
- Fix 5 stale docs (README, getting-started, authoring-commands, web adapter)
- Update event-emitter tests to use node events instead of removed step events
- Add executor-shared.test.ts (12 tests) for substituteWorkflowVariables
- Add executor.test.ts (11 tests) for concurrent-run, model resolution, resume

* fix(workflows): add migration guide, port preamble tests, improve error message

- Add docs/sequential-dag-migration-guide.md with 3 conversion patterns
  (single step, chain with clearContext, parallel block) and a Claude Code
  migration command for automated conversion
- Update loader error message to point to migration guide and include
  ready-to-run claude command
- Port 8 preamble tests from deleted executor.test.ts to new
  executor-preamble.test.ts: staleness detection (3), concurrent-run
  guard (3), DAG resume (2)

Addresses review feedback from #805.

* fix(workflows): update loader test to match new error message wording

* fix: address review findings — fail stuck runs, remove dead code, fix docs

- Mark workflow run as failed when artifacts mkdir fails (prevents
  15-min concurrent-run guard block)
- Remove vestigial totalSteps from WorkflowStartedEvent and executor
- Delete dead WorkflowToolbar.tsx (369 lines, no importers)
- Remove stepIndex prop from StepLogs (always 0, label now "Node logs")
- Restore cn() in StatusBar for consistent conditional classes
- Promote resume-check log to error, add errorType to failure logs
- Remove ghost $PLAN/$IMPLEMENTATION_SUMMARY from docs (never implemented)
- Update workflows.md rules to DAG-only format
- Fix migration guide trigger_rule example
- Clean up blank-line residues and stale comments

* fix: resolve rebase conflicts with #729 (forkSession) and #730 (dashboard)

- Remove sequential forkSession/persistSession code from #729 (dead after
  sequential removal)
- Fix loader type narrowing for DagNode context field
- Update dashboard components from #730 to use dagNodes instead of steps
- Remove WorkflowStepEvent/ParallelAgentEvent from dashboard SSE hook
2026-03-26 11:27:34 +02:00
Rasmus Widing
73cb4784a1
refactor(core): break up god function in command-handler (#742)
* refactor(core): break up god function in command-handler

Extract handleWorktreeCommand, handleWorkflowCommand, handleRepoCommand,
and handleRepoRemoveCommand from the 1300-line handleCommand switch
statement. Add resolveRepoArg helper to eliminate duplication between
repo and repo-remove cases. handleCommand now contains ~200 lines of
routing logic only.

* fix: address review findings from PR #742

command-handler.ts:
- Replace fragile 'success' in discriminator with proper ResolveRepoArgResult
  discriminated union (ok: true/false) and fix misleading JSDoc
- Add missing error handling to worktree orphans, workflow cancel, workflow reload
- Fix isolation_env_id UUID used as filesystem path in worktree create/list/orphans
  (look up working_path from DB instead)
- Add cmd. domain prefix to all log events per CLAUDE.md convention
- Add identifier/isolationEnvId context to repo_switch_failed and worktree_remove_failed logs
- Capture isCurrentCodebase before mutation in handleRepoRemoveCommand
- Hoist duplicated workflowCwd computation in handleWorkflowCommand
- Remove stale (Phase 3D) comment marker

docs:
- Remove all /command-invoke references from CLAUDE.md, README.md,
  docs/architecture.md, and .claude/rules/orchestrator.md
- Update command list to match actual handleCommand cases
- Replace outdated routing examples with current AI router pattern

* refactor: remove MAX_WORKTREES_PER_CODEBASE limit

Worktree count is no longer restricted. Remove the constant, the
limit field from WorktreeStatusBreakdown, the limit_reached block
reason, formatWorktreeLimitMessage, and all associated tests.

* fix: address review findings — error handling, log prefixes, tests, docs

- Wrap workflow list discoverWorkflowsWithConfig in try/catch (was the
  only unprotected async call among workflow subcommands)
- Cast error to Error before logging in workflow cancel/status catch blocks
- Add cmd. domain prefix to all command-handler log events (12 events)
- Update worktree create test to use UUID isolation_env_id with DB lookup
- Add resolveRepoArg boundary tests (/repo 0, /repo N > count)
- Add worktree cleanup subcommand tests (merged, stale, invalid type)
- Add updateConversation assertion to repo-remove session test
- Fix stale docs: architecture.md command handler section, .claude → .archon
  paths, remove /command-invoke from commands-reference, fix github.md example
2026-03-25 11:01:03 +02:00
Cole Medin
d5cffaaeeb Release skill: add GitHub Release creation to post-merge step 2026-03-20 10:32:13 -05:00
Rasmus Widing
845c816226
feat: default worktree isolation for CLI + auto-detect base branch (#692)
* feat: default worktree isolation for CLI + auto-detect base branch

- CLI now creates a worktree by default (matching all other adapters)
- Branch names auto-generated as {workflowName}-{timestamp}
- --no-worktree opts out of isolation (standalone flag, no longer requires --branch)
- All generated branch names prefixed with archon/ for clear namespace
- Base branch auto-detected from git (symbolic-ref → origin/main → origin/master)
- Config worktree.baseBranch still overrides auto-detection
- $BASE_BRANCH in workflow prompts auto-resolves without config
- Ignore .claude/skills/ from ESLint

* fix: address PR review findings — error handling, tests, docs

- Add warn log for silent getDefaultBranch catch in executor.ts
- Fix branchToSync bug: don't pass fromBranch as sync target
  (fromBranch is the worktree start-point, not the base to sync)
- Add user-facing warning when isolation is silently skipped
- Add errorType to codebase_auto_registration_failed log
- Consolidate all validation guards in workflowRunCommand
  (cli.ts keeps them for UX fast-path, workflowRunCommand is
  the authoritative boundary for programmatic callers)
- Add tests: validation guards, default isolation, --no-worktree
  skip, isolation-skipped warning, auto-detect $BASE_BRANCH success
- Add loadRepoConfig to @archon/core mock in workflow tests
- Update docs: CLAUDE.md, cli-user-guide, configuration,
  authoring-workflows, worktree-orchestration, README, cli.md rule
  — all updated for default isolation, archon/ prefix, optional
  baseBranch with auto-detection

* refactor: simplify isolation branch logic and fix log naming

- Split shouldIsolate into wantsIsolation + codebase check to
  eliminate redundant double-check of codebase
- Simplify else-if chain: use wantsIsolation instead of re-testing
  already-false conditions
- Deduplicate isolation-skipped warning messages
- Fix log event: base_branch.auto_detect_failed →
  workflow.base_branch_auto_detect_failed (project naming convention)

* fix: fail fast when isolation cannot be created instead of silent fallback

When the user hasn't opted out with --no-worktree, failing to create
a worktree (DB error or not in a git repo) now throws instead of
silently running in the live checkout. This prevents AI from making
unprotected changes to the working tree.

* chore: Auto-commit workflow artifacts (archon-assist)
2026-03-17 13:39:41 +02:00
Cole Medin
aaac5d7e64
Merge pull request #663 from dynamous-community/wisc-video-preparation
feat: add WISC framework context engineering for video demonstration
2026-03-16 05:56:50 -05:00
Rasmus Widing
9655f88a4a fix: sync dev after merge in release skill 2026-03-16 11:36:03 +02:00
Rasmus Widing
bd98d40144 feat: add dev branch workflow and /release skill
Set up dev as the working branch with main as the release branch.
Add stack-agnostic /release skill that detects project type, generates
changelog entries from commits, bumps version, and creates a PR to main.
2026-03-16 11:18:11 +02:00
Cole Medin
0d48fa0d96 docs: update orchestrator docs to routing-agent architecture, enrich commit command
- orchestrator.md: rewrite to reflect current routing-agent model (5 deterministic
  commands, AI routing for everything else, /invoke-workflow protocol)
- architecture-deep-dive.md Flow #1: rewrite message flow to show AI routing path,
  prompt selection, and parseOrchestratorCommands output parsing
- commit.md: add step 4 for capturing AI context changes (rules, commands, docs)
  in commit messages — git log as long-term memory for the AI layer

Context:
- Updated .claude/rules/orchestrator.md to match current handleMessage() flow
- Updated .claude/docs/architecture-deep-dive.md Flow #1 for routing-agent pattern
- Enhanced .claude/commands/commit.md with AI context tracking for WISC Write strategy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 16:09:43 -05:00
Cole Medin
77895e053b fix: correct broken paths in system-review.md and factual errors in cli.md
- system-review.md: fix stale core_piv_loop/ path references to flattened locations
- system-review.md: remove undefined $3 reference in output section
- cli.md: CLIAdapter implements IPlatformAdapter, not IWorkflowPlatform
- cli.md: default streaming mode is 'batch', not 'stream'

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 16:09:42 -05:00
Cole Medin
800018c33e feat: add WISC framework context engineering for video demonstration
Add 3-tier progressive disclosure context system:
- 9 path-scoped auto-loading rules (.claude/rules/) for domain-specific conventions
- 4 heavy reference docs (.claude/docs/) for scout-pattern demonstrations
- 14 new commands (.claude/commands/) including PIV loop, prime commands, validation, and handoff

Rules auto-load when Claude reads files in matching paths (adapters, isolation,
workflows, orchestrator, database, web-frontend, server-api, testing, cli).
Reference docs are too large for auto-loading — designed for sub-agent scouting.
Commands adapted from agentic-coding-course examples, made Archon-specific.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 16:09:41 -05:00
Rasmus Widing
859ae108a7
fix: use SDK structured_output for output_format DAG nodes (#546)
* Investigate issue #497: output_format mixed prose+JSON breaking conditions

* fix: use SDK structured_output for output_format nodes (#497)

When a DAG node uses output_format, the Claude SDK streams reasoning
prose before the structured JSON. executeNodeInternal concatenated all
assistant text, producing mixed content that broke JSON.parse() in
downstream when: conditions.

The SDK already provides validated JSON via structured_output on the
result message — we just never read it. Now we forward it through
WorkflowMessageChunk and use it to override nodeOutputText when
output_format is set.

Changes:
- Add structuredOutput field to WorkflowMessageChunk result variant
- Extract structured_output from SDK result in ClaudeClient.sendQuery
- Override nodeOutputText with structuredOutput in executeNodeInternal
- Add tests for structured output extraction and condition evaluation

Fixes #497

* fix: move structured output override before post-loop side effects

Address self-review finding: the nodeOutputText override should happen
before logging/events, not after, so the canonical value is established
before any downstream use. Also remove redundant assertion.

* Archive investigation for issue #497

* fix: address review findings for structured output PR

- Fix batch-mode sending raw prose+JSON to user when structuredOutput
  overrides nodeOutputText (use clean JSON for batch content instead)
- Add warn log + user message when output_format is set but SDK returns
  no structured_output (prevents silent fallback to broken behavior)
- Wrap JSON.stringify(structuredOutput) in try-catch with node context
- Add debug log at structured output override point
- Fix pre-existing domain prefix: activity_update_failed → dag.activity_update_failed
- Add ClaudeClient tests for structuredOutput propagation (present/absent)
- Add DAG executor test for output_format absent guard
- Update docs/authoring-workflows.md to describe structured_output mechanism
2026-03-12 12:38:21 +02:00
Rasmus Widing
bc07c4f69f
fix(cli): error when --branch and --no-worktree are both passed (#545)
* Investigate issue #497: output_format mixed prose+JSON breaking conditions

* fix(cli): error when --branch and --no-worktree are both passed (#488)

--no-worktree silently wins when combined with --branch, checking out
the branch directly in the user's repo without warning. Add a mutual
exclusion check that exits with a clear error message before any git
operations happen.

Also adds a test for the existing --from + --no-worktree conflict guard.

Fixes #488

* fix(cli): move --branch + --no-worktree guard into workflowRunCommand

Move the authoritative mutual exclusion check into workflowRunCommand
itself (not just cli.ts) so any caller is protected. Replace the silent
git checkout code path with a throw. Add test for the exact #488
scenario (--branch + --no-worktree without --from).

* fix(cli): add structured logging before flag conflict throws

Add getLog().warn() calls before both --no-worktree conflict throws
in workflowRunCommand so programmatic callers have an audit trail
in structured logs.
2026-03-11 15:47:59 +02:00