Skip to content

fix(server): PUT/DELETE /api/workflows/{name} miss home-scoped (~/.archon/workflows/)#1525

Closed
blankse wants to merge 1 commit into
coleam00:devfrom
blankse:fix/1524-home-scoped-workflow-endpoints
Closed

fix(server): PUT/DELETE /api/workflows/{name} miss home-scoped (~/.archon/workflows/)#1525
blankse wants to merge 1 commit into
coleam00:devfrom
blankse:fix/1524-home-scoped-workflow-endpoints

Conversation

@blankse

@blankse blankse commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Rebased onto dev: The original PR also fixed GET /api/workflows/{name} — that was merged separately as #1405. After rebase, this PR's net contribution is PUT + DELETE only.

  • Problem: PUT and DELETE /api/workflows/{name} skip the home-scoped layer (~/.archon/workflows/). Saving a workflow from the dashboard with no project selected lands the YAML in ~/.archon/.archon/workflows/ — the legacy pre-0.x path the migration warning explicitly tells users to abandon. Deleting a home-scoped workflow via the API silently fails (404) because the handler looks in the wrong directory.
  • Why it matters: After fix(server): GET /api/workflows/:name missed home-scoped workflows #1405 (GET) and the discovery layer changes in feat(paths,workflows): unify ~/.archon/{workflows,commands,scripts} + drop globalSearchPath (closes #1136) #1315, home-scoped workflows are visible everywhere — dashboard, run-detail page, CLI — except when writing or deleting through the REST endpoints. CLAUDE.md documents the priority bundled < global < project; the write endpoints were the last layer still walking project → bundled and missing the home tier.
  • What changed:
    • PUT /api/workflows/{name}: when no cwd and no registered codebases exist, write to getHomeWorkflowsPath() (= ~/.archon/workflows/) instead of falling through to <archonHome>/.archon/workflows/. Response includes source: 'global' for the home-tier case ('project' unchanged).
    • DELETE /api/workflows/{name}: mirrors PUT's resolution — home-scoped path when no project is registered, project path otherwise.
    • 4 new tests in api.workflows.test.ts covering: PUT falls back to home-scoped, PUT into project unchanged, DELETE removes home-scoped, DELETE returns 404 cleanly when missing.
  • What did NOT change (scope boundary): GET handler (= fix(server): GET /api/workflows/:name missed home-scoped workflows #1405's territory), bundled-default fallback order, WorkflowSource type, discovery layer, any client-facing shape beyond the new source: 'global' case on PUT.

Closes #1524.

Test plan

  • bun --filter @archon/server type-check passes
  • bun --filter @archon/server test packages/server/src/routes/api.workflows.test.ts — all 68 tests pass (4 new)
  • Manual: register no codebase, PUT a workflow via dashboard → lands at ~/.archon/workflows/<name>.yaml
  • Manual: DELETE a home-scoped workflow via dashboard → file removed, 200 response

Summary by CodeRabbit

  • Bug Fixes
    • Improved workflow storage and deletion behavior to correctly resolve project vs. global workflow locations
    • Workflow API now consistently uses project directory when available for save and delete operations
    • Enhanced fallback ordering for workflow source detection

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fb0704ad-c665-47e4-bfe7-1b8a71029784

📥 Commits

Reviewing files that changed from the base of the PR and between 4ad107f and d4d0394.

📒 Files selected for processing (2)
  • packages/server/src/routes/api.ts
  • packages/server/src/routes/api.workflows.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/server/src/routes/api.workflows.test.ts
  • packages/server/src/routes/api.ts

📝 Walkthrough

Walkthrough

The workflow API endpoints now implement tiered workflow discovery: GET reads from project-scoped, then home-scoped (~/.archon/workflows/), returning source: 'global' for home-scoped results; PUT and DELETE resolve targets using validated cwd or first registered codebase default_cwd, otherwise defaulting to home-scoped paths with updated logging.

Changes

Workflow Route Implementation

Layer / File(s) Summary
GET fallback label
packages/server/src/routes/api.ts
Adds an explicit labeled step for the filesystem-backed home-scoped defaults in the single-workflow GET fallback sequence.
PUT projectDir resolution
packages/server/src/routes/api.ts
Compute projectDir from validated cwd or first registered codebase default_cwd, removing legacy workingDir/getArchonHome fallback behavior.
PUT write target and logging
packages/server/src/routes/api.ts
Derive dirPath and savedSource from whether projectDir is present (project workflows folder vs getHomeWorkflowsPath()), return saved source, and include resolved dirPath in save-failure logs.
DELETE target resolution
packages/server/src/routes/api.ts
Resolve delete filePath using the same projectDir vs home-scoped decision as PUT and delete from project workflow YAML or the home-scoped workflows directory.
Tests: PUT/DELETE home-scoped regressions
packages/server/src/routes/api.workflows.test.ts
Rename and update PUT fallback test to assert source: "global" and filesystem path under ~/.archon/workflows/; add DELETE test that creates a home-scoped workflow, calls DELETE with no cwd/codebases, asserts deleted: true, and verifies file removal.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

  • coleam00/Archon#1405 — Related changes adding home-scoped (~/.archon/workflows/.yaml) discovery and source: 'global' handling.
  • coleam00/Archon#1315 — Earlier work on home-scoped workflow resolution and WorkflowSource that this PR builds upon.

Poem

🐰 I hopped through YAML paths so neat,
Project first, then home beneath my feet,
Saved with care, removed on cue,
Home-scoped fallbacks—steady and true.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing PUT/DELETE /api/workflows/{name} to properly handle home-scoped workflows (~/.archon/workflows/).
Description check ✅ Passed The description covers the required sections: clear problem statement, impact, detailed changes, scope boundaries, and test evidence. However, manual verification items are incomplete (2 of 4 marked unchecked).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/server/src/routes/api.workflows.test.ts`:
- Around line 256-293: The test mutates process.env.ARCHON_HOME and the finally
block unconditionally deletes it; capture the original value before setting
ARCHON_HOME (e.g., const prevArchonHome = process.env.ARCHON_HOME), set
process.env.ARCHON_HOME = testArchonHome for the test, and in the finally block
restore it (process.env.ARCHON_HOME = prevArchonHome or delete if prevArchonHome
is undefined) instead of always deleting; apply the same pattern to the other
affected tests (the blocks around lines 295-334, 397-437, 537-569) to avoid
leaking environment state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d109f173-1b47-4e93-b7d3-8e8bbd72cb68

📥 Commits

Reviewing files that changed from the base of the PR and between 69b2c89 and 5be4214.

📒 Files selected for processing (2)
  • packages/server/src/routes/api.ts
  • packages/server/src/routes/api.workflows.test.ts

Comment on lines +256 to +293
test('returns home-scoped workflow with source:global when only ~/.archon/workflows/ has it', async () => {
// Regression for #1524: home-scoped workflows are listed by the
// dashboard but were unfetchable via GET, breaking the run detail page.
const testArchonHome = join(tmpdir(), `archon-home-get-${Date.now()}`);
const homeWorkflowDir = join(testArchonHome, 'workflows');
await mkdir(homeWorkflowDir, { recursive: true });
await writeFile(
join(homeWorkflowDir, 'team-shared.yaml'),
'name: team-shared\ndescription: shared\nnodes:\n - id: n\n command: c\n'
);
process.env.ARCHON_HOME = testArchonHome;

try {
const app = createTestApp();
registerApiRoutes(app, {} as WebAdapter, {} as ConversationLockManager);

// No project-scoped match; falls through to home-scoped.
mockListCodebases.mockImplementationOnce(async () => []);
mockParseWorkflow.mockReturnValueOnce({
workflow: makeTestWorkflow({ name: 'team-shared', description: 'shared' }),
error: null,
});

const response = await app.request('/api/workflows/team-shared');
expect(response.status).toBe(200);
const body = (await response.json()) as {
source: string;
filename: string;
workflow: { name: string };
};
expect(body.source).toBe('global');
expect(body.filename).toBe('team-shared.yaml');
expect(body.workflow.name).toBe('team-shared');
} finally {
delete process.env.ARCHON_HOME;
await rm(testArchonHome, { recursive: true, force: true });
}
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Restore any pre-existing ARCHON_HOME instead of always deleting it.

These tests mutate a process-global env var, but finally always deletes it. If the runner already had ARCHON_HOME set, later tests inherit the wrong environment and the suite becomes order-dependent.

Suggested fix
-    process.env.ARCHON_HOME = testArchonHome;
+    const previousArchonHome = process.env.ARCHON_HOME;
+    process.env.ARCHON_HOME = testArchonHome;

     try {
       // ...
     } finally {
-      delete process.env.ARCHON_HOME;
+      if (previousArchonHome === undefined) {
+        delete process.env.ARCHON_HOME;
+      } else {
+        process.env.ARCHON_HOME = previousArchonHome;
+      }
       await rm(testArchonHome, { recursive: true, force: true });
     }

As per coding guidelines, **/*.test.ts: "keep tests deterministic — no flaky timing or network dependence without guardrails".

Also applies to: 295-334, 397-437, 537-569

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/server/src/routes/api.workflows.test.ts` around lines 256 - 293, The
test mutates process.env.ARCHON_HOME and the finally block unconditionally
deletes it; capture the original value before setting ARCHON_HOME (e.g., const
prevArchonHome = process.env.ARCHON_HOME), set process.env.ARCHON_HOME =
testArchonHome for the test, and in the finally block restore it
(process.env.ARCHON_HOME = prevArchonHome or delete if prevArchonHome is
undefined) instead of always deleting; apply the same pattern to the other
affected tests (the blocks around lines 295-334, 397-437, 537-569) to avoid
leaking environment state.

@Wirasm

Wirasm commented May 4, 2026

Copy link
Copy Markdown
Collaborator

@blankse related to #1524 — home-scoped workflow REST endpoints.

@leex279

leex279 commented May 4, 2026

Copy link
Copy Markdown
Collaborator

@blankse this PR looks similar to #1560, which was closed on 2026-05-04 (closed without merging). You may want to read the discussion there before pushing further.

@blankse blankse force-pushed the fix/1524-home-scoped-workflow-endpoints branch from 5be4214 to 4ad107f Compare May 12, 2026 09:26
@blankse blankse changed the title fix(server): wire ~/.archon/workflows/ into single-workflow REST endpoints fix(server): PUT/DELETE /api/workflows/{name} miss home-scoped (~/.archon/workflows/) May 12, 2026
@blankse

blankse commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current dev (commit 4ad107f6). The original PR also fixed GET /api/workflows/{name} — that was merged separately as #1405, so I dropped the redundant GET changes during rebase and kept only the PUT/DELETE work + 4 new tests. Title and description updated to reflect the reduced scope.

Type-check + all 68 tests in api.workflows.test.ts green.

…ingle-workflow REST endpoints

Background

`GET /api/workflows` (list) reads home-scoped workflows correctly via
`discoverWorkflowsWithConfig` — files placed under `~/.archon/workflows/`
appear in the dashboard, run successfully, and persist across projects
exactly as documented in CLAUDE.md (`bundled < global < project`).

The single-workflow REST endpoints (`GET`, `PUT`, `DELETE
/api/workflows/{name}`) never got the memo. Their lookup ladder skips
straight from project-scoped to bundled, so any home-scoped workflow
returns 404 from `GET`. The Web UI's run-detail page calls `getWorkflow`
to render the DAG graph; the 404 leaves it stuck on "Loading graph…"
forever.

`PUT` and `DELETE` had a related but distinct bug: when no codebase is
registered they fell back to `workingDir = getArchonHome()` and joined
the workflow folder as `<archonHome>/.archon/workflows/` — which is the
legacy pre-0.x location whose only remaining purpose is to emit the
migration warning. New workflows created from the dashboard with no
project landed there silently and stayed invisible to discovery.

Closes coleam00#1524.

Change

1. `GET /api/workflows/{name}` gains a step 2 between project-scoped and
   bundled: read `getHomeWorkflowsPath()/<name>.yaml` and return
   `source: 'global'` on hit. Mirrors the discovery layer's documented
   priority. ENOENT falls through; any other error surfaces as 500.

2. `PUT /api/workflows/{name}`: when no `cwd` and no codebase exists,
   write to `getHomeWorkflowsPath()` directly (`source: 'global'`)
   instead of joining `getArchonHome()` with the project workflow
   folder. Project-scoped saves are unchanged.

3. `DELETE /api/workflows/{name}`: same correction as PUT — operate on
   `getHomeWorkflowsPath()` for the no-project case.

The `WorkflowSource` type already includes `'global'`; the discovery
code already labels home-scoped workflows that way. The endpoints now
agree with the rest of the system.

Tests

- New: GET returns `source: 'global'` for a home-scoped file.
- New: GET project-shadows-home (regression cover for the documented
  priority).
- New: DELETE removes a real home-scoped file when no project is
  registered, and verifies the file actually disappears from
  `~/.archon/workflows/`.
- Updated: the existing "fall back to getArchonHome() when no cwd"
  PUT test now asserts `source: 'global'` and verifies the file lands
  at `~/.archon/workflows/<name>.yaml`, not at the legacy
  `<archonHome>/.archon/workflows/...` path.
- Tests pull `ARCHON_HOME` via `process.env`, matching the existing
  pattern in this file.

Out of scope

`WorkflowExecution.tsx` shows "Loading graph…" without a timeout or
error path when the GET returns anything other than 200 — flagged in
@blankse blankse force-pushed the fix/1524-home-scoped-workflow-endpoints branch from 4ad107f to d4d0394 Compare May 14, 2026 12:03
@Wirasm

Wirasm commented May 15, 2026

Copy link
Copy Markdown
Collaborator

Review Summary

Verdict: ready-to-merge

Clean fix for the fallback-path regression in PUT and DELETE workflow routes. Both handlers were silently writing to ~/.archon/.archon/workflows/ instead of ~/.archon/workflows/ when no project was registered. Code quality, error handling, and test coverage are solid — only minor comment hygiene items remain.

Blocking issues

None.

Suggested fixes

None — all remaining items are optional.

Minor / nice-to-have

  • api.ts:2361-2367 — The multi-line comment in the PUT handler references workflow-discovery.ts by name. If that warning ever moves or changes, this comment becomes misleading. A single-line comment like // Write to project dir if cwd/codebase exists; otherwise fall back to ~/.archon/workflows/. would be clearer and lower-maintenance.

  • api.ts:2431-2434 — Same issue in the DELETE handler: duplicate multi-line block with the same rot risk. Replace with // Falls back to ~/.archon/workflows/ (not the legacy archonHome path).

  • api.ts:2445workflow.delete_failed log omits filePath in context, while the PUT handler at line 2404 includes dirPath. For consistency when debugging a delete failure, add it:

    getLog().error({ err, name, filePath }, 'workflow.delete_failed');
  • api.workflows.test.ts:469-471 and 598-600 — Test comment headers include #1524 / Closes #1524. The issue number adds no value once the PR is merged and will become noise. Safe to remove.

  • api.ts:2324// 4. Source-build fallback: filesystem-backed defaults is a section label rather than a why-comment. Consider whether it's needed at all given the surrounding code.

Compliments

  • The source: 'global' assertion updated from the old project expectation is exactly the right regression test: it would have caught the bug before the fix landed.
  • The new DELETE test (removes home-scoped workflow when no cwd / no codebases registered) provides genuine coverage for the broken path that silently failed before — not just a happy-path assertion.
  • The rename from falls back to getArchonHome() to falls back to home-scoped (~/.archon/workflows/) in the test name is a meaningful clarity improvement.

Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality.

@Wirasm

Wirasm commented May 15, 2026

Copy link
Copy Markdown
Collaborator

@blankse — first, real thank-you for this work. You correctly diagnosed that PUT and DELETE were missing the home-scoped (`~/.archon/workflows/`) layer that GET had been fixed for separately in #1405, and you kept this PR focused tightly on that gap with good test coverage and a rebase note that made the scope crystal-clear.

I'm closing this in favor of #1557 (@guanghuang), which lands the same server fix plus the Web UI integration that lets users actually exercise the capability from the workflow builder (`source` query parameter end-to-end through the React side, not just the API).

The two PRs converged on the same underlying problem but with different API contracts:

I went with #1557's explicit-parameter approach because (a) it matches the precedent for `source` in `GET /api/workflows` responses, and (b) the explicit contract avoids ambiguity when a workflow exists in both `project` and `global` locations (which one wins on PUT?).

Your test coverage on the home-scoped GET fallback that landed via the rebase is in dev now. Thank you for the careful diagnosis, and please don't read this as wasted effort — your work confirmed the bug existed and motivated the wider fix.

@Wirasm Wirasm closed this May 15, 2026
@blankse blankse deleted the fix/1524-home-scoped-workflow-endpoints branch May 15, 2026 12:34
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.

bug(server): GET/PUT/DELETE /api/workflows/{name} miss home-scoped (~/.archon/workflows/) — workflow detail page hangs

3 participants