From e6d777e5896337a5fb9da75f3aeeedc384eb83e3 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 13 Jan 2026 06:50:56 -0800 Subject: [PATCH] feat: add Codex per-repo skills support - use-skills.sh: symlink to $CODEX_HOME/skills when CODEX_HOME is set - docs: update PER-REPO-SKILLS.md and RFC-SKILLS-MANIFEST.md with Codex flow - hq: add model configuration section (sonnet-4.5, Claude Max) - hq: update launch commands with explicit --model flag Closes skills-legi Co-Authored-By: Claude Opus 4.5 --- .beads/issues.jsonl | 1 + bin/use-skills.sh | 5 +++++ docs/PER-REPO-SKILLS.md | 10 ++++++++-- docs/RFC-SKILLS-MANIFEST.md | 9 ++++++++- skills/hq/README.md | 2 +- skills/hq/SKILL.md | 15 ++++++++++++--- 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index d5effa7..ee07692 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -186,6 +186,7 @@ {"id":"skills-koes","title":"Add file path context to JSON parse errors in context.nim","description":"[ERROR] LOW context.nim:22-23 - parseJson/fromJson errors don't include file path. Wrap with try/except adding: 'Failed to parse context file {path}'","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-10T20:10:03.902733605-08:00","created_by":"dan","updated_at":"2026-01-10T20:37:04.754197256-08:00","closed_at":"2026-01-10T20:37:04.754197256-08:00","close_reason":"Implemented consistent error handling strategy"} {"id":"skills-kvdl","title":"Remove unused globalChannel variable in heartbeat.nim","description":"[DEAD] LOW heartbeat.nim:37 - globalChannel declared but never used. Compiler warns about this. Delete unused variable.","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-10T19:54:45.125528634-08:00","created_by":"dan","updated_at":"2026-01-10T20:24:43.733773826-08:00","closed_at":"2026-01-10T20:24:43.733773826-08:00","close_reason":"Fixed: removed unused globalChannel in heartbeat.nim rewrite"} {"id":"skills-le9","title":"beads new --from-cursor: capture symbol context","description":"When creating a bead, auto-capture LSP context:\n- Current symbol FQN (fully qualified name)\n- Definition snippet\n- Top 10 references/callers\n- Current diagnostics for the symbol\n\nMakes beads self-contained without copy/paste archaeology. Symbol URI allows jumping back to exact location even if file moved.","status":"open","priority":3,"issue_type":"feature","created_at":"2025-12-24T02:29:55.989876856-05:00","updated_at":"2025-12-24T02:29:55.989876856-05:00","dependencies":[{"issue_id":"skills-le9","depends_on_id":"skills-gga","type":"blocks","created_at":"2025-12-24T02:30:06.416484732-05:00","created_by":"daemon"}]} +{"id":"skills-legi","title":"Add Codex per-repo skills support in use-skills.sh","description":"Changes staged locally in skills repo: bin/use-skills.sh now links to /skills when CODEX_HOME is set; docs updated (RFC-SKILLS-MANIFEST.md, PER-REPO-SKILLS.md) to document Codex per-repo flow and .codex/skills/ gitignore. Next steps: commit/push skills repo changes, then update dotfiles flake input to a clean rev (remove dirtyRev) after pull.","status":"open","priority":2,"issue_type":"task","owner":"dan@delpad","created_at":"2026-01-13T06:50:06.197221856-08:00","created_by":"dan","updated_at":"2026-01-13T06:50:06.197221856-08:00"} {"id":"skills-lie","title":"Compare DEPENDENCIES.md with upstream","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-03T20:15:53.925914243-08:00","updated_at":"2025-12-03T20:19:28.665641809-08:00","closed_at":"2025-12-03T20:19:28.665641809-08:00","dependencies":[{"issue_id":"skills-lie","depends_on_id":"skills-ebh","type":"discovered-from","created_at":"2025-12-03T20:15:53.9275694-08:00","created_by":"daemon","metadata":"{}"}]} {"id":"skills-lr29","title":"review-gate: CI/test gates before approve","description":"**Raised by:** flash-or, gemini, gpt (all three)\n\n**Problem:**\n\"Tests pass\" is vague. HQ is an LLM reviewing text, not behavior. It might approve code that looks correct but fails tests or doesn't build. \"LGTM syndrome.\"\n\n**flash-or:**\n\u003e \"The worker state IN_REVIEW should be unreachable unless a 'worker test' command (or CI check) returns a success code. HQ should see the test logs *before* the diff.\"\n\n**gemini:**\n\u003e \"HQ is reviewing text, not behavior. The review phase *must* include a tool output proving success. 'worker approve' should arguably be blocked unless 'worker test-results' returns PASS.\"\n\n**gpt:**\n\u003e \"'Tests pass' is necessary but not sufficient. Flaky tests will cause thrash. Define test tiers and when each is required. Add a 'post-merge verification' stage.\"\n\n**Suggested fixes:**\n1. worker verify \u003ctask-id\u003e command that runs CI checks\n2. IN_REVIEW requires test pass proof\n3. Approve blocked unless test output verified\n4. Post-merge CI verification before bd close\n5. Test tier definitions (unit, integration, e2e)\n6. Flake handling policy","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-12T09:21:27.600572533-08:00","created_by":"dan","updated_at":"2026-01-12T09:42:02.492169038-08:00","comments":[{"id":9,"issue_id":"skills-lr29","author":"dan","text":"[RECLASSIFY:2026-01-12T09:42:02-08:00] Moved from HQ to review-gate layer.\n\nThis is quality enforcement, not orchestration. review-gate should verify tests pass before allowing approve. HQ just respects the gate.","created_at":"2026-01-12T17:42:02Z"}]} {"id":"skills-luzk","title":"Extract rowToWorkerInfo helper in state.nim","description":"[REDUNDANCY] LOW state.nim:136-143,165-172 - WorkerInfo construction duplicated in getWorker() and getAllWorkers(). Extract proc rowToWorkerInfo(row): WorkerInfo.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-10T19:49:53.238303032-08:00","created_by":"dan","updated_at":"2026-01-11T15:34:20.564896474-08:00","closed_at":"2026-01-11T15:34:20.564896474-08:00","close_reason":"Closed"} diff --git a/bin/use-skills.sh b/bin/use-skills.sh index 23a8bc9..3e6af5f 100755 --- a/bin/use-skills.sh +++ b/bin/use-skills.sh @@ -4,6 +4,7 @@ # # Usage in .envrc: # source ~/proj/skills/bin/use-skills.sh +# export CODEX_HOME="$PWD/.codex" # Optional: per-repo Codex skills # use_skills worklog web-search # # Or with manifest file: @@ -28,6 +29,10 @@ use_skill() { mkdir -p .claude/skills .opencode/skills ln -sfn "$out" ".claude/skills/${skill}" ln -sfn "$out" ".opencode/skills/${skill}" + if [[ -n "${CODEX_HOME:-}" ]]; then + mkdir -p "${CODEX_HOME}/skills" + ln -sfn "$out" "${CODEX_HOME}/skills/${skill}" + fi echo "use_skill: ${skill}" } diff --git a/docs/PER-REPO-SKILLS.md b/docs/PER-REPO-SKILLS.md index 64dd9c2..44b3c6b 100644 --- a/docs/PER-REPO-SKILLS.md +++ b/docs/PER-REPO-SKILLS.md @@ -4,7 +4,7 @@ Deploy selected skills to individual projects using direnv + Nix. ## Overview -Each project can declare which skills it needs. When team members enter the directory (via direnv), skills are symlinked from the Nix store into `.claude/skills/` and `.opencode/skills/`. +Each project can declare which skills it needs. When team members enter the directory (via direnv), skills are symlinked from the Nix store into `.claude/skills/` and `.opencode/skills/` (and `$CODEX_HOME/skills` if set). ``` teammate clones repo @@ -25,6 +25,7 @@ teammate clones repo **Option A: Source the helper** (if skills repo is accessible) ```bash source ~/proj/skills/bin/use-skills.sh +export CODEX_HOME="$PWD/.codex" # Optional: per-repo Codex skills use_skills worklog web-search ``` @@ -41,6 +42,10 @@ use_skill() { mkdir -p .claude/skills .opencode/skills ln -sfn "$out" ".claude/skills/${skill}" ln -sfn "$out" ".opencode/skills/${skill}" + if [[ -n "${CODEX_HOME:-}" ]]; then + mkdir -p "${CODEX_HOME}/skills" + ln -sfn "$out" "${CODEX_HOME}/skills/${skill}" + fi echo "use_skill: ${skill}" fi } @@ -54,6 +59,7 @@ use_skill web-search ``` .claude/skills/ .opencode/skills/ +.codex/skills/ ``` ### 3. Done @@ -78,7 +84,7 @@ Current list: 1. **direnv** triggers on directory entry 2. **nix build** fetches/builds the skill package (cached locally) -3. **symlink** points `.claude/skills/` to `/nix/store/xxx-ai-skill-` +3. **symlink** points `.claude/skills/` to `/nix/store/xxx-ai-skill-` (and `$CODEX_HOME/skills/` if set) 4. **Claude Code** reads skills from `.claude/skills/` when in that directory Skills are always fetched from the latest commit on the skills repo. Nix caches builds locally, so subsequent loads are fast. diff --git a/docs/RFC-SKILLS-MANIFEST.md b/docs/RFC-SKILLS-MANIFEST.md index 5d1a6bb..ff8aa44 100644 --- a/docs/RFC-SKILLS-MANIFEST.md +++ b/docs/RFC-SKILLS-MANIFEST.md @@ -58,6 +58,7 @@ Projects add to their `.envrc`: ```bash # AI Agent Skills if [[ -f .skills ]]; then + export CODEX_HOME="$PWD/.codex" # Optional: per-repo Codex skills SKILLS_REPO="${SKILLS_REPO:-git+file://$HOME/proj/skills}" mkdir -p .claude/skills .opencode/skills while IFS= read -r skill || [[ -n "$skill" ]]; do @@ -68,6 +69,10 @@ if [[ -f .skills ]]; then if [[ -n "$out" ]]; then ln -sfn "$out" ".claude/skills/${skill}" ln -sfn "$out" ".opencode/skills/${skill}" + if [[ -n "${CODEX_HOME:-}" ]]; then + mkdir -p "${CODEX_HOME}/skills" + ln -sfn "$out" "${CODEX_HOME}/skills/${skill}" + fi fi done < .skills fi @@ -77,6 +82,7 @@ Or source the helper: ```bash if [[ -f .skills ]]; then + export CODEX_HOME="$PWD/.codex" # Optional: per-repo Codex skills source ~/proj/skills/bin/use-skills.sh load_skills_from_manifest fi @@ -87,6 +93,7 @@ fi ``` .claude/skills/ .opencode/skills/ +.codex/skills/ ``` The manifest (`.skills`) IS committed. The symlinks are not. @@ -231,4 +238,4 @@ echo ".claude/skills/" >> .gitignore - [ ] Create template CLAUDE.md blurb - [ ] Survey existing projects for migration - [ ] Migrate pilot project -- [ ] Update AGENTS.md with pattern reference \ No newline at end of file +- [ ] Update AGENTS.md with pattern reference diff --git a/skills/hq/README.md b/skills/hq/README.md index 8b4b288..553e191 100644 --- a/skills/hq/README.md +++ b/skills/hq/README.md @@ -121,7 +121,7 @@ load_skills_from_manifest 4. **Launch worker agent** (see SKILL.md for agent-specific commands): ```bash cd worktrees/skills-abc - claude -p "$(cat .worker-prompt.md)" + claude --model sonnet-4.5 -p "$(cat .worker-prompt.md)" ``` 5. **Monitor and review**: diff --git a/skills/hq/SKILL.md b/skills/hq/SKILL.md index d49b938..37d7075 100644 --- a/skills/hq/SKILL.md +++ b/skills/hq/SKILL.md @@ -25,7 +25,7 @@ Load this skill when: **Workers can be different agents than HQ.** Common pattern: - HQ: Gemini or Codex (orchestration) -- Workers: Claude Code Sonnet (implementation) +- Workers: Claude Code Sonnet 4.5 (implementation) All coordination happens through: - Filesystem (worktrees, context files) @@ -70,6 +70,14 @@ HQ is a **thin orchestration layer**. It makes decisions but delegates execution **Principle:** If something can be handled by a lower layer, delegate it. HQ should not implement retry logic, rebase commands, or test runners - it just invokes tools that do. +## Subscription & Model Configuration + +The preferred configuration for worker agents is: +- **Default Model:** `sonnet-4.5` +- **Subscription:** Claude Max (ensure `claude setup-token` is configured if using service tokens) + +When launching workers, always explicitly specify the model to ensure consistency across environments. + ## Core Loop ``` @@ -172,12 +180,13 @@ sed -e "s/{{TASK_ID}}/$TASK_ID/g" \ **Claude Code:** ```bash -cd "$WORKTREE" && claude -p "$(cat .worker-prompt.md)" +# Using Sonnet 4.5 with Max subscription +cd "$WORKTREE" && claude --model sonnet-4.5 -p "$(cat .worker-prompt.md)" ``` For background execution: ```bash -cd "$WORKTREE" && nohup claude -p "$(cat .worker-prompt.md)" > worker.log 2>&1 & +cd "$WORKTREE" && nohup claude --model sonnet-4.5 -p "$(cat .worker-prompt.md)" > worker.log 2>&1 & disown ```