* 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>
* 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.
* 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.
- 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
* 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>
* 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.
* 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
* 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
* 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
* 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
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.
- 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
- 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
- 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
- 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
- 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
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.
- 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>
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>
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>
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>
* 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>
- 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>
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
* 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
* 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
* 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
* 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)
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.
- 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>
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>
* 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
* 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.