refactor: both tools import the same fragments; scope code comments by path
Codex reads ~/.codex/AGENTS.md, not ~/.agents/AGENTS.md, so the file generated there last commit was inert. Both tools support @path imports, which removes the generate-and-drift step entirely. code-comments.md moves to ~/.claude/rules/ with paths frontmatter, so its 24 lines load only when a source file is read.
This commit is contained in:
@@ -27,7 +27,7 @@ git clone https://git.naps.pt/yolo/agent-skills.git ~/tea/yolo/agent-skills
|
||||
|
||||
Symlinks each skill into `~/.claude/skills/` and `~/.agents/skills/`, commands into `~/.claude/commands/`, hooks into `~/.claude/hooks/`, `claude-md/` fragments into `~/.claude/`. Idempotent; any pre-existing real dir is moved to `~/.agent-skills-backup/` (outside the discovery path, so it isn't picked up as a duplicate skill). Re-run after adding a skill.
|
||||
|
||||
Hooks and fragments need one manual step each: the `settings.json` snippet in `hooks/README.md`, and `@writing.md` + `@operating.md` import lines in your `~/.claude/CLAUDE.md`. Codex needs no step — `link.sh` generates `~/.agents/AGENTS.md` from both fragments (re-run it after editing them).
|
||||
Hooks and fragments need one manual step each: the `settings.json` snippet in `hooks/README.md`, and `@writing.md` + `@operating.md` import lines in your `~/.claude/CLAUDE.md` and `~/.codex/AGENTS.md`. Both tools support `@path`, so they import the same fragments — no copy, no drift.
|
||||
|
||||
### NixOS machine (home-manager)
|
||||
|
||||
@@ -83,7 +83,7 @@ Two enforcers in `hooks/`:
|
||||
| enforcer | scope |
|
||||
|----------|-------|
|
||||
| `comms-lint.py` | GitHub issues/PRs/review comments — 150 words (hard cap 300), evidence in `<details>`, no reviewer-addressing opener, plain diction |
|
||||
| `comment-lint.py` | code comments — 1-3 lines, volume and purpose, not wording |
|
||||
| `comment-lint.py` | code comments — 1-3 lines, volume and purpose, not wording. The rule is path-scoped (`~/.claude/rules/`), so it loads only when Claude reads a source file. |
|
||||
|
||||
Written in the voice it asks for, and leads with a worked example of each.
|
||||
Prompt style leaks into output style, and examples steer harder than
|
||||
|
||||
+13
-13
@@ -13,7 +13,8 @@ CODEX_SKILLS="$HOME/.agents/skills"
|
||||
CLAUDE_CMDS="$HOME/.claude/commands" # commands are Claude-only; Codex ignores
|
||||
CLAUDE_HOOKS="$HOME/.claude/hooks" # hooks are Claude-only
|
||||
CLAUDE_HOME="$HOME/.claude" # CLAUDE.md fragments, pulled in via @name.md
|
||||
AGENTS_HOME="$HOME/.agents" # Codex global config root
|
||||
CLAUDE_RULES="$HOME/.claude/rules" # path-scoped rules
|
||||
CODEX_HOME="$HOME/.codex" # Codex global config root
|
||||
|
||||
# Per-FILE links, never a whole-dir link: ~/.claude/hooks and ~/.claude itself hold
|
||||
# machine-local files this repo does not own, and a dir symlink would hide them.
|
||||
@@ -33,7 +34,7 @@ link() { # link <src> <dst>
|
||||
echo "linked $dst -> $src"
|
||||
}
|
||||
|
||||
mkdir -p "$CLAUDE_SKILLS" "$CODEX_SKILLS" "$CLAUDE_CMDS" "$CLAUDE_HOOKS" "$AGENTS_HOME"
|
||||
mkdir -p "$CLAUDE_SKILLS" "$CODEX_SKILLS" "$CLAUDE_CMDS" "$CLAUDE_HOOKS" "$CLAUDE_RULES" "$CODEX_HOME"
|
||||
|
||||
for d in "$REPO"/skills/*/; do
|
||||
name="$(basename "$d")"
|
||||
@@ -51,22 +52,21 @@ for f in "$REPO"/hooks/*.py "$REPO"/hooks/*.sh; do
|
||||
link "$f" "$CLAUDE_HOOKS/$(basename "$f")"
|
||||
done
|
||||
|
||||
# code-comments.md is path-scoped and belongs in rules/, not here — linking it
|
||||
# into ~/.claude/ as well would load it unconditionally and defeat the scoping.
|
||||
for f in "$REPO"/claude-md/*.md; do
|
||||
[ -e "$f" ] || continue
|
||||
[ "$(basename "$f")" = "code-comments.md" ] && continue
|
||||
link "$f" "$CLAUDE_HOME/$(basename "$f")"
|
||||
done
|
||||
|
||||
# Codex reads ~/.agents/AGENTS.md and has no @import, so the fragments are
|
||||
# concatenated into a real file. Re-run this script after editing claude-md/.
|
||||
rm -f "$AGENTS_HOME/AGENTS.md"
|
||||
{
|
||||
echo "<!-- generated by agent-skills/bin/link.sh from claude-md/ — do not edit -->"
|
||||
echo
|
||||
cat "$REPO/claude-md/operating.md"
|
||||
echo
|
||||
cat "$REPO/claude-md/writing.md"
|
||||
} > "$AGENTS_HOME/AGENTS.md"
|
||||
echo "generated $AGENTS_HOME/AGENTS.md"
|
||||
# Path-scoped rules load only when Claude reads a matching file.
|
||||
link "$REPO/claude-md/code-comments.md" "$CLAUDE_RULES/code-comments.md"
|
||||
rm -f "$CLAUDE_HOME/code-comments.md" "$HOME/.agents/AGENTS.md"
|
||||
|
||||
# Codex reads ~/.codex/AGENTS.md and supports @path imports, same as CLAUDE.md,
|
||||
# so both tools import the identical fragments — no copy, no drift.
|
||||
mkdir -p "$CODEX_HOME"
|
||||
|
||||
echo "done."
|
||||
echo "hooks still need wiring in ~/.claude/settings.json — see hooks/README.md"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
paths:
|
||||
- "**/*.{ts,tsx,js,jsx,mjs,cjs,py,rs,go,sol,sh,bash,zsh,c,h,cc,cpp,hpp,java,kt,rb,lua,zig,nix,swift,php,cs,ex}"
|
||||
---
|
||||
|
||||
## Code comments
|
||||
|
||||
Budget: 1-3 lines. Write one only when an agent with the repo and thirty
|
||||
seconds of grep would still get it wrong. That means one of:
|
||||
|
||||
- a landmine no test catches
|
||||
- a fact not in the repo (deployed bytecode, chain quirk, library bug)
|
||||
- a unit or epoch the type cannot carry (wei, ms, 18-dp)
|
||||
- a MUST or MUST NOT a caller can break
|
||||
|
||||
Good:
|
||||
|
||||
> `// MUST read lastGoodPrice before fetchPrice — same eth_call state.`
|
||||
|
||||
Everything else: delete. Design rationale and rejected alternatives go in
|
||||
`docs/`; leave a path. History is in git. No emphasis; ALL-CAPS only for
|
||||
MUST / NEVER.
|
||||
|
||||
Deleting a comment is cheap and reversible. When unsure, delete.
|
||||
@@ -81,26 +81,6 @@ Commits: Conventional Commits, subject ≤50 chars, body only when the
|
||||
"why" is not obvious. Review comments: one line per finding — location,
|
||||
problem, fix.
|
||||
|
||||
### Code comments
|
||||
|
||||
Budget: 1-3 lines. Write one only when an agent with the repo and thirty
|
||||
seconds of grep would still get it wrong. That means one of:
|
||||
|
||||
- a landmine no test catches
|
||||
- a fact not in the repo (deployed bytecode, chain quirk, library bug)
|
||||
- a unit or epoch the type cannot carry (wei, ms, 18-dp)
|
||||
- a MUST or MUST NOT a caller can break
|
||||
|
||||
Good:
|
||||
|
||||
> `// MUST read lastGoodPrice before fetchPrice — same eth_call state.`
|
||||
|
||||
Everything else: delete. Design rationale and rejected alternatives go in
|
||||
`docs/`; leave a path. History is in git. No emphasis; ALL-CAPS only for
|
||||
MUST / NEVER.
|
||||
|
||||
Deleting a comment is cheap and reversible. When unsure, delete.
|
||||
|
||||
### Where this does not apply
|
||||
|
||||
Security warnings, irreversible-action confirmations, and legal or
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"""PostToolUse nudge for code comments: Write / Edit / MultiEdit.
|
||||
|
||||
Lints ONLY the newly-added text against the "Code comments" contract in
|
||||
~/.claude/writing.md, so legacy files are not re-flagged on every touch.
|
||||
~/.claude/rules/code-comments.md, so legacy files are not re-flagged on every touch.
|
||||
|
||||
Exit 0 = silent. Exit 2 = stderr goes back to Claude as feedback; the edit is
|
||||
already applied, so this is a revise-it nudge, not a block.
|
||||
@@ -157,7 +157,7 @@ def main():
|
||||
name = os.path.basename(path)
|
||||
|
||||
if problems:
|
||||
lines = [f"Comment contract (~/.claude/writing.md) — {name}:", ""]
|
||||
lines = [f"Comment contract (~/.claude/rules/code-comments.md) — {name}:", ""]
|
||||
lines += [f" - {p}" for p in problems + notes]
|
||||
lines += ["", "Trim what you just wrote, or say why it stays."]
|
||||
print("\n".join(lines), file=sys.stderr)
|
||||
|
||||
+3
-5
@@ -21,11 +21,9 @@
|
||||
".claude/writing.md".source = "${agent-skills}/claude-md/writing.md";
|
||||
".claude/operating.md".source = "${agent-skills}/claude-md/operating.md";
|
||||
|
||||
# Codex has no @import, so the fragments are concatenated into one file.
|
||||
".agents/AGENTS.md".text = builtins.concatStringsSep "\n" [
|
||||
(builtins.readFile "${agent-skills}/claude-md/operating.md")
|
||||
(builtins.readFile "${agent-skills}/claude-md/writing.md")
|
||||
];
|
||||
# Path-scoped: loads only when Claude reads a matching source file.
|
||||
".claude/rules/code-comments.md".source = "${agent-skills}/claude-md/code-comments.md";
|
||||
|
||||
};
|
||||
}
|
||||
# Hook wiring lives in ~/.claude/settings.json, which this module does not own.
|
||||
|
||||
Reference in New Issue
Block a user