Files
agent-skills/README.md
T
naps62 95e98a1e77 refactor: hourlog reports whole days, timer to 18:00
Half-days forced every result into a 4h bucket. Days with hours split by
share give the same answer at finer granularity and drop a concept.

Session minutes are now stated as a floor on real work, not a measure:
the day's length comes from the calendar and only the split between
projects comes from the sessions. Meetings and review leave no
transcript, so a thin day is still a full day.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 18:36:34 +00:00

160 lines
8.2 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 timers: weekly review + hour log — 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.
## Hour log timer
`systemd/hourlog.timer` fires Fridays at 18:00 Europe/Lisbon and runs
`bin/hourlog-session.sh`, which opens an Agent of Empires session on a scratch
dir, sends it `/hourlog --week this`, and pushes an ntfy notification.
Same shape as the weekly review and interactive for the same reason: the skill
proposes hours and stops for approval before writing anything to the timesheet.
An unattended run would be deciding a company record on your behalf. It skips
if a previous `hourlog-*` session is still open, and `Persistent=true` makes a
missed Friday fire on the next boot.
Enable on one machine only:
```sh
systemctl --user daemon-reload
systemctl --user enable --now hourlog.timer
```
Setup lives outside this repo, which is public:
- `~/.config/hourlog/projects.json` — path prefix to project mapping, copied
from `skills/hourlog/config.example.json`.
- `HOURLOG_API` and `HOURLOG_TOKEN` in `~/.env.claude` — API base URL and a
personal access token (`profile:read`, `schedule:read`, `schedule:write`).
No project, client, or host name belongs in a committed file here.
## 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 |
| `hourlog` | hours-per-project-per-day proposal from session activity, reconciled against the timesheet; submits only what you approve |
| `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`.