Skip to content

fix: pass globalSearchPath to command handler workflow discovery#1136

Closed
jonasvanderhaegen wants to merge 1 commit into
coleam00:mainfrom
jonasvanderhaegen:fix/command-handler-global-workflow-discovery
Closed

fix: pass globalSearchPath to command handler workflow discovery#1136
jonasvanderhaegen wants to merge 1 commit into
coleam00:mainfrom
jonasvanderhaegen:fix/command-handler-global-workflow-discovery

Conversation

@jonasvanderhaegen

Copy link
Copy Markdown
Contributor

Problem

The command handler (packages/core/src/handlers/command-handler.ts) calls discoverWorkflowsWithConfig without globalSearchPath. This means workflows in ~/.archon/.archon/workflows/ are invisible to webhook-triggered /workflow run and /workflow list commands.

The CLI (cli.ts:125) and orchestrator (orchestrator-agent.ts:385) already pass globalSearchPath: getArchonHome(). The command handler was the only caller that didn't.

Symptom: @archon /workflow run my-custom-workflow posted as a GitHub comment returns "Workflow not found", even though archon workflow run my-custom-workflow via CLI works.

Fix

Pass { globalSearchPath: getArchonHome() } to all three discoverWorkflowsWithConfig calls in command-handler.ts (list, reload, run).

Changes

  • Import getArchonHome from @archon/paths (already exported)
  • 3 call sites updated (lines 566, 612, 807)

4 lines changed.

@coderabbitai

coderabbitai Bot commented Apr 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 66d8eaa7-e732-461b-ad60-76d67bd9eaa4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

The command handler and web UI API endpoint call discoverWorkflowsWithConfig
without globalSearchPath, making workflows in ~/.archon/.archon/workflows/
invisible to webhook commands and the web UI.

Fix: pass { globalSearchPath: getArchonHome() } to:
- command-handler.ts: list, reload, run (3 calls)
- api.ts: GET /api/workflows (1 call)

The CLI and orchestrator already pass this correctly.
@jonasvanderhaegen jonasvanderhaegen force-pushed the fix/command-handler-global-workflow-discovery branch from 44b80c3 to f4b3163 Compare April 12, 2026 19:57
fcamblor added a commit to fcamblor/Archon that referenced this pull request Apr 16, 2026
Problem: Web UI was blind to workflows in ~/.archon/.archon/workflows/
because GET /api/workflows called discoverWorkflowsWithConfig without
a third argument, so the global search path was never consulted.

Fix: pass { globalSearchPath: getArchonHome() } as third argument,
aligning with CLI (cli/workflow.ts:123) and orchestrator
(orchestrator-agent.ts:386).

