Files
agent-skills/README.md
T
naps62andClaude Opus 5 5e95a7337f feat(week-review): spawn weekly via systemd timer
Fridays 17:00 Europe/Lisbon, pinned in the unit because the machine
clock is UTC. Creates an Agent of Empires session in a fresh
week-review/<ISO week> worktree, sends it /week-review, notifies ntfy.

Interactive, not `claude -p`: the skill asks which carry-over issues to
take and what to apply, so an unattended run would stall or decide on
its own. link.sh links the units but does not enable them, since
enabling on every machine spawns one session per box for the same week.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SC9zwjErud3jfeYVEkf2Zd
2026-08-01 15:51:34 +00:00

131 lines
7.0 KiB
Markdown

# agent-skills
Single source of truth for custom agent skills + commands. Shared across **Claude Code** and **Codex**, every machine.
## Layout
```
skills/ # SKILL.md dirs — Claude Code AND Codex both read these (open Agent Skills standard)
commands/ # slash commands — Claude Code only (Codex ignores)
hooks/ # Claude Code hooks — see hooks/README.md, wiring is manual
claude-md/ # shared instruction fragments — imported by both entry files
entry/ # entry files: ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md
systemd/ # user timer that starts the weekly review — one machine only, see below
bin/link.sh # bootstrap symlinks for non-Nix machines
nix/home.nix # home-manager module for NixOS machines
flake.nix # exposes homeModules.default
```
Skills are portable: only `name`+`description` frontmatter is required by both tools; Claude-only fields (`user-invocable`, `args`) are ignored by Codex. Cross-skill refs use root-relative paths (`linear-common/COMMON.md`), so they resolve under `~/.claude/skills` and `~/.agents/skills` alike.
## Install
### Non-Nix machine (e.g. dev VM)
```sh
git clone https://git.naps.pt/yolo/agent-skills.git ~/tea/yolo/agent-skills
~/tea/yolo/agent-skills/bin/link.sh
```
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 still need one manual step: the `settings.json` snippet in `hooks/README.md`. Entry files are linked automatically — `entry/CLAUDE.md` and `entry/codex-AGENTS.md` hold the machine-local sections and `@import` the shared fragments, so both tools read the same rules with no copy and no drift.
### NixOS machine (home-manager)
```nix
# flake inputs
inputs.agent-skills.url = "git+https://git.naps.pt/yolo/agent-skills.git";
# home config imports
imports = [ inputs.agent-skills.homeModules.default ];
```
`recursive = true` links files individually, so machine-local skills can coexist in the same dir. `nixos-rebuild switch` to apply/update.
## Shared machine, many sessions
Several autonomous runs share one box. `skills/linear-common/scripts/gate.sh` is a machine-wide semaphore for heavy commands (full test suites, whole-project builds): bounded slots, memory + CPU cap via a systemd user scope, pinned build/test parallelism. Skills run scoped checks in the inner loop and put only the once-per-push full suite through the gate; exit 75 means it never ran and CI takes over. Policy lives in `linear-common/COMMON.md` under "Local verification budget".
```sh
~/.claude/skills/linear-common/scripts/gate.sh --status
AGENT_GATE_SLOTS=3 AGENT_GATE_MEM_MAX=4G ~/.claude/skills/linear-common/scripts/gate.sh -- cargo test
```
## Weekly review timer
`systemd/week-review.timer` fires Fridays at 17:00 Europe/Lisbon (the zone is pinned in the unit because the machine clock is UTC). It runs `bin/week-review-session.sh`, which creates an Agent of Empires session in a fresh `week-review/<ISO week>` worktree, sends it `/week-review`, and pushes an ntfy notification to the `homelab` topic.
The session is interactive, not `claude -p`. `/week-review` asks which carry-over issues to take and which changes to apply, so an unattended run would either stall or decide on its own. It stops at the first question and waits for `aoe attach`.
If a previous `week-review-*` session is still open the run skips and says so, so weeks do not pile up. `Persistent=true` means a Friday spent with the machine off fires on the next boot instead of being lost.
`bin/link.sh` symlinks the units into `~/.config/systemd/user/` but does not enable them — enabling on every machine would spawn one session per box for the same week. On the one machine that should run it:
```sh
systemctl --user daemon-reload
systemctl --user enable --now week-review.timer
systemctl --user list-timers week-review.timer
```
Needs `loginctl enable-linger` so the timer runs while logged out. Logs are in `~/.local/state/week-review/run.log`. The nix module deliberately omits the timer for the same one-machine reason.
## Adding a skill
Drop a new `skills/<name>/SKILL.md` (+ optional `scripts/`, `references/`, `assets/`). Commit. Non-Nix: re-run `bin/link.sh`. Nix: rebuild.
## Skills
| skill | what |
|-------|------|
| `work` | tracker issue → worktree → PR → hands off to `land` |
| `yolo` | quick ship; optional `land` handoff |
| `land` | drive an open PR to green + ready-to-merge; user clicks merge (canonical CI/review loop) |
| `blitz` | drive a whole milestone to done |
| `nightshift` | hours-long unattended build; architect delegating to subagents, backs off before the 5h limit |
| `linear-common` | shared config/setup/worktree conventions + local verification budget (dependency of work/yolo/blitz/nightshift) |
| `week-review` | review the past week's sessions for recurring friction; reads open issues here as carry-over |
| `crit`, `improve-codebase-architecture` | misc |
## Vendored skills
`humanizer` and `impeccable` are third-party and copied in, not written here.
Each carries an `UPSTREAM` file recording repo, pinned tag, subdirectory, and
license. Do not edit them — a local change becomes a merge conflict on every
update, and a rule that reads wrong is a bug to report upstream.
```sh
./bin/check-vendored.sh # reports any that have moved upstream
```
To update: re-clone at the newer tag, copy the `subdir` over the skill dir, and
bump `ref` + `vendored` in `UPSTREAM`.
| skill | upstream | license |
|-------|----------|---------|
| `humanizer` | [blader/humanizer](https://github.com/blader/humanizer) | MIT |
| `impeccable` | [pbakaus/impeccable](https://github.com/pbakaus/impeccable) | Apache-2.0 |
## Writing contract
One contract, `claude-md/writing.md`. Both entry files `@import` it, so Claude
Code and Codex read the same bytes on every machine.
The rule it encodes is **selection, not compression**: keep output short by
cutting whole ideas that don't change what the reader does next, then write
what survives as plain sentences. Not by dropping articles, abbreviating, or
writing fragments — that is shorter and worse. Anthropic's Fable 5 and Opus 5
prompting guides both say this explicitly.
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. 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
prohibitions, so the file is short and shows rather than forbids. Prose alone
drifts; the linters make it binding. Details in `hooks/README.md`.