Repository navigation
feat: pluggable CLI-based artifact resolver for porch - #613
timeleft-- wants to merge 11 commits into
Conversation
Add ArtifactResolver abstraction with LocalResolver (default) and CliResolver backends. Porch can now resolve specs, plans, and reviews from any CLI tool that supports `get` and `get --list` commands. Configuration via af-config.json: artifacts.backend: "cli" (or "local" default) artifacts.scope: "org/project/codev-assets" artifacts.command: "my-tool" (CLI executable) Closes #612 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CliResolver is fully generic — no default command, no legacy env vars, no backend aliases. Users must explicitly set artifacts.command in af-config.json. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use ContentRef resolver approach with upstream's string ID handling. Drop issueAsNumber() helper — upstream already accepts string IDs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Spec, plan, and review documents for the CLI-based artifact resolver. Follows SPIR protocol with 3-way expert consultation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix silent fallback in findSpecContent/findPlanContent — config errors now propagate instead of silently falling back to local filesystem - Fix stale "Spec 559" comment → link to GitHub issue #612 - Add 23 unit tests for CliResolver, LocalResolver, isPreApprovedContent, and getResolver factory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…es regex - builder-prompt.md: change SPIR protocol reference to ASPIR - spawn.ts: call initPorchInWorktree() in spawnTask() when hasExplicitProtocol - checks.ts: use regex for has_phases_json to handle whitespace variations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nto builder worktrees Extends createWorktree() to symlink codev/protocols, codev/resources, and codev/roles from the workspace root into builder worktrees, with parent directory creation if needed. Skips if target already exists (git-tracked). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…etch in spawnSpec When no local spec file is found, spawnSpec() now tries the artifact resolver (getResolver().findSpecBaseName()) before falling back to a fatal GitHub issue fetch. This enables af spawn N --protocol aspir when specs exist only in an external CLI artifact backend (no local file, no GitHub issue required). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Architect Integration Review (3-way CMAP: Gemini, Codex, Claude)Hey timeleft--, thanks for this contribution! The That said, the reviewers identified a couple of correctness issues that would break CLI-backend workflows in practice, plus some cleanup items. I'd love to get these addressed so we can move this forward. Issues to address1. 2. 3. 4. Error messages hardcode local paths 5. No tests for 6. Drive-by changes Heads up on upcoming config workWe're currently working on a systematic configuration overhaul (#618) that will move Thanks again for the solid architecture work here! |
1. Fix spawnSpec to try resolver before fatal() for protocols with input.required (e.g. TICK) — previously the fatal exit ran before the resolver check, so CLI-backend specs were never found 2. Pass resolver to resolveArtifactBaseName() at all 3 call sites in check(), done(), and approve() — PROJECT_TITLE was wrong for CLI backend users in those commands (only getArtifactForPhase passed it) 3. Add 'fava-trails' as accepted alias for 'cli' backend in getResolver() and ArtifactConfig type — was mentioned in PR description but unimplemented 4. Make error messages in consult/index.ts backend-agnostic — remove hardcoded "in codev/specs/" / "in codev/plans/" from not-found errors 5. Add tests for runArtifactCheck() (plan_exists, has_phases_json, min_two_phases, review_has_arch_updates, review_has_lessons_updates, override skip path) and fava-trails alias in getResolver factory Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Review Feedback AddressedAll 6 items from the architect review have been addressed in the latest commit (7b92c21d): Issue #1 — Issue #2 — Issue #3 — Issue #4 — Error messages hardcode local paths ✅ Issue #5 — No tests for Issue #6 — Drive-by changes 📝 🤖 Generated with Claude Code |
… code Based on Claude reviewer feedback on PR #613: 1. Fix 4 callsites in index.ts that still used findPlanFile/extractPhasesFromFile directly, bypassing the resolver: status(), advanceProtocolPhase() ×2, rollback(). Now all use getPlanContent() and extractPlanPhasesResolved() with the resolver threaded through. 2. Remove dead code: findSpec() and findPlan() in consult/index.ts are no longer called after the resolver migration (findSpecContent/findPlanContent use the resolver instead). 3. Remove console.error diagnostic logging from getProjectSummary() in prompts.ts — these produced stderr noise on every offline/CI invocation. 4. Remove extra blank line at consult/index.ts:1146. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The fatal() error message when no spec is found still referenced codev/specs/ as the expected location, which is confusing for users with a CLI artifact backend. Remove the local path hint — the spec ID is sufficient to identify what's missing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CMAP Review Results (Round 2)3-way parallel review (gemini, codex, claude) on latest commits:
CMAP findings and dispositions1. 2. 3. Review doc has Summary of all changes in this PRAll 6 original architect review items are addressed. Two additional rounds of fixes based on CMAP feedback:
🤖 Generated with Claude Code |
|
Hey — appreciate the work on this! Wanted to flag that PR #624 (the systematic configuration overhaul, now in v3.0.0-rc.8) made significant changes to porch internals — unified config loader, runtime file resolution, and a new four-tier resolution chain. This PR was written against the pre-#624 codebase and will have substantial conflicts. Could you take a look at what landed in #624 and assess whether the pluggable artifact resolver is still useful given the new architecture? If it is, it would need a rewrite against the current codebase. The key files that changed are |
Addressed Review FeedbackThree commits added to address all 6 items from the review:
|
Nice. Thanks for the headsup @waleedkadous . I will rebase the changes to the latest, and focus on the key files that changed. |
Summary
Adds a pluggable
ArtifactResolverabstraction to porch so specs, plans, and reviews can be resolved from external systems — not just localcodev/specs/,codev/plans/files.LocalResolver(default): wraps existing filesystem logic, zero behavior changeCliResolver: shells out to any CLI that supports<cmd> get <scope>and<cmd> get --list <scope>Configuration
{ "artifacts": { "backend": "cli", "scope": "org/project/codev-assets", "command": "my-artifact-tool" } }What's included
artifacts.tswithArtifactResolverinterface,LocalResolver,CliResolver, factory + confignext,prompts,plan,checks,state,indexrunArtifactCheck()for resolver-based plan/review checks (replaces hardcoded shell commands)consultCLI updated to use resolver for spec/plan content (inlines content instead of file paths)af statusshows configured artifact backendresolveArtifactBaseName()uses resolver for spec discoveryisPreApprovedContent()helper for both resolversCODEV_ARTIFACTS_DATA_REPOenv var propagated to terminal sessionsBackward compatibility
backend: "local"(or unset) behaves identically to current behaviorbackend: "fava-trails"accepted as alias for"cli"CLI protocol
Any CLI tool that implements these two commands works as an artifact backend:
Closes #612
Test plan
porch status,porch next,porch donework with local backend (no config change)af statusdisplays artifact backend when configured🤖 Generated with Claude Code