Also fix missing `resolve` import in isolation/worktree.ts that caused
type-check and lint errors (introduced in coleam00#1034).

Ref: completes coleam00#1138 (PR coleam00#1136 only covered command-handler/webhook).

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

Wirasm commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator

Related to #1138 — overlapping area or partial fix.

@Wirasm

Wirasm commented Apr 20, 2026

Copy link
Copy Markdown
Collaborator

Superseded by #1315 — a broader primitive refactor that eliminates the globalSearchPath option entirely (instead of threading it through every call site). The refactor moves ~/.archon/.archon/workflows/ to ~/.archon/workflows/ (direct child, matching the workspaces/ / archon.db convention), adds home-scoped commands and scripts as first-class capabilities with the same discovery semantics, and fixes the latent bug where commands in subfolders were listed but unresolvable.

The specific bug this PR fixes — webhook /workflow run missing home-scoped workflows — is closed by #1315 since home-scope is now read unconditionally by every caller. Your tactical fix directly motivated the refactor; you're credited via Co-authored-by: on the replacement commit.

Closing this in favor of #1315. Thanks for surfacing the bug class.

@Wirasm Wirasm closed this Apr 20, 2026
Wirasm added a commit that referenced this pull request Apr 20, 2026
… drop globalSearchPath (closes #1136) (#1315)

* feat(paths,workflows): unify ~/.archon/{workflows,commands,scripts} + drop globalSearchPath

Collapses the awkward `~/.archon/.archon/workflows/` convention to a direct
`~/.archon/workflows/` child (matching `workspaces/`, `archon.db`, etc.), adds
home-scoped commands and scripts with the same loading story, and kills the
opt-in `globalSearchPath` parameter so every call site gets home-scope for free.

Closes #1136 (supersedes @jonasvanderhaegen's tactical fix — the bug was the
primitive itself: an easy-to-forget parameter that five of six call sites on
dev dropped).

Primitive changes:

- Home paths are direct children of `~/.archon/`. New helpers in `@archon/paths`:
  `getHomeWorkflowsPath()`, `getHomeCommandsPath()`, `getHomeScriptsPath()`,
  and `getLegacyHomeWorkflowsPath()` (detection-only for migration).
- `discoverWorkflowsWithConfig(cwd, loadConfig)` reads home-scope internally.
  The old `{ globalSearchPath }` option is removed. Chat command handler, Web
  UI workflow picker, orchestrator resolve path — all inherit home-scope for
  free without maintainer patches at every new site.
- `discoverScriptsForCwd(cwd)` merges home + repo scripts (repo wins on name
  collision). dag-executor and validator use it; the hardcoded
  `resolve(cwd, '.archon', 'scripts')` single-scope path is gone.
- Command resolution is now walked-by-basename in each scope. `loadCommand`
  and `resolveCommand` walk 1 subfolder deep and match by `.md` basename, so
  `.archon/commands/triage/review.md` resolves as `review` — closes the
  latent bug where subfolder commands were listed but unresolvable.
- All three (`workflows/`, `commands/`, `scripts/`) enforce a 1-level
  subfolder cap (matches the existing `defaults/` convention). Deeper
  nesting is silently skipped.
- `WorkflowSource` gains `'global'` alongside `'bundled'` and `'project'`.
  Web UI node palette shows a dedicated "Global (~/.archon/commands/)"
  section; badges updated.

Migration (clean cut — no fallback read):

- First use after upgrade: if `~/.archon/.archon/workflows/` exists, Archon
  logs a one-time WARN per process with the exact `mv` command:
  `mv ~/.archon/.archon/workflows ~/.archon/workflows && rmdir ~/.archon/.archon`
  The legacy path is NOT read — users migrate manually. Rollback caveat
  noted in CHANGELOG.

Tests:

- `@archon/paths/archon-paths.test.ts`: new helper tests (default HOME,
  ARCHON_HOME override, Docker), plus regression guards for the double-`.archon/`
  path.
- `@archon/workflows/loader.test.ts`: home-scoped workflows, precedence,
  subfolder 1-depth cap, legacy-path deprecation warning fires exactly once
  per process.
- `@archon/workflows/validator.test.ts`: home-scoped commands + subfolder
  resolution.
- `@archon/workflows/script-discovery.test.ts`: depth cap + merge semantics
  (repo wins, home-missing tolerance).
- Existing CLI + orchestrator tests updated to drop `globalSearchPath`
  assertions.

E2E smoke (verified locally, before cleanup):

- `.archon/workflows/e2e-home-scope.yaml` + scratch repo at /tmp
- Home-scoped workflow discovered from an unrelated git repo
- Home-scoped script (`~/.archon/scripts/*.ts`) executes inside a script node
- 1-level subfolder workflow (`~/.archon/workflows/triage/*.yaml`) listed
- Legacy path warning fires with actionable `mv` command; workflows there
  are NOT loaded

Docs: `CLAUDE.md`, `docs-web/guides/global-workflows.md` (full rewrite for
three-type scope + subfolder convention + migration), `docs-web/reference/
configuration.md` (directory tree), `docs-web/reference/cli.md`,
`docs-web/guides/authoring-workflows.md`.

Co-authored-by: Jonas Vanderhaegen <7755555+jonasvanderhaegen@users.noreply.github.com>

* test(script-discovery): normalize path separators in mocks for Windows

The 4 new tests in `scanScriptDir depth cap` and `discoverScriptsForCwd —
merge repo + home with repo winning` compared incoming mock paths with
hardcoded forward-slash strings (`if (path === '/scripts/triage')`). On
Windows, `path.join('/scripts', 'triage')` produces `\scripts\triage`, so
those branches never matched, readdir returned `[]`, and the tests failed.

Added a `norm()` helper at module scope and wrapped the incoming `path`
argument in every `mockImplementation` before comparing. Stored paths go
through `normalizeSep()` in production code, so the existing equality
assertions on `script.path` remain OS-independent.

Fixes Windows CI job `test (windows-latest)` on PR #1315.

* address review feedback: home-scope error handling, depth cap, and tests

Critical fixes:
- api.ts: add `maxDepth: 1` to all 3 findMarkdownFilesRecursive calls in
  GET /api/commands (bundled/home/project). Without this the UI palette
  surfaced commands from deep subfolders that the executor (capped at 1)
  could not resolve — silent "command not found" at runtime.
- validator.ts: wrap home-scope findMarkdownFilesRecursive and
  resolveCommandInDir calls in try/catch so EACCES/EPERM on
  ~/.archon/commands/ doesn't crash the validator with a raw filesystem
  error. ENOENT still returns [] via the underlying helper.

Error handling fixes:
- workflow-discovery.ts: maybeWarnLegacyHomePath now sets the
  "warned-once" flag eagerly before `await access()`, so concurrent
  discovery calls (server startup with parallel codebase resolution)
  can't double-warn. Non-ENOENT probe errors (EACCES/EPERM) now log at
  WARN instead of DEBUG so permission issues on the legacy dir are
  visible in default operation.
- dag-executor.ts: wrap discoverScriptsForCwd in its own try/catch so
  an EACCES on ~/.archon/scripts/ routes through safeSendMessage /
  logNodeError with a dedicated "failed to discover scripts" message
  instead of being mis-attributed by the outer catch's
  "permission denied (check cwd permissions)" branch.

Tests:
- load-command-prompt.test.ts (new): 6 tests covering the executor's
  command resolution hot path — home-scope resolves when repo misses,
  repo shadows home, 1-level subfolder resolvable by basename, 2-level
  rejected, not-found, empty-file. Runs in its own bun test batch.
- archon-paths.test.ts: add getHomeScriptsPath describe block to match
  the existing getHomeCommandsPath / getHomeWorkflowsPath coverage.

Comment clarity:
- workflow-discovery.ts: MAX_DISCOVERY_DEPTH comment now leads with the
  actual value (1) before describing what 0 would mean.
- script-discovery.ts: copy the "routing ambiguity" rationale from
  MAX_DISCOVERY_DEPTH to MAX_SCRIPT_DISCOVERY_DEPTH.

Cleanup:
- Remove .archon/workflows/e2e-home-scope.yaml — one-off smoke test that
  would ship permanently in every project's workflow list. Equivalent
  coverage exists in loader.test.ts.

Addresses all blocking and important feedback from the multi-agent
review on PR #1315.

---------

Co-authored-by: Jonas Vanderhaegen <7755555+jonasvanderhaegen@users.noreply.github.com>
@Wirasm Wirasm mentioned this pull request Apr 22, 2026
prospapledge88 added a commit to prospapledge88/Archon that referenced this pull request May 5, 2026
* feat(paths/cli/setup): unify env load + write on three-path model (coleam00#1302, coleam00#1303) (coleam00#1304)

* feat(paths/cli/setup): unify env load + write on three-path model (coleam00#1302, coleam00#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 (coleam00#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 (coleam00#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-coleam00#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(paths,workflows): unify ~/.archon/{workflows,commands,scripts} + drop globalSearchPath (closes coleam00#1136) (coleam00#1315)

* feat(paths,workflows): unify ~/.archon/{workflows,commands,scripts} + drop globalSearchPath

Collapses the awkward `~/.archon/.archon/workflows/` convention to a direct
`~/.archon/workflows/` child (matching `workspaces/`, `archon.db`, etc.), adds
home-scoped commands and scripts with the same loading story, and kills the
opt-in `globalSearchPath` parameter so every call site gets home-scope for free.

Closes coleam00#1136 (supersedes @jonasvanderhaegen's tactical fix — the bug was the
primitive itself: an easy-to-forget parameter that five of six call sites on
dev dropped).

Primitive changes:

- Home paths are direct children of `~/.archon/`. New helpers in `@archon/paths`:
  `getHomeWorkflowsPath()`, `getHomeCommandsPath()`, `getHomeScriptsPath()`,
  and `getLegacyHomeWorkflowsPath()` (detection-only for migration).
- `discoverWorkflowsWithConfig(cwd, loadConfig)` reads home-scope internally.
  The old `{ globalSearchPath }` option is removed. Chat command handler, Web
  UI workflow picker, orchestrator resolve path — all inherit home-scope for
  free without maintainer patches at every new site.
- `discoverScriptsForCwd(cwd)` merges home + repo scripts (repo wins on name
  collision). dag-executor and validator use it; the hardcoded
  `resolve(cwd, '.archon', 'scripts')` single-scope path is gone.
- Command resolution is now walked-by-basename in each scope. `loadCommand`
  and `resolveCommand` walk 1 subfolder deep and match by `.md` basename, so
  `.archon/commands/triage/review.md` resolves as `review` — closes the
  latent bug where subfolder commands were listed but unresolvable.
- All three (`workflows/`, `commands/`, `scripts/`) enforce a 1-level
  subfolder cap (matches the existing `defaults/` convention). Deeper
  nesting is silently skipped.
- `WorkflowSource` gains `'global'` alongside `'bundled'` and `'project'`.
  Web UI node palette shows a dedicated "Global (~/.archon/commands/)"
  section; badges updated.

Migration (clean cut — no fallback read):

- First use after upgrade: if `~/.archon/.archon/workflows/` exists, Archon
  logs a one-time WARN per process with the exact `mv` command:
  `mv ~/.archon/.archon/workflows ~/.archon/workflows && rmdir ~/.archon/.archon`
  The legacy path is NOT read — users migrate manually. Rollback caveat
  noted in CHANGELOG.

Tests:

- `@archon/paths/archon-paths.test.ts`: new helper tests (default HOME,
  ARCHON_HOME override, Docker), plus regression guards for the double-`.archon/`
  path.
- `@archon/workflows/loader.test.ts`: home-scoped workflows, precedence,
  subfolder 1-depth cap, legacy-path deprecation warning fires exactly once
  per process.
- `@archon/workflows/validator.test.ts`: home-scoped commands + subfolder
  resolution.
- `@archon/workflows/script-discovery.test.ts`: depth cap + merge semantics
  (repo wins, home-missing tolerance).
- Existing CLI + orchestrator tests updated to drop `globalSearchPath`
  assertions.

E2E smoke (verified locally, before cleanup):

- `.archon/workflows/e2e-home-scope.yaml` + scratch repo at /tmp
- Home-scoped workflow discovered from an unrelated git repo
- Home-scoped script (`~/.archon/scripts/*.ts`) executes inside a script node
- 1-level subfolder workflow (`~/.archon/workflows/triage/*.yaml`) listed
- Legacy path warning fires with actionable `mv` command; workflows there
  are NOT loaded

Docs: `CLAUDE.md`, `docs-web/guides/global-workflows.md` (full rewrite for
three-type scope + subfolder convention + migration), `docs-web/reference/
configuration.md` (directory tree), `docs-web/reference/cli.md`,
`docs-web/guides/authoring-workflows.md`.

Co-authored-by: Jonas Vanderhaegen <7755555+jonasvanderhaegen@users.noreply.github.com>

* test(script-discovery): normalize path separators in mocks for Windows

The 4 new tests in `scanScriptDir depth cap` and `discoverScriptsForCwd —
merge repo + home with repo winning` compared incoming mock paths with
hardcoded forward-slash strings (`if (path === '/scripts/triage')`). On
Windows, `path.join('/scripts', 'triage')` produces `\scripts\triage`, so
those branches never matched, readdir returned `[]`, and the tests failed.

Added a `norm()` helper at module scope and wrapped the incoming `path`
argument in every `mockImplementation` before comparing. Stored paths go
through `normalizeSep()` in production code, so the existing equality
assertions on `script.path` remain OS-independent.

Fixes Windows CI job `test (windows-latest)` on PR coleam00#1315.

* address review feedback: home-scope error handling, depth cap, and tests

Critical fixes:
- api.ts: add `maxDepth: 1` to all 3 findMarkdownFilesRecursive calls in
  GET /api/commands (bundled/home/project). Without this the UI palette
  surfaced commands from deep subfolders that the executor (capped at 1)
  could not resolve — silent "command not found" at runtime.
- validator.ts: wrap home-scope findMarkdownFilesRecursive and
  resolveCommandInDir calls in try/catch so EACCES/EPERM on
  ~/.archon/commands/ doesn't crash the validator with a raw filesystem
  error. ENOENT still returns [] via the underlying helper.

Error handling fixes:
- workflow-discovery.ts: maybeWarnLegacyHomePath now sets the
  "warned-once" flag eagerly before `await access()`, so concurrent
  discovery calls (server startup with parallel codebase resolution)
  can't double-warn. Non-ENOENT probe errors (EACCES/EPERM) now log at
  WARN instead of DEBUG so permission issues on the legacy dir are
  visible in default operation.
- dag-executor.ts: wrap discoverScriptsForCwd in its own try/catch so
  an EACCES on ~/.archon/scripts/ routes through safeSendMessage /
  logNodeError with a dedicated "failed to discover scripts" message
  instead of being mis-attributed by the outer catch's
  "permission denied (check cwd permissions)" branch.

Tests:
- load-command-prompt.test.ts (new): 6 tests covering the executor's
  command resolution hot path — home-scope resolves when repo misses,
  repo shadows home, 1-level subfolder resolvable by basename, 2-level
  rejected, not-found, empty-file. Runs in its own bun test batch.
- archon-paths.test.ts: add getHomeScriptsPath describe block to match
  the existing getHomeCommandsPath / getHomeWorkflowsPath coverage.

Comment clarity:
- workflow-discovery.ts: MAX_DISCOVERY_DEPTH comment now leads with the
  actual value (1) before describing what 0 would mean.
- script-discovery.ts: copy the "routing ambiguity" rationale from
  MAX_DISCOVERY_DEPTH to MAX_SCRIPT_DISCOVERY_DEPTH.

Cleanup:
- Remove .archon/workflows/e2e-home-scope.yaml — one-off smoke test that
  would ship permanently in every project's workflow list. Equivalent
  coverage exists in loader.test.ts.

Addresses all blocking and important feedback from the multi-agent
review on PR coleam00#1315.

---------

Co-authored-by: Jonas Vanderhaegen <7755555+jonasvanderhaegen@users.noreply.github.com>

* feat(isolation,workflows): worktree location + per-workflow isolation policy (coleam00#1310)

* feat(isolation): per-project worktree.path + collapse to two layouts

Adds an opt-in `worktree.path` to .archon/config.yaml so a repo can co-locate
worktrees with its own checkout (`<repoRoot>/<path>/<branch>`) instead of the
default `~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`. Requested in
joelsb's coleam00#1117.

Primitive changes (clean up the graveyard rather than add parallel code paths):

- Collapse worktree layouts from three to two. The old "legacy global" layout
  (`~/.archon/worktrees/<owner>/<repo>/<branch>`) is gone — every repo resolves
  to the workspace-scoped layout (`~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`),
  whether it was archon-cloned or locally registered. `extractOwnerRepo()` on
  the repo path is the stable identity fallback. Ends the divergence where
  workspace-cloned and local repos had visibly different worktree trees.

- `getWorktreeBase()` in @archon/git now returns `{ base, layout }` and accepts
  an optional `{ repoLocal }` override. The layout value replaces the old
  `isProjectScopedWorktreeBase()` classification at the call sites
  (`isProjectScopedWorktreeBase` stays exported as deprecated back-compat).

- `WorktreeCreateConfig.path` carries the validated override from repo config.
  `resolveRepoLocalOverride()` fails loudly on absolute paths, `..` escapes,
  and resolve-escape edge cases (Fail Fast — no silent default fallback when
  the config is syntactically wrong).

- `WorktreeProvider.create()` now loads repo config exactly once and threads it
  through `getWorktreePath()` + `createWorktree()`. Replaces the prior
  swallow-then-retry pattern flagged on coleam00#1117. `generateEnvId()` is gone —
  envId is assigned directly from the resolved path (the invariant was already
  documented on `destroy(envId)`).

Tests (packages/git + packages/isolation):
- Update the pre-existing `getWorktreeBase` / `isProjectScopedWorktreeBase`
  suite for the new two-layout return shape and precedence.
- Add 8 tests for `worktree.path`: default fallthrough, empty/whitespace
  ignored, override wins for workspace-scoped repos, rejects absolute, rejects
  `../` escapes (three variants), accepts nested relative paths.

Docs: add `worktree.path` to the repo config reference with explicit precedence
and the `.gitignore` responsibility note.

Co-authored-by: Joel Bastos <joelsb2001@gmail.com>

* feat(workflows): per-workflow worktree.enabled policy

Introduces a declarative top-level `worktree:` block on a workflow so
authors can pin isolation behavior regardless of invocation surface. Solves
the case where read-only workflows (e.g. `repo-triage`) should always run in
the live checkout, without every CLI/web/scheduled-trigger caller having to
remember to set the right flag.

Schema (packages/workflows/src/schemas/workflow.ts + loader.ts):

- New optional `worktree.enabled: boolean` on `workflowBaseSchema`. Loader
  parses with the same warn-and-ignore discipline used for `interactive`
  and `modelReasoningEffort` — invalid shapes log and drop rather than
  killing workflow discovery.

Policy reconciliation (packages/cli/src/commands/workflow.ts):

- Three hard-error cases when YAML policy contradicts invocation flags:
  • `enabled: false` + `--branch`       (worktree required by flag, forbidden by policy)
  • `enabled: false` + `--from`         (start-point only meaningful with worktree)
  • `enabled: true`  + `--no-worktree`  (policy requires worktree, flag forbids it)
- `enabled: false` + `--no-worktree` is redundant, accepted silently.
- `--resume` ignores the pinned policy (it reuses the existing run's worktree
  even when policy would disable — avoids disturbing a paused run).

Orchestrator wiring (packages/core/src/orchestrator/orchestrator-agent.ts):

- `dispatchOrchestratorWorkflow` short-circuits `validateAndResolveIsolation`
  when `workflow.worktree?.enabled === false` and runs directly in
  `codebase.default_cwd`. Web chat/slack/telegram callers have no flag
  equivalent to `--no-worktree`, so the YAML field is their only control.
- Logged as `workflow.worktree_disabled_by_policy` for operator visibility.

First consumer (.archon/workflows/repo-triage.yaml):

- `worktree: { enabled: false }` — triage reads issues/PRs and writes gh
  labels; no code mutations, no reason to spin up a worktree per run.

Tests:

- Loader: parses `worktree.enabled: true|false`, omits block when absent.
- CLI: four new integration tests for the reconciliation matrix (skip when
  policy false, three hard-error cases, redundant `--no-worktree` accepted,
  `--no-worktree` + `enabled: true` rejected).

Docs: authoring-workflows.md gets the new top-level field in the schema
example with a comment explaining the precedence and the `enabled: true|false`
semantics.

* fix(isolation): use path.sep for repo-containment check on Windows

resolveRepoLocalOverride was hardcoding '/' as the separator in the
startsWith check, so on Windows (where `resolve()` returns backslash
paths like `D:\Users\dev\Projects\myapp`) every otherwise-valid
relative `worktree.path` was rejected with "resolves outside the repo
root". Fixed by importing `path.sep` and using it in the sentinel.

Fixes the 3 Windows CI failures in `worktree.path repo-local override`.

---------

Co-authored-by: Joel Bastos <joelsb2001@gmail.com>

* docs(worktree): fix stale rename example + document copyFiles properly (coleam00#1328)

Three related fixes around the `worktree.copyFiles` primitive:

1. Remove the `.env.example -> .env` rename example from
   reference/configuration.md and getting-started/overview.md. The
   `->` parser was removed in coleam00#739 (2026-03-19) because it caused
   the stale-credentials production bug in coleam00#228 — but the docs kept
   advertising it. A user writing `.env.example -> .env` today gets
   `parseCopyFileEntry` returning `{source: '.env.example -> .env',
   destination: '.env.example -> .env'}`, stat() fails with ENOENT,
   and the copy silently no-ops at debug level.

2. Replace the single-line "Default behavior: .archon/ is always
   copied" note with a proper "Worktree file copying" subsection
   that explains:
   - Why this exists (git worktree add = tracked files only; gitignored
     workflow inputs need this hook)
   - The `.archon/` default (no config needed for the common case)
   - Common entries: .env, .vscode/, .claude/, plans/, reports/,
     data fixtures
   - Semantics: source=destination, ENOENT silently skipped, per-entry
     error isolation, path-traversal rejected
   - Interaction with `worktree.path` (both layouts get the same
     treatment)

3. Update the overview example to drop the `.env.example + .env` pair
   (which implied rename semantics) in favor of `.env + plans/`, and
   call out that `.archon/` is auto-copied so users don't list it.

No code changes. `bun run format:check` and `bun run lint` green.

* fix(workflows): archon-assist runs in live checkout (worktree.enabled: false) — closes coleam00#1546 (coleam00#1555)

Co-authored-by: Zolto <zolto@zhome.local>

* chore(changelog): document Tier 4 paths/env unification cherry-pick batch (5 commits)

Adds a CHANGELOG entry under [Unreleased] / Fixed summarizing the five
upstream commits picked in this batch:

  - 28908f0 — env load/write three-path model + loadArchonEnv helper (coleam00#1302/coleam00#1303/coleam00#1304)
  - 7be4d0a — unify ~/.archon/{workflows,commands,scripts} (coleam00#1315)
  - 5ed38dc — worktree.path config + per-workflow worktree.enabled policy (coleam00#1310)
  - ba4b9b4 — docs follow-up to 5ed38dc (coleam00#1328)
  - e33e0de — archon-assist worktree.enabled: false (deferred from PR #8, now unblocked)

Notes that cc78071 (worktree timeout 5m) was already absorbed in earlier batches.

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

---------

Co-authored-by: Rasmus Widing <152263317+Wirasm@users.noreply.github.com>
Co-authored-by: Jonas Vanderhaegen <7755555+jonasvanderhaegen@users.noreply.github.com>
Co-authored-by: Joel Bastos <joelsb2001@gmail.com>
Co-authored-by: ztech-gthb <ztech-001@gmx.net>
Co-authored-by: Zolto <zolto@zhome.local>
Co-authored-by: cjnprospa <sirhcle.j23@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants