Repository navigation
[Spec 618] Systematic configuration overhaul - #624
Conversation
Addresses feedback from Gemini, Codex, and Claude: - Claude-specific files (.claude/skills, CLAUDE.md) explicitly out of scope for runtime resolution - Deep merge semantics defined (arrays replace, objects merge, null removes) - Two independent resolution chains documented and unification planned - Error handling for config files specified - models field typed as string | string[] - Default config when no files exist - All config loading sites enumerated - Remote source ref pinning added
Addresses iteration 2 feedback from all three reviewers: - Expanded config loading sites from 3 to 10 (forge, tower, spawn-worktree, etc.) - Added third resolution chain (prompts.ts has its own PROTOCOL_PATHS) - Added forge section to config schema - Changed codev update to one-time skeleton cleanup (prevents update shadowing) - Defined consultation mode behavior in verify steps - Added codev adopt --update flag for Claude-specific file updates - Clarified null removal, default config, remote source pre-Phase 4 behavior
…esign Added 'What Lives Where' table, 'What This Means for Users' section, and concrete example of resolution order to make it clear that version-dependent files (protocols, roles, templates) stay in the npm package and are read at runtime — not copied into projects.
Full design for remote protocol fetching: - Git clone via shallow clone, uses existing SSH/HTTPS auth - Cache at ~/.codev/cache/ with immutable ref optimization - ref is required (prevents silent drift) - Fail hard on fetch failure (no silent fallback) - codev protocols fetch/--force commands - Resolution chain: local > project > remote > package - Security: trust model, audit, immutable refs recommended
Remote protocol fetching now goes through the forge's concept-command system via a new 'repo-archive' concept, not raw git clone. This: - Uses existing forge auth (gh CLI for GitHub, glab for GitLab, etc.) - No dependency on git CLI being installed - Platform-agnostic via forge providers - Consistent with how codev interacts with external platforms - Source config is forge-relative (owner/repo), not a git URL
Remote sources now cover the full framework (protocols, roles, consult-types, templates, porch prompts), not just protocols. Config key is 'framework', command is 'codev sync' (with --force and --status flags).
- framework.type: 'forge' (default) or 'command' (arbitrary CLI) - source accepts full URLs and forge-relative owner/repo - ref is now optional (defaults to repo's default branch) - Remote framework can include base config.json (participates in config layering) - codev update becomes the full migration tool (moves config, cleans skeleton, updates Claude files) - command type: escape hatch for self-hosted git, S3, NFS, etc.
| { | ||
| "porch": { | ||
| "consultation": { | ||
| "models": ["claude", "gemini"] |
There was a problem hiding this comment.
are these really models? I'm not raising an issue with terminology , just wondering if this is a spot where users would add custom ones. Is the model in this context the cli command that codev executes to trigger the consult? If yes, I might try and do gemini -m "<some model of my choosing>
There was a problem hiding this comment.
Good question! You're right that "models" here refers to CLI command names (gemini, codex, claude) — each maps to a consult -m <name> invocation, not a raw model ID like gemini-3-pro-preview. Your instinct about wanting to use a custom backing model is spot on though — today consult only knows these three backends, so models in the config must be from that set. Extending to support user-registered models (e.g. a custom Ollama backend) is a natural follow-on but out of scope for this spec. We'll make sure the spec clarifies this distinction.
| - `["claude"]` — single-model mode (addresses #592) | ||
| - `["gemini", "codex", "claude"]` — current default (backward compatible) | ||
| - `"parent"` — delegate to architect session (foundation for #614) | ||
| - `"none"` — skip all consultations (equivalent to "without consultation") |
There was a problem hiding this comment.
ah I see, this section makes it clearer to me that they're cli commands, and not the backing model names.
| | Mode | Verify step behavior | | ||
| |------|---------------------| | ||
| | `["claude"]` | Run consult with only claude. Verify passes if claude approves. | | ||
| | `["gemini", "codex", "claude"]` | Current behavior — 3-way parallel consultation. | |
There was a problem hiding this comment.
wondering if models must be one of the three
There was a problem hiding this comment.
Yes, currently they must be one of the three registered backends. The spec should state this explicitly — and note that adding new backends would be a separate feature. Good catch.
|
|
||
| - **Fresh projects**: `codev init` no longer copies protocols/roles/templates. They resolve from the package. | ||
| - **Existing projects**: Local copies in `codev/protocols/` etc. continue to work (they take precedence). Over time, unmodified copies are cleaned up (see "Stale skeleton file cleanup" below). | ||
| - **Customization**: To customize a protocol, copy just that file into `.codev/protocols/<name>/protocol.json`. Your override takes precedence over the package version. |
There was a problem hiding this comment.
Does customize specifically mean override or does overrie behavior on ly occur if I the name I give the protocol in the path overlaps with an existing protocol? For instance if I named it SPIR that'd be an override but if I named the new protocol FOOBAR, then I've essentially created a new protocol? I am also not forgetting your guidance that my idea for a Quality engineering role I mentioned probably belongs somewhere as a part of a protocol or extension to an existing one.
There was a problem hiding this comment.
You've got it exactly right — it's both. Same name = override (your custom spir replaces the built-in one), new name like FOOBAR = net-new protocol. The resolution chain just looks for protocols/<name>/protocol.json at each tier, so whatever name you use in the path is what you get. And yes, your QE role idea could absolutely work as either a new protocol or an extension to SPIR (e.g. adding a QE verification phase). This framework makes both paths possible.
| - Detects existing `codev/protocols/` etc. — leaves them in place (they take precedence via resolution order) | ||
| - Creates `.codev/config.json` if not present | ||
|
|
||
| **`codev update` becomes the migration tool**: |
There was a problem hiding this comment.
This makes a lot of sense to me.
|
|
||
| ### 4. Remote Framework Sources | ||
|
|
||
| Teams can point to a shared repository containing their development framework — protocols, roles, consult-types, and templates: |
There was a problem hiding this comment.
This feature is going to be awesome!
There was a problem hiding this comment.
Thanks Damon! Really appreciate you taking the time to read through the whole spec and leave such thoughtful questions.
| } | ||
| ``` | ||
|
|
||
| The config key is `framework`, not `protocols`, because a team's shared methodology includes more than just protocols — it includes roles, consult-types, templates, porch prompts, and base config. The entire framework bundle is fetched and cached as a unit. |
There was a problem hiding this comment.
This is exactly the feature I was hoping for. Quick clarifying question about frameworks. Will storing multiple frameworks in the same repo be ok? (Basically wondering if the full path would be respected) Thinking about collecting favorites in one repo.
"framework": {
"source": "myorg/our-codev-frameworks/team-a-favorite-framework",
"ref": "v1.2.0"
}
"framework": {
"source": "myorg/our-codev-frameworks/<team-b-python-framework">,
"ref": "v1.2.0"
}
There was a problem hiding this comment.
Great question, and the short answer is yes — the source field supports subpaths, so myorg/our-codev-frameworks/team-a-favorite-framework and myorg/our-codev-frameworks/team-b-python-framework would both work from the same repo. The forge repo-archive concept would need to handle extracting just the specified subdirectory rather than the entire repo archive. We'll make sure the spec explicitly addresses subpath extraction and cache keying so there's no ambiguity about how this works.
|
Suggestion: for config/temp/etc. file locations use the XDG Base Directory Specification. Benefits include avoiding clutter in |
|
Thanks for the suggestion, Neil! We considered XDG and it's a solid standard. We went with |
…raction, override semantics 1. Section 2: Add note that model names must be registered backends (gemini, codex, claude); user-defined backends are future/out-of-scope. 2. Section 4: Add paragraph on subpath sources — forge fetches full archive, extracts subdirectory only; cache key includes full source string for independent caching. 3. Section 3: Add bullet clarifying override vs. create semantics — same name as built-in overrides it, new name creates net-new protocol, resolution chain handles both identically.
Six phases: unified config loader, unified file resolver, pluggable consultation models, init/adopt/update changes, remote framework sources, migration and cleanup.
Address issues from 3-way consultation (Gemini, Codex, Claude): - Fix config layering contradiction: project > global consistently across all phases - Fix consumer list: tower-terminals.ts and tower-instances.ts instead of architect.ts - Clarify parent/none validation path for consultation modes - Add command type env vars (CODEV_OUTPUT_DIR, CODEV_REF) to Phase 5 - Add ref requirement coverage in Phase 5 acceptance criteria - Add migration edge-case test scenarios to Phase 4 - Note: forge providers are github/gitlab/gitea (not Bitbucket)
- Drop af-config.json backward compat: hard error if found, no fallback - codev update: always refreshes CLAUDE.md/AGENTS.md (not just a no-op) - Remove --update flag from adopt (unclear purpose, codev update handles it) - repo-archive uses existing forge infrastructure, not standalone scripts - Worktree symlink: just rename af-config.json to .codev/config.json - Update risk analysis and validation checkpoints accordingly
New lib/config.ts provides centralized config loading with: - Three-layer merge: defaults → ~/.codev/config.json → .codev/config.json - Deep merge semantics: objects recurse, arrays replace, null deletes - Hard error if legacy af-config.json found (migration required) All consumers updated to use .codev/config.json: - agent-farm config.ts delegates to unified loader - porch config.ts delegates to unified loader - forge.ts delegates to unified loader - tower-terminals.ts, tower-instances.ts read .codev/config.json - send.ts detects .codev/ directory instead of af-config.json - spawn-worktree.ts symlinks .codev/config.json into worktrees - All string references updated from af-config.json to .codev/config.json
…json - agent-farm config.test.ts: mock lib/config.ts to avoid real workspace - spawn-worktree.test.ts: update symlinkConfigFiles tests for new .codev/ pattern, add mkdirSync mock - forge.test.ts: use .codev/config.json instead of af-config.json
- readJsonFile: handle EACCES/EPERM with warning + fallback (per spec) - loadForgeConfig: don't swallow af-config.json hard error - forge.test.ts: fix stale test name referencing af-config.json
…lution resolveCodevFile() now checks .codev/ → codev/ → skeleton/ in order: - skeleton.ts: added .codev/<path> as highest-priority tier - protocol.ts: replaced PROTOCOL_PATHS with resolveCodevFile() - prompts.ts: replaced PROTOCOL_PATHS with resolveCodevFile() - config.ts getRolesDir: added .codev/roles/ check Tests: 4 new tests for .codev/ resolution priority and fallthrough
…resolver Tests were writing protocols to codev-skeleton/ which is no longer in the resolution chain. Updated to use codev/ (project-level tier).
…pts and roles Address reviewer feedback: directory-level resolution broke per-file fallback when partial overrides exist. - prompts.ts: loadPromptFile now resolves each prompt file individually via resolveCodevFile(), removed findPromptsDir entirely - roles.ts: findRolePromptPath uses resolveCodevFile when workspaceRoot is available, with legacy fallback for backward compat - tower-utils.ts: passes workspaceRoot to RoleConfig
porch verify steps now use configurable models from .codev/config.json: - resolveConsultationModels() checks config porch.consultation.models - Config overrides protocol's verify.models (protocol is fallback) - "none" mode: skip verification entirely with clear note - "parent" mode: emit phase-review gate for architect review - Model validation: must be gemini, codex, or claude - Default behavior (no config) unchanged Tests: 7 new tests covering config loading for consultation modes
…fig models Address reviewer feedback: porch done was using protocol models, breaking config overrides. - index.ts done(): resolves effective models from config, handles "none" (skip verification) and "parent" (delegate to architect) - next.ts resolveConsultationModels(): let config errors propagate instead of silently swallowing them
…dev/
- init.ts: creates .codev/config.json instead of af-config.json,
no longer copies framework files (protocols, roles, consult-types)
- adopt.ts: creates .codev/config.json, leaves existing local files
in place (resolution chain handles them)
- update.ts: rewritten with two responsibilities:
A. One-time migration: af-config.json → .codev/config.json,
clean unmodified skeleton files using .update-hashes.json
B. Claude file refresh: always updates CLAUDE.md, AGENTS.md, skills
Skills are Claude-specific files that should be updated on every codev update run, not skipped when existing.
New codev sync command for fetching and caching remote frameworks: - repo-archive forge concept for github/gitlab/gitea providers - codev sync, codev sync --force, codev sync --status - Cache at ~/.codev/cache/framework/<hash>/<ref>/ - Subpath support (myorg/repo/team-a extracts only team-a/) - Framework type: "forge" (default) and "command" (arbitrary shell) - Immutable refs cached without re-fetch; branches re-fetch on sync Four-tier resolution chain: - skeleton.ts: .codev/ → codev/ → cache → skeleton - config.ts: defaults → cache config → global → project Tests: 10 new tests for cache dirs, resolution chain with cache
…cepts Updated concept count from 15 to 16 after adding repo-archive.
Address reviewer feedback: - Initialize framework cache dir in requireWorkspace() so remote framework files and config actually resolve in production - fetchFromCommand: use temp dir + atomic rename (no partial cache) - isImmutableRef: tighten to semver-like patterns (v1.0.0, not 1-branch)
…config.json Migrated all test files from af-config.json to .codev/config.json: - tower-test-utils.ts: creates .codev/config.json in test workspaces - send.test.ts: workspace detection checks for .codev/ dir - tower-instances/terminals tests: read .codev/config.json - All E2E tests: create .codev/ dir and write config.json there
Architect Integration Review (3-Way CMAP)Excellent work on this massive overhaul — the unified config loader, four-tier resolution chain, and pluggable consultation models are all well-designed. The test coverage is strong. However, the 3-way review (Gemini, Codex, Claude) surfaced 5 issues I'd like to see addressed before merge. 1. Tower config reads not migrated to unified loader (all 3 reviewers)
2.
|
6.
|
1. Tower config reads: tower-instances.ts and tower-terminals.ts now use loadConfig() instead of manual fs.readFileSync 2. af-config.json migration: deprecation warning with fallback instead of hard error; fix data loss when both configs exist (merge instead of skip+delete) 3. Workspace detection: check .codev/config.json (file) not .codev/ (directory) to avoid false positive at HOME 4. Framework cache: lazy initialization in skeleton.ts computes cache dir on first access, no explicit startup wiring needed 5. URL source parsing: parseSource handles http/https/git@ URLs
Calling copySkills without skipExisting silently overwrites user-customized skills. Restore skipExisting: true to preserve customizations while still adding new skills from the package.
Per architect: we don't do fallbacks. af-config.json presence triggers a hard error directing user to run 'codev update' to migrate. That IS the migration path.
Summary
Specification for a major configuration overhaul covering four concerns:
.codev/config.json— layered config (global~/.codev/+ project.codev/) replacingaf-config.json, with deep merge semanticsporch.consultation.models(single-model, none, parent modes)codev updatecodev syncfetches shared team frameworks via forge or arbitrary CLI commandTwo rounds of 3-way consultation (Gemini, Codex, Claude) completed. Architect review comments addressed.
Status
Spec only — no implementation code. Pending spec-approval gate.
Test plan
🤖 Generated with Claude Code