fix(use-skills): prevent stderr from corrupting symlink targets

Remove 2>&1 from nix build capture. When repo is dirty, nix emits
warnings to stderr which were being merged into $out and used as
symlink targets, creating broken symlinks like:

  orch -> warning: Git tree '...' is dirty\n/nix/store/...

Now stderr goes to terminal, only stdout (store path) captured.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
dan 2025-12-14 12:42:26 -08:00
parent 67f6d69cc7
commit 90e72f1095
3 changed files with 173 additions and 2 deletions

View file

@ -11,13 +11,16 @@
{"id":"skills-7sh","title":"Set up bd-issue-tracking Claude Code skill from beads repo","description":"Install the beads Claude Code skill from https://github.com/steveyegge/beads/tree/main/examples/claude-code-skill\n\nThis skill teaches Claude how to effectively use beads for issue tracking across multi-session coding workflows. It provides strategic guidance on when/how to use beads, not just command syntax.\n\nFiles to install to ~/.claude/skills/bd-issue-tracking/:\n- SKILL.md - Core workflow patterns and decision criteria\n- BOUNDARIES.md - When to use beads vs markdown alternatives\n- CLI_REFERENCE.md - Complete command documentation\n- DEPENDENCIES.md - Relationship types and patterns\n- WORKFLOWS.md - Step-by-step procedures\n- ISSUE_CREATION.md - Quality guidelines\n- RESUMABILITY.md - Making work resumable across sessions\n- STATIC_DATA.md - Using beads as reference databases\n\nCan symlink or copy the files. Restart Claude Code after install.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-03T17:53:43.254007992-08:00","updated_at":"2025-12-03T20:04:53.416579381-08:00","closed_at":"2025-12-03T20:04:53.416579381-08:00"}
{"id":"skills-8d4","title":"Compare CLI_REFERENCE.md with upstream","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-03T20:15:53.268324087-08:00","updated_at":"2025-12-03T20:17:26.552616779-08:00","closed_at":"2025-12-03T20:17:26.552616779-08:00","dependencies":[{"issue_id":"skills-8d4","depends_on_id":"skills-ebh","type":"discovered-from","created_at":"2025-12-03T20:15:53.27265681-08:00","created_by":"daemon"}]}
{"id":"skills-a23","title":"Update main README to list all 9 skills","description":"Main README.md 'Skills Included' section only lists worklog and update-spec-kit. Repo actually has 9 skills: template, worklog, update-spec-kit, screenshot-latest, niri-window-capture, tufte-press, update-opencode, web-research, web-search.","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-30T11:58:14.042397754-08:00","updated_at":"2025-11-30T12:00:18.916270858-08:00","dependencies":[{"issue_id":"skills-a23","depends_on_id":"skills-4yn","type":"blocks","created_at":"2025-11-30T12:01:30.306742184-08:00","created_by":"daemon"}]}
{"id":"skills-al5","title":"Consider repo-setup-verification skill","description":"The dotfiles repo has a repo-setup-prompt.md verification checklist that could become a skill.\n\n**Source**: ~/proj/dotfiles/docs/repo-setup-prompt.md\n\n**What it does**:\n- Verifies .envrc has use_api_keys and skills loading\n- Checks .skills manifest exists with appropriate skills\n- Optionally checks beads setup\n- Verifies API keys are loaded\n\n**As a skill it could**:\n- Be invoked to audit any repo's agent setup\n- Offer to fix missing pieces\n- Provide consistent onboarding for new repos\n\n**Questions**:\n- Is this better as a skill vs a slash command?\n- Should it auto-fix or just report?\n- Does it belong in skills repo or dotfiles?","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-06T12:38:32.561337354-08:00","updated_at":"2025-12-06T12:38:32.561337354-08:00"}
{"id":"skills-bcu","title":"Design doc-review skill","description":"# doc-review skill\n\nFight documentation drift with a non-interactive review process that generates patchfiles for human review.\n\n## Problem\n- No consistent documentation system across repos\n- Stale content accumulates\n- Structural inconsistencies (docs not optimized for agents)\n\n## Envisioned Workflow\n\n```bash\n# Phase 1: Generate patches (non-interactive, use spare credits, test models)\ndoc-review scan ~/proj/foo --model claude-sonnet --output /tmp/foo-patches/\n\n# Phase 2: Review patches (interactive session)\ncd ~/proj/foo\nclaude # human reviews patches, applies selectively\n```\n\n## Design Decisions Made\n\n- **Trigger**: Manual invocation (not CI). Use case includes burning extra LLM credits, testing models repeatably.\n- **Source of truth**: Style guide embedded in prompt template. Blessed defaults, overridable per-repo.\n- **Output**: Patchfiles for human review in interactive Claude session.\n- **Chunking**: Based on absolute size, not file count. Logical chunks easy for Claude to review.\n- **Scope detection**: Graph-based discovery starting from README.md or AGENTS.md, not glob-all-markdown.\n\n## Open Design Work\n\n### Agent-Friendly Doc Conventions (needs brainstorming)\nWhat makes docs agent-readable?\n- Explicit context (no \"as mentioned above\")\n- Clear section headers for navigation\n- Self-contained sections\n- Consistent terminology\n- Front-loaded summaries\n- ???\n\n### Prompt Content\nFull design round needed on:\n- What conventions to enforce\n- How to express them in prompt\n- Examples of \"good\" vs \"bad\"\n\n### Graph-Based Discovery\nHow does traversal work?\n- Parse links from README/AGENTS.md?\n- Follow relative markdown links?\n- Depth limit?\n\n## Skill Structure (tentative)\n```\nskills/doc-review/\n├── prompt.md # Core review instructions + style guide\n├── scan.sh # Orchestrates: find docs → invoke claude → emit patches\n└── README.md\n```\n\n## Out of Scope (for now)\n- Cross-repo standardization (broader than skills repo)\n- CI integration\n- Auto-apply without human review","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-04T14:01:43.305653729-08:00","updated_at":"2025-12-04T16:44:03.468118288-08:00","closed_at":"2025-12-04T16:44:03.468118288-08:00","dependencies":[{"issue_id":"skills-bcu","depends_on_id":"skills-1ig","type":"blocks","created_at":"2025-12-04T14:02:17.144414636-08:00","created_by":"daemon"},{"issue_id":"skills-bcu","depends_on_id":"skills-53k","type":"blocks","created_at":"2025-12-04T14:02:17.164968463-08:00","created_by":"daemon"}]}
{"id":"skills-cnc","title":"Add direnv helper for per-repo skill deployment","description":"Create sourceable helper script and documentation for the standard per-repo skill deployment pattern using direnv + nix build.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-11-30T12:19:20.71056749-08:00","updated_at":"2025-11-30T12:37:47.22638278-08:00","closed_at":"2025-11-30T12:37:47.22638278-08:00"}
{"id":"skills-czz","title":"Research OpenCode agents for skill integration","description":"DEPLOYMENT.md:218 has TODO to research OpenCode agents. Need to understand how Build/Plan/custom agents work and whether skills need agent-specific handling.","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-30T11:58:24.855701141-08:00","updated_at":"2025-11-30T11:58:24.855701141-08:00"}
{"id":"skills-d6r","title":"Design: orch as local agent framework","description":"# Orch Evolution: From Consensus Tool to Agent Framework\n\n## Current State\n- `orch consensus` - multi-model queries\n- `orch chat` - single model queries\n- No state, no pipelines, no retries\n\n## Proposed Extensions\n\n### Pipeline Mode\n```bash\norch pipeline config.yaml\n```\nWhere config.yaml defines:\n- Stages (triage → specialists → verify)\n- Routing logic (if triage finds X, run specialist Y)\n- Retry policy\n\n### Evaluate Mode (doc-review specific)\n```bash\norch evaluate doc.md --rubrics=1,4,7 --output=patches/\n```\n- Applies specific rubrics to document\n- Outputs JSON or patches\n\n### Parallel Mode\n```bash\norch parallel --fan-out=5 --template=\"evaluate {rubric}\" rubrics.txt\n```\n- Fan-out to multiple parallel calls\n- Aggregate results\n\n## Open Questions\n1. Does this belong in orch or a separate tool?\n2. Should orch pipelines be YAML-defined or code-defined?\n3. How does this relate to Claude Code Task subagents?\n4. What's the minimal viable extension?\n\n## Context\nEmerged from doc-review skill design - need multi-pass evaluation but don't want to adopt heavy framework (LangGraph, etc.)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-04T16:06:56.681282678-08:00","updated_at":"2025-12-04T16:44:08.652185174-08:00","closed_at":"2025-12-04T16:44:08.652185174-08:00"}
{"id":"skills-d87","title":"orch skill is documentation-only, needs working invocation mechanism","description":"The orch skill provides SKILL.md documentation but no working invocation mechanism.\n\n**Resolution**: Install orch globally via home-manager (dotfiles-3to). The skill documents a system tool, doesn't need to bundle it.\n\n**Blocked by**: dotfiles-3to (Add orch CLI to home-manager packages)","status":"open","priority":2,"issue_type":"bug","created_at":"2025-12-14T11:54:03.157039164-08:00","updated_at":"2025-12-14T12:05:26.427975702-08:00"}
{"id":"skills-dpw","title":"orch: add command to show available/configured models","description":"## Problem\n\nWhen trying to use orch, you have to trial-and-error through models to find which ones have API keys configured. Each failure looks like:\n\n```\nError: GEMINI_API_KEY not set. Required for Google Gemini models.\n```\n\nNo way to know upfront which models are usable.\n\n## Proposed Solution\n\nAdd `orch models` or `orch status` command:\n\n```bash\n$ orch models\nAvailable models:\n ✓ flash (GEMINI_API_KEY set)\n ✓ gemini (GEMINI_API_KEY set)\n ✗ deepseek (OPENROUTER_KEY not set)\n ✗ qwen (OPENROUTER_KEY not set)\n ✓ gpt (OPENAI_API_KEY set)\n```\n\nOr at minimum, on failure suggest alternatives:\n```\nError: GEMINI_API_KEY not set. Try --model gpt or --model deepseek instead.\n```\n\n## Context\n\nHit this while trying to brainstorm with high-temp gemini - had to try 4 models before realizing none were configured in this environment.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-12-04T14:10:07.069103175-08:00","updated_at":"2025-12-04T14:11:05.49122538-08:00","closed_at":"2025-12-04T14:11:05.49122538-08:00"}
{"id":"skills-ebh","title":"Compare bd-issue-tracking skill files with upstream","description":"Fetch upstream beads skill files and compare with our condensed versions to identify differences","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-03T20:14:07.886535859-08:00","updated_at":"2025-12-03T20:19:37.579815337-08:00","closed_at":"2025-12-03T20:19:37.579815337-08:00"}
{"id":"skills-fo3","title":"Compare WORKFLOWS.md with upstream","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-03T20:15:54.283175561-08:00","updated_at":"2025-12-03T20:19:28.897037199-08:00","closed_at":"2025-12-03T20:19:28.897037199-08:00","dependencies":[{"issue_id":"skills-fo3","depends_on_id":"skills-ebh","type":"discovered-from","created_at":"2025-12-03T20:15:54.286009672-08:00","created_by":"daemon"}]}
{"id":"skills-fvx","title":"use-skills.sh: stderr from nix build corrupts symlinks when repo is dirty","description":"In use-skills.sh, the line:\n\n```bash\nout=$(nix build --print-out-paths --no-link \"${SKILLS_REPO}#${skill}\" 2\u003e\u00261) || {\n```\n\nThe `2\u003e\u00261` merges stderr into stdout. When the skills repo is dirty, nix emits a warning to stderr which gets captured into $out and used as the symlink target.\n\nResult: symlinks like:\n```\norch -\u003e warning: Git tree '/home/dan/proj/skills' is dirty\n/nix/store/j952hgxixifscafb42vmw9vgdphi1djs-ai-skill-orch\n```\n\nFix: redirect stderr to /dev/null or filter it out before creating symlink.","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-12-14T11:54:03.06502295-08:00","updated_at":"2025-12-14T11:59:25.472044754-08:00","closed_at":"2025-12-14T11:59:25.472044754-08:00"}
{"id":"skills-kmj","title":"Orch skill: document or handle orch not in PATH","description":"Skill docs show 'orch consensus' but orch requires 'uv run' from ~/proj/orch. Either update skill to invoke correctly or document installation requirement.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-01T17:29:48.844997238-08:00","updated_at":"2025-12-01T18:28:11.374048504-08:00","closed_at":"2025-12-01T18:28:11.374048504-08:00"}
{"id":"skills-lie","title":"Compare DEPENDENCIES.md with upstream","description":"","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"}]}
{"id":"skills-lvg","title":"Compare ISSUE_CREATION.md with upstream","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-03T20:15:54.609282051-08:00","updated_at":"2025-12-03T20:19:29.134966356-08:00","closed_at":"2025-12-03T20:19:29.134966356-08:00","dependencies":[{"issue_id":"skills-lvg","depends_on_id":"skills-ebh","type":"discovered-from","created_at":"2025-12-03T20:15:54.610717055-08:00","created_by":"daemon"}]}
@ -26,3 +29,4 @@
{"id":"skills-qeh","title":"Add README.md for web-research skill","description":"web-research skill has SKILL.md and scripts but no README.md. AGENTS.md says README.md is for humans, contains installation instructions, usage examples, prerequisites.","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-30T11:58:14.475647113-08:00","updated_at":"2025-11-30T12:00:30.309340468-08:00","dependencies":[{"issue_id":"skills-qeh","depends_on_id":"skills-vb5","type":"blocks","created_at":"2025-11-30T12:01:30.278784381-08:00","created_by":"daemon"}]}
{"id":"skills-uz4","title":"Compare RESUMABILITY.md with upstream","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-03T20:15:54.897754095-08:00","updated_at":"2025-12-03T20:19:29.384645842-08:00","closed_at":"2025-12-03T20:19:29.384645842-08:00","dependencies":[{"issue_id":"skills-uz4","depends_on_id":"skills-ebh","type":"discovered-from","created_at":"2025-12-03T20:15:54.899671178-08:00","created_by":"daemon"}]}
{"id":"skills-vb5","title":"Resolve web search design questions","description":"web_search_brainstorm.md has unanswered design questions: single smart skill vs explicit flags, specific sources priority, raw links vs summaries. Need user input to finalize web-search/web-research direction.","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-30T11:58:33.482270742-08:00","updated_at":"2025-11-30T11:58:33.482270742-08:00"}
{"id":"skills-x2l","title":"Investigate hooks for parallel orch queries","description":"When using orch skill, it would be useful to spin off multiple model queries in parallel automatically (e.g., gemini + gpt simultaneously). Explore if Claude Code hooks can trigger parallel background processes when the orch skill is invoked.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-12-06T19:29:00.165752425-08:00","updated_at":"2025-12-06T19:29:00.165752425-08:00"}

View file

@ -20,9 +20,8 @@ use_skill() {
local skill="$1"
local out
out=$(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}" 2>&1) || {
out=$(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}") || {
echo "use_skill: failed to build ${skill}" >&2
echo "$out" >&2
return 1
}

View file

@ -0,0 +1,168 @@
#+TITLE: use-skills.sh Symlink Corruption Bug Fix and Orch Invocation Analysis
#+DATE: 2025-12-14
#+KEYWORDS: use-skills, symlink, nix, stderr, orch, direnv, cross-repo-deps, home-manager
#+COMMITS: 0 (uncommitted fix pending)
#+COMPRESSION_STATUS: uncompressed
* Session Summary
** Date: 2025-12-14 (Sunday)
** Focus Area: Diagnosing and fixing skill loading failures in per-repo deployment
* Accomplishments
- [X] Analyzed talu project's skill configuration status
- [X] Diagnosed why orch skill failed to work in talu session (from user-provided transcript)
- [X] Root-caused the symlink corruption bug in use-skills.sh
- [X] Fixed the stderr capture issue that corrupted symlink targets
- [X] Verified fix by reloading skills in talu - symlinks now correct
- [X] Filed skills-fvx (P1 bug) for symlink corruption - closed with fix
- [X] Filed skills-d87 (P2 bug) for orch invocation mechanism
- [X] Filed dotfiles-3to (P2 task) for adding orch to home-manager
- [X] Ran orch consensus to evaluate orch deployment options
- [ ] Commit the use-skills.sh fix (pending)
* Key Decisions
** Decision 1: Fix stderr capture by removing 2>&1
- Context: nix build emits warnings to stderr when repo is dirty
- Options considered:
1. Remove 2>&1 entirely - let stderr go to terminal, capture only stdout
2. Filter out warning lines with grep
3. Redirect stderr to temp file, only show on failure
- Rationale: Option 1 is simplest and correct - nix already shows errors on failure, no need to capture and re-echo
- Impact: Symlinks now contain only the store path, not warning text
** Decision 2: orch belongs in home-manager, not bundled in skill
- Context: orch skill provides documentation but CLI isn't in PATH
- Options considered (via orch consensus with gemini + gpt):
1. Wrapper script in skill - self-contained but hardcoded path
2. Global install via home-manager - system tool approach
3. Per-project direnv PATH - repetitive, fragile for agents
4. (Gemini suggestion) Build CLI from source in skill package
- Rationale: orch is a general-purpose system tool (like git, rg), not a project-specific dependency. System tools belong in home-manager.
- Impact: Cross-repo coordination needed - skills repo documents, dotfiles repo installs
** Decision 3: Cross-repo dependencies noted in description, not formal
- Context: skills-d87 is blocked by dotfiles-3to, but bd dep doesn't support cross-repo
- Options: Hard dep, soft/formal dep, or text note
- Rationale: Text note is sufficient for human readers, no tooling benefit from more formal tracking
- Impact: skills-d87 description mentions "Blocked by: dotfiles-3to"
* Problems & Solutions
| Problem | Solution | Learning |
|---------|----------|----------|
| Symlinks contained "warning: Git tree is dirty" in target path | Remove 2>&1 from nix build capture - let stderr go to terminal | Shell command substitution captures all stdout, including merged stderr |
| orch command not found when agent tried to use skill | Skill documents tool but doesn't provide it - need global install | Skills can be documentation-only for system tools |
| Can't create formal cross-repo dependency | Note in issue description | bd beads is per-repo; cross-repo tracking is manual |
* Technical Details
** Code Changes
- Total files modified: 1 (bin/use-skills.sh)
- Key files changed:
- ~bin/use-skills.sh~ - Removed 2>&1 from nix build command
** The Bug
Original code:
#+BEGIN_SRC bash
out=$(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}" 2>&1) || {
echo "use_skill: failed to build ${skill}" >&2
echo "$out" >&2
return 1
}
#+END_SRC
When repo is dirty, nix emits warning to stderr. The ~2>&1~ merges stderr into stdout, so ~$out~ becomes:
#+BEGIN_EXAMPLE
warning: Git tree '/home/dan/proj/skills' is dirty
/nix/store/j952hgxixifscafb42vmw9vgdphi1djs-ai-skill-orch
#+END_EXAMPLE
This multiline string with warning becomes the symlink target - completely broken.
** The Fix
#+BEGIN_SRC bash
out=$(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}") || {
echo "use_skill: failed to build ${skill}" >&2
return 1
}
#+END_SRC
Now stderr goes to terminal (where warnings belong), stdout captured cleanly.
** Commands Used
#+BEGIN_SRC bash
# Verify talu's skill setup
cat ~/proj/talu/.envrc
cat ~/proj/talu/.skills
ls -la ~/proj/talu/.claude/skills/
# Diagnose broken symlinks
readlink -f ~/proj/talu/.claude/skills/orch # showed "symlink broken"
# Test the fix
cd ~/proj/talu && rm -rf .claude/skills .opencode/skills
source ~/proj/skills/bin/use-skills.sh && load_skills_from_manifest
ls -la .claude/skills/ # now shows clean paths
# orch consensus for design decision
cd ~/proj/orch && uv run orch consensus "..." gemini gpt --mode vote
#+END_SRC
** Architecture Notes
- Skills system has two layers: skill packages (nix) and skill loading (direnv/bash)
- Skills can be documentation-only (assume tool exists) or bundled (include tool)
- System tools (git, rg, orch) should be globally installed, not per-skill
- Per-repo skill deployment via .skills manifest + direnv
* Process and Workflow
** What Worked Well
- User provided exact transcript of failure - made diagnosis quick
- orch consensus gave useful opposing viewpoints on design decision
- Cross-repo issue filing maintained traceability
** What Was Challenging
- Shell stderr/stdout behavior is easy to get wrong
- Cross-repo dependencies have no formal tooling support
* Learning and Insights
** Technical Insights
- ~$(cmd 2>&1)~ is dangerous when you only want stdout - stderr gets mixed in
- nix build warnings go to stderr even on success
- Symlinks happily accept multiline strings as targets (they just won't resolve)
** Process Insights
- When skill invocation fails, check: (1) symlink validity, (2) skill.md readability, (3) actual tool availability
- orch consensus is useful for getting opposing viewpoints on design decisions
** Architectural Insights
- Distinction between "system tools" and "project tools" helps decide where to install
- Skills documenting system tools don't need to bundle them - just assume they exist
- Cross-repo coordination is a reality; text notes in descriptions are pragmatic
* Context for Future Work
** Open Questions
- Should skills have a way to declare system tool dependencies?
- Would a "skill doctor" tool help diagnose skill loading issues?
** Next Steps
- Commit use-skills.sh fix
- dotfiles team implements dotfiles-3to (add orch to home-manager)
- Then skills-d87 can be closed
** Related Work
- Previous: [[file:2025-11-30-per-repo-skill-deployment-design.org][Per-Repo Skill Deployment Design]]
- Cross-repo: dotfiles-3to (Add orch CLI to home-manager packages)
* Raw Notes
- The failure cascade: dirty repo → nix warning → stderr merged → symlink corrupted → skill.md unreadable → agent doesn't know invocation → bare command fails → hunt for workaround
- User asked "how much do we want to mix nix and agentic dev tooling" - good architectural tension to keep in mind
- Gemini suggested the "proper" fix (build tool in skill), GPT suggested pragmatic fix (global install) - ended up with pragmatic
* Session Metrics
- Commits made: 0 (fix uncommitted)
- Files touched: 2 (bin/use-skills.sh, .beads/issues.jsonl)
- Lines added/removed: +3/-2
- Issues created: 2 (skills-fvx closed, skills-d87 open)
- Cross-repo issues: 1 (dotfiles-3to)