@gonxped31/agent-kit 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/bin/agk.mjs +348 -0
- package/lib/kit.mjs +125 -0
- package/lib/ui.mjs +127 -0
- package/package.json +28 -4
- package/template/.gitattributes +5 -0
- package/template/.githooks/pre-commit +8 -0
- package/template/BOOTSTRAP.md +103 -0
- package/template/CLAUDE.template.md +36 -0
- package/template/docs/workflow.md +15 -0
- package/template/dot-claude/settings.json +40 -0
- package/template/dot-claude/skills/agent-setup/SKILL.md +69 -0
- package/template/dot-claude/skills/git/SKILL.md +68 -0
- package/template/dot-claude/skills/todo/SKILL.md +74 -0
- package/template/dot-claude/skills/todo/scripts/todo.mjs +696 -0
- package/template/scripts/check.json +5 -0
- package/template/scripts/check.mjs +50 -0
- package/template/scripts/doctor.mjs +177 -0
- package/template/scripts/hooks/block-big-read.mjs +25 -0
- package/template/scripts/hooks/guard-commands.mjs +110 -0
- package/template/scripts/merge.mjs +82 -0
package/lib/ui.mjs
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// How agk prints: colors, symbols and a spinner, with plain fallbacks.
|
|
2
|
+
// - Color is on for a terminal, unless NO_COLOR is set or TERM is dumb. FORCE_COLOR=1 forces it
|
|
3
|
+
// on, FORCE_COLOR=0 off.
|
|
4
|
+
// - Symbols are Unicode where the terminal can show them, ASCII elsewhere. On Windows that's only
|
|
5
|
+
// in Windows Terminal, VS Code and the like: an old console lacks the glyphs, and a pipe may be
|
|
6
|
+
// decoded with an old code page.
|
|
7
|
+
// - The spinner moves only in a terminal. Elsewhere (a pipe, Claude Code) each step prints one
|
|
8
|
+
// line when it's done.
|
|
9
|
+
|
|
10
|
+
const env = process.env;
|
|
11
|
+
const tty = Boolean(process.stdout.isTTY) && env.TERM !== "dumb";
|
|
12
|
+
|
|
13
|
+
function colorOn(stream) {
|
|
14
|
+
if (env.FORCE_COLOR) return env.FORCE_COLOR !== "0";
|
|
15
|
+
return Boolean(stream.isTTY) && !env.NO_COLOR && env.TERM !== "dumb";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const modernWindowsTerminal = Boolean(
|
|
19
|
+
env.WT_SESSION || env.TERM_PROGRAM === "vscode" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm" || env.ConEmuTask,
|
|
20
|
+
);
|
|
21
|
+
const unicode = process.platform === "win32" ? tty && modernWindowsTerminal : env.TERM !== "linux";
|
|
22
|
+
|
|
23
|
+
const sym = unicode
|
|
24
|
+
? { ok: "✔", fail: "✖", warn: "▲", more: "…", frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] }
|
|
25
|
+
: { ok: "+", fail: "x", warn: "!", more: "...", frames: ["-", "\\", "|", "/"] };
|
|
26
|
+
|
|
27
|
+
function palette(on) {
|
|
28
|
+
const wrap = (open, close) => (s) => (on ? `\x1b[${open}m${s}\x1b[${close}m` : String(s));
|
|
29
|
+
return { bold: wrap(1, 22), dim: wrap(2, 22), red: wrap(31, 39), green: wrap(32, 39), yellow: wrap(33, 39), cyan: wrap(36, 39) };
|
|
30
|
+
}
|
|
31
|
+
/** Styles for stdout, and for stderr (failures). */
|
|
32
|
+
export const out = palette(colorOn(process.stdout));
|
|
33
|
+
const err = palette(colorOn(process.stderr));
|
|
34
|
+
|
|
35
|
+
const say = (text = "") => process.stdout.write(`${text}\n`);
|
|
36
|
+
export const blank = () => say();
|
|
37
|
+
/** A line indented under the header. */
|
|
38
|
+
export const line = (text) => say(` ${text}`);
|
|
39
|
+
export const ok = (text) => line(`${out.green(sym.ok)} ${text}`);
|
|
40
|
+
export const warn = (text) => line(`${out.yellow(sym.warn)} ${text}`);
|
|
41
|
+
/** The items of the line above, indented under it (the first 8 of them). */
|
|
42
|
+
export const details = (items) => {
|
|
43
|
+
for (const item of clip(items)) line(` ${item}`);
|
|
44
|
+
};
|
|
45
|
+
/** "1 file", "2 files". */
|
|
46
|
+
export const count = (n, noun) => `${n} ${noun}${n === 1 ? "" : "s"}`;
|
|
47
|
+
|
|
48
|
+
export function header(version, subtitle) {
|
|
49
|
+
blank();
|
|
50
|
+
line(`${out.bold(out.cyan("agk"))} ${out.dim(`v${version}`)}${subtitle ? ` ${subtitle}` : ""}`);
|
|
51
|
+
blank();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** A numbered list under a bold title. An item's later lines are dimmed, as its explanation. */
|
|
55
|
+
export function list(title, items) {
|
|
56
|
+
blank();
|
|
57
|
+
line(out.bold(title));
|
|
58
|
+
items.forEach((item, i) => {
|
|
59
|
+
const [first, ...rest] = item.split("\n");
|
|
60
|
+
line(` ${out.cyan(`${i + 1}.`)} ${first}`);
|
|
61
|
+
for (const r of rest) line(` ${out.dim(r)}`);
|
|
62
|
+
});
|
|
63
|
+
blank();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** What went wrong, for the user: a message, the lines that show it, and what to do next. */
|
|
67
|
+
export class Failure extends Error {
|
|
68
|
+
constructor(message, { details = [], hint = "" } = {}) {
|
|
69
|
+
super(message);
|
|
70
|
+
this.details = details;
|
|
71
|
+
this.hint = hint;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function showFailure(e) {
|
|
76
|
+
const lines = [` ${err.red(sym.fail)} ${err.bold(e.message)}`, ...e.details.map((d) => ` ${d}`)];
|
|
77
|
+
if (e.hint) lines.push(...e.hint.split("\n").map((h) => ` ${h}`));
|
|
78
|
+
process.stderr.write(`${lines.join("\n")}\n\n`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Up to `max` items, then "... and N more". */
|
|
82
|
+
export function clip(items, max = 8) {
|
|
83
|
+
return items.length <= max ? items : [...items.slice(0, max), `${sym.more} and ${items.length - max} more`];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let cursorHidden = false;
|
|
87
|
+
function showCursor() {
|
|
88
|
+
if (cursorHidden) process.stdout.write("\x1b[?25h");
|
|
89
|
+
cursorHidden = false;
|
|
90
|
+
}
|
|
91
|
+
process.on("exit", showCursor);
|
|
92
|
+
process.on("SIGINT", () => {
|
|
93
|
+
if (tty) process.stdout.write("\r\x1b[2K");
|
|
94
|
+
showCursor();
|
|
95
|
+
process.exit(130);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Runs `work` (async) behind a spinner, then marks the step done with the text `work` returns,
|
|
100
|
+
* or `text`. If `work` throws, the spinner is cleared and the error goes on.
|
|
101
|
+
*/
|
|
102
|
+
export async function step(text, work) {
|
|
103
|
+
if (!tty) {
|
|
104
|
+
ok((await work()) ?? text);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
let frame = 0;
|
|
108
|
+
const draw = () => process.stdout.write(`\r\x1b[2K ${out.cyan(sym.frames[frame++ % sym.frames.length])} ${text}${out.dim(sym.more)}`);
|
|
109
|
+
process.stdout.write("\x1b[?25l");
|
|
110
|
+
cursorHidden = true;
|
|
111
|
+
draw();
|
|
112
|
+
const timer = setInterval(draw, 80);
|
|
113
|
+
const stop = () => {
|
|
114
|
+
clearInterval(timer);
|
|
115
|
+
process.stdout.write("\r\x1b[2K");
|
|
116
|
+
showCursor();
|
|
117
|
+
};
|
|
118
|
+
let done;
|
|
119
|
+
try {
|
|
120
|
+
done = await work();
|
|
121
|
+
} catch (e) {
|
|
122
|
+
stop();
|
|
123
|
+
throw e;
|
|
124
|
+
}
|
|
125
|
+
stop();
|
|
126
|
+
ok(done ?? text);
|
|
127
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gonxped31/agent-kit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Sets up git repos for Claude Code, and keeps them up to date: a short CLAUDE.md, git and todo skills, hooks and checks.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"claude",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"agents",
|
|
10
|
+
"git-hooks",
|
|
11
|
+
"cli"
|
|
12
|
+
],
|
|
13
|
+
"bin": {
|
|
14
|
+
"agk": "bin/agk.mjs"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"bin/",
|
|
18
|
+
"lib/",
|
|
19
|
+
"template/"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "node --test test/kit.test.mjs"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Refuses commits on main (except a repo's very first commit), then runs the fast checks.
|
|
3
|
+
# Turned on once per clone: git config core.hooksPath .githooks
|
|
4
|
+
if git rev-parse -q --verify HEAD >/dev/null && [ "$(git symbolic-ref --short -q HEAD)" = "main" ]; then
|
|
5
|
+
echo "pre-commit: no commits on main. Work on a branch; main moves through node scripts/merge.mjs (git skill)." >&2
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
exec node scripts/check.mjs --fast
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Bootstrap: set up this repo for agents
|
|
2
|
+
|
|
3
|
+
agent-kit's `agk setup` copied this file and the setup files into the repo, and ran
|
|
4
|
+
`git init` if it wasn't one yet. Where the repo had one of those files already, it left
|
|
5
|
+
that file as it was and put the kit's version next to it, as `<file>.kit`. Follow these
|
|
6
|
+
steps once, in order. Step 6 deletes this file.
|
|
7
|
+
|
|
8
|
+
## 1. Look before asking
|
|
9
|
+
|
|
10
|
+
Find out on your own:
|
|
11
|
+
- Does it have commits (`git log --oneline -3`)? If so, its main branch must be called
|
|
12
|
+
`main` (the hook and `scripts/merge.mjs` assume it). If it's called something else,
|
|
13
|
+
ask the user before renaming it.
|
|
14
|
+
- Remotes (`git remote -v`). None is fine: the `git` skill handles both.
|
|
15
|
+
`agk setup --github` adds an empty GitHub repo as `origin`.
|
|
16
|
+
- The stack, from what's there: `package.json`, `pyproject.toml`, `go.mod`,
|
|
17
|
+
`Cargo.toml`, a README.
|
|
18
|
+
- Uncommitted work (`git status --short`) in `scripts/`, `docs/` or `.claude/` that
|
|
19
|
+
isn't the kit's (`.claude/agk.json` lists the kit's files): step 6 stages those
|
|
20
|
+
folders whole, so ask the user to commit it first.
|
|
21
|
+
- Git hooks of its own (`git config core.hooksPath`, `.husky/`): step 5 points git at
|
|
22
|
+
`.githooks/` instead, which turns them off. Ask the user; to keep both,
|
|
23
|
+
`.githooks/pre-commit` can run theirs.
|
|
24
|
+
|
|
25
|
+
## 2. Ask, in one message
|
|
26
|
+
|
|
27
|
+
Ask only what step 1 didn't answer. "Don't know yet" is a good answer: it becomes a
|
|
28
|
+
todo (step 4), never a guess.
|
|
29
|
+
|
|
30
|
+
1. The project's name, and what it is in 2-3 sentences.
|
|
31
|
+
2. The stack, if it's chosen: language, framework, how to test and lint.
|
|
32
|
+
3. Does `main` deploy anywhere when it changes?
|
|
33
|
+
4. What must never break?
|
|
34
|
+
5. What do you need to see before a change counts as done (tests, screenshots, a demo)?
|
|
35
|
+
6. Is there anything agents must never read or change (large data, secrets, generated files)?
|
|
36
|
+
|
|
37
|
+
## 3. Fill in the setup
|
|
38
|
+
|
|
39
|
+
- Each `<file>.kit` (`node scripts/doctor.mjs` lists them) is the kit's version of a
|
|
40
|
+
file the repo had. Merge it into that file: keep what the repo has, add what the
|
|
41
|
+
kit's brings (for `CLAUDE.md` its sections, for `.claude/settings.json` its hooks
|
|
42
|
+
and rules), and ask the user where they conflict. Then delete the `.kit` file.
|
|
43
|
+
- `CLAUDE.md`: replace every `{{...}}`. Write only the rules the user gave, one bullet
|
|
44
|
+
each. Keep it short: it's in context on every turn.
|
|
45
|
+
- If `main` deploys, add to "Working here": "`main` deploys to <where> on every merge."
|
|
46
|
+
- Never read or change → `deny` rules in `.claude/settings.json`, e.g.
|
|
47
|
+
`Read(./data/**)` and `Edit(./data/**)`.
|
|
48
|
+
- If the stack is known, do the "stack chosen" row of step 4 now instead of adding it.
|
|
49
|
+
|
|
50
|
+
## 4. Add a todo for everything deferred
|
|
51
|
+
|
|
52
|
+
`T` stands for `node .claude/skills/todo/scripts/todo.mjs`. One todo per deferred
|
|
53
|
+
part. Its detail holds the trigger, what to do and why, and must stand alone: this
|
|
54
|
+
file will be gone.
|
|
55
|
+
|
|
56
|
+
T add 'Stack chosen: checks, ignores, deny rules' -p 1 --tag setup
|
|
57
|
+
T detail <ID> 'Trigger: ... Do: ... Why: ...'
|
|
58
|
+
|
|
59
|
+
Single quotes, not double: the `todo` skill says why, and what to do about apostrophes.
|
|
60
|
+
|
|
61
|
+
| Trigger | Do |
|
|
62
|
+
| :--- | :--- |
|
|
63
|
+
| The stack is chosen | Add its checks to `scripts/check.json` (`{ "name": "test", "run": "npm test", "slow": true }`; `slow` steps skip the pre-commit hook but run in `check` and `merge`). Add a `.gitignore`, `deny` reads of dependency and build folders, and allow the check commands in `.claude/settings.json`. |
|
|
64
|
+
| The first screen exists (if there's a UI) | A skill that screenshots it at phone and desktop sizes and flags overflow and console errors. |
|
|
65
|
+
| A remote is added (or `agk setup --github` added one) | CI that runs `node scripts/check.mjs`. |
|
|
66
|
+
| A "don't know yet" from step 2 | Ask again then. |
|
|
67
|
+
|
|
68
|
+
Add any others the answers suggest, e.g. large data files coming: `deny` reads of
|
|
69
|
+
them, and a script that queries them with short output.
|
|
70
|
+
|
|
71
|
+
## 5. Turn on the hooks and check
|
|
72
|
+
|
|
73
|
+
git config core.hooksPath .githooks
|
|
74
|
+
node scripts/check.mjs
|
|
75
|
+
|
|
76
|
+
Fix whatever `check` reports (it runs `doctor`) until it prints OK.
|
|
77
|
+
|
|
78
|
+
## 6. Delete this file and commit
|
|
79
|
+
|
|
80
|
+
1. Delete `BOOTSTRAP.md`.
|
|
81
|
+
2. Stage by name, adding `todos` if step 4 added any and `.gitignore` if you wrote one:
|
|
82
|
+
|
|
83
|
+
git add CLAUDE.md .claude/settings.json .claude/skills .claude/agk.json .githooks scripts docs .gitattributes
|
|
84
|
+
git add --chmod=+x .githooks/pre-commit
|
|
85
|
+
|
|
86
|
+
Not all of `.claude`: Claude Code may keep the user's personal `settings.local.json`
|
|
87
|
+
there, and a machine's git ignore can miss it. `.claude/agk.json` records the kit's
|
|
88
|
+
files, for `agk update`. The `--chmod` line is for Windows, which doesn't record the
|
|
89
|
+
executable bit.
|
|
90
|
+
3. If the repo had no commits, commit on `main`: the hook allows a repo's first commit
|
|
91
|
+
there. Otherwise `git switch -c agent-setup`, commit, and merge with
|
|
92
|
+
`node scripts/merge.mjs` once the user approves.
|
|
93
|
+
Message: `Agent setup: <what was set up>`.
|
|
94
|
+
4. If there's a remote (`git remote`), push `main` once the user agrees:
|
|
95
|
+
`git push -u origin main`.
|
|
96
|
+
|
|
97
|
+
## 7. Report
|
|
98
|
+
|
|
99
|
+
In a few lines: what was set up, the todos added (`T list`), and two notes for the user:
|
|
100
|
+
- The git hooks are turned on per clone. After cloning this repo elsewhere, run
|
|
101
|
+
`git config core.hooksPath .githooks` (`doctor` says so when they're off).
|
|
102
|
+
- Personal habits that hold in every repo belong in `~/.claude/CLAUDE.md`, not here.
|
|
103
|
+
- `agk update` brings in the kit's later changes.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# {{NAME}}
|
|
2
|
+
|
|
3
|
+
{{WHAT IT IS, in 2-3 sentences}}
|
|
4
|
+
|
|
5
|
+
This file holds what must stay true on **every** change. Everything else loads on
|
|
6
|
+
demand: skills by their descriptions, a folder's rules from its own `CLAUDE.md`, and
|
|
7
|
+
the docs below.
|
|
8
|
+
|
|
9
|
+
| Need | Where |
|
|
10
|
+
| :--- | :--- |
|
|
11
|
+
| Session habits: one task per session, `/clear`, reading narrowly | `docs/workflow.md` |
|
|
12
|
+
|
|
13
|
+
## Always true
|
|
14
|
+
|
|
15
|
+
{{RULES: what must never break, one bullet each. Remove this section if there are none yet.}}
|
|
16
|
+
|
|
17
|
+
## Working here
|
|
18
|
+
|
|
19
|
+
- **Every task starts on its own branch.** `main` moves only through
|
|
20
|
+
`node scripts/merge.mjs`, after the user approves (`git` skill).
|
|
21
|
+
- **Deferred work is a todo with its trigger** ("when X happens, do Y"), never a note
|
|
22
|
+
in chat (`todo` skill).
|
|
23
|
+
- **Before finishing a task, check the todos**
|
|
24
|
+
(`node .claude/skills/todo/scripts/todo.mjs list --all`) for items the work
|
|
25
|
+
triggers: do them, or tell the user they're due.
|
|
26
|
+
- **New rules, skills, hooks or docs for agents** follow the `agent-setup` skill: a
|
|
27
|
+
check beats a written rule, and nothing is written twice.
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
| Command | What it does |
|
|
32
|
+
| :--- | :--- |
|
|
33
|
+
| `node scripts/check.mjs` | Every check in `scripts/check.json`: only what failed, then OK or FAIL (`--verbose` for full output) |
|
|
34
|
+
| `node scripts/doctor.mjs` | The agent setup: size limits, dead paths, hooks turned on |
|
|
35
|
+
|
|
36
|
+
**Before calling a change done:** `node scripts/check.mjs` passes.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Session workflow
|
|
2
|
+
|
|
3
|
+
Habits that keep sessions cheap and focused.
|
|
4
|
+
|
|
5
|
+
- **One task per session.** `todo next`, finish it, `todo done`, stop.
|
|
6
|
+
- **`/clear` between unrelated tasks.** Old context costs tokens on every turn.
|
|
7
|
+
- **`/compact` with a focus** when a long task must go on, e.g.
|
|
8
|
+
`/compact keep the failing test names and the files changed`.
|
|
9
|
+
- **`/context` and `/cost`** show what's using the window, and the money, before you
|
|
10
|
+
guess.
|
|
11
|
+
- **Change `CLAUDE.md` and MCP config between sessions**, not in the middle of one:
|
|
12
|
+
either change breaks prompt caching for the rest of the session.
|
|
13
|
+
- **Read narrowly.** Grep, or Read with `offset` and `limit`; a hook refuses
|
|
14
|
+
whole-file reads over 1500 lines.
|
|
15
|
+
- **Run `node scripts/check.mjs`** instead of reading raw test or lint output.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(node .claude/skills/todo/scripts/todo.mjs:*)",
|
|
5
|
+
"Bash(node scripts/check.mjs:*)",
|
|
6
|
+
"Bash(node scripts/doctor.mjs:*)"
|
|
7
|
+
],
|
|
8
|
+
"deny": [
|
|
9
|
+
"Read(./todos/**)",
|
|
10
|
+
"Edit(./todos/**)",
|
|
11
|
+
"Write(./todos/**)",
|
|
12
|
+
"Read(./todo-archive.md)",
|
|
13
|
+
"Edit(./todo-archive.md)",
|
|
14
|
+
"Write(./todo-archive.md)",
|
|
15
|
+
"Read(./*.log)"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"hooks": {
|
|
19
|
+
"PreToolUse": [
|
|
20
|
+
{
|
|
21
|
+
"matcher": "Read",
|
|
22
|
+
"hooks": [
|
|
23
|
+
{
|
|
24
|
+
"type": "command",
|
|
25
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/scripts/hooks/block-big-read.mjs\""
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"matcher": "Bash|PowerShell",
|
|
31
|
+
"hooks": [
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/scripts/hooks/guard-commands.mjs\""
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-setup
|
|
3
|
+
description: Where agent knowledge goes (CLAUDE.md, skills, hooks, scripts, docs, todos) and its size limits. Use when adding or changing any of them, or after a repeated mistake.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent setup: where knowledge goes
|
|
7
|
+
|
|
8
|
+
## 1. Pick the cheapest place that works
|
|
9
|
+
|
|
10
|
+
| The knowledge is... | Put it in | Costs |
|
|
11
|
+
| :--- | :--- | :--- |
|
|
12
|
+
| A rule a machine can check | A lint rule, a git hook (`.githooks/`), a permission in `.claude/settings.json`, or a Claude hook in `scripts/hooks/` | Nothing |
|
|
13
|
+
| Mechanical work done often | A script with short output: one line per problem, then OK or FAIL | Its output |
|
|
14
|
+
| True for every change | The root `CLAUDE.md` | Every turn |
|
|
15
|
+
| True for one folder | That folder's `CLAUDE.md` | When the agent works there |
|
|
16
|
+
| A procedure for one kind of task | A skill | Its description every session; the body when used |
|
|
17
|
+
| Long reference (specs, formulas, data formats) | `docs/`, listed in the root `CLAUDE.md`'s table | When read |
|
|
18
|
+
| Work for later, or for when something happens | A todo with its trigger (`todo` skill) | Nothing |
|
|
19
|
+
| Why a change was made | The commit message | Nothing |
|
|
20
|
+
| Your own habits, true in every repo | `~/.claude/CLAUDE.md` | Every turn, in every repo |
|
|
21
|
+
|
|
22
|
+
Prefer the top of the table. A written rule is a request; a check is a guarantee. When
|
|
23
|
+
a rule becomes a check, keep at most one line saying why.
|
|
24
|
+
|
|
25
|
+
## 2. When to add something
|
|
26
|
+
|
|
27
|
+
- The same mistake twice: a rule. If a machine can check it: a check instead.
|
|
28
|
+
- The same procedure explained in two sessions: a skill.
|
|
29
|
+
- A command run often, with long output: a wrapper script.
|
|
30
|
+
- Not before. A guardrail for something that hasn't happened yet is a todo with a
|
|
31
|
+
trigger.
|
|
32
|
+
|
|
33
|
+
## 3. Size limits
|
|
34
|
+
|
|
35
|
+
`node scripts/doctor.mjs` enforces them (`check` runs it).
|
|
36
|
+
|
|
37
|
+
| What | Limit |
|
|
38
|
+
| :--- | :--- |
|
|
39
|
+
| The root `CLAUDE.md` | 800 words |
|
|
40
|
+
| A folder's `CLAUDE.md` | 400 words |
|
|
41
|
+
| A skill's description | 30 words, saying when to use it ("Use when ...") |
|
|
42
|
+
| A `SKILL.md` | 100 lines; longer reference goes in files next to it |
|
|
43
|
+
|
|
44
|
+
Change a limit in `scripts/doctor.mjs` only with the reason in the commit.
|
|
45
|
+
|
|
46
|
+
## 4. Adding a skill
|
|
47
|
+
|
|
48
|
+
1. Look in `.claude/skills/` first: extend a skill rather than add a near-duplicate.
|
|
49
|
+
2. Write `.claude/skills/<name>/SKILL.md` with frontmatter `name` (the folder's name)
|
|
50
|
+
and `description` (what it covers, then "Use when ..."). The body is procedure:
|
|
51
|
+
steps, commands, gotchas. No history, and nothing `CLAUDE.md` already says.
|
|
52
|
+
3. A script goes in the skill's `scripts/` folder. Allow it in `.claude/settings.json`
|
|
53
|
+
(`Bash(node .claude/skills/<name>/scripts/<file>:*)`), merging into the list.
|
|
54
|
+
4. Don't list skills in `CLAUDE.md`: their descriptions are already in context.
|
|
55
|
+
5. Run `node scripts/doctor.mjs`.
|
|
56
|
+
|
|
57
|
+
## 5. Never
|
|
58
|
+
|
|
59
|
+
- `@`-imports in `CLAUDE.md`: they load the whole file on every turn. Name the path in
|
|
60
|
+
backticks instead, so it's read only when needed.
|
|
61
|
+
- The same fact in two places. Point to its source (the code, a doc) instead of
|
|
62
|
+
copying it: copies go stale.
|
|
63
|
+
|
|
64
|
+
## 6. The kit's files
|
|
65
|
+
|
|
66
|
+
agent-kit wrote the files listed in `.claude/agk.json`; change them as the repo needs.
|
|
67
|
+
`agk update` brings in the kit's later changes. Where the repo changed a file, it puts
|
|
68
|
+
the kit's version next to it as `<file>.kit`: merge what's new into the file, keeping
|
|
69
|
+
the repo's changes, then delete the `.kit` file (`doctor` reports it until then).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git
|
|
3
|
+
description: Branching, committing, rebasing and merging. Use when starting a task, committing, or merging into main. One branch per task, files staged by name, main only with approval.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Git: a branch per task, main only with approval
|
|
7
|
+
|
|
8
|
+
`main` moves only through `node scripts/merge.mjs`, after the user approves. The
|
|
9
|
+
pre-commit hook refuses commits on `main` and runs `node scripts/check.mjs --fast`. A
|
|
10
|
+
Claude hook refuses `--no-verify` and bulk staging, and asks before merges, pushes and
|
|
11
|
+
commands that discard work.
|
|
12
|
+
|
|
13
|
+
## 1. Start every task on a new branch
|
|
14
|
+
|
|
15
|
+
- `git switch -c <branch> main`. Names are short kebab-case `<area>-<topic>`, with the
|
|
16
|
+
todo ID first when there is one (`t-k7q3-route-cost`).
|
|
17
|
+
- Follow-ups to the same task stay on its branch.
|
|
18
|
+
- If the checkout is on a branch that isn't yours, or has changes you didn't make,
|
|
19
|
+
don't switch it. Work in a worktree in a sibling folder:
|
|
20
|
+
`git worktree add ../<repo>-<branch> -b <branch> main`.
|
|
21
|
+
- A worktree has no installed dependencies: install them there. Never link them
|
|
22
|
+
from the main checkout: removing the worktree deletes what the link points to.
|
|
23
|
+
|
|
24
|
+
## 2. Commit
|
|
25
|
+
|
|
26
|
+
1. `git branch --show-current` must print your branch. If it doesn't, someone switched
|
|
27
|
+
the checkout: stop and tell the user.
|
|
28
|
+
2. `git status --short`, then stage what you changed **by name**. Leave out files you
|
|
29
|
+
didn't touch, and mention them.
|
|
30
|
+
3. One logical change per commit. Todo changes go in the same commit as the work.
|
|
31
|
+
4. If the hook fails, fix what it reports. Never get around it.
|
|
32
|
+
|
|
33
|
+
Message:
|
|
34
|
+
|
|
35
|
+
<Area>: <what is now true, or what changed> (T-xxxx)
|
|
36
|
+
|
|
37
|
+
Why it was needed, and what a reader can't see in the diff.
|
|
38
|
+
Say what wasn't verified, when that matters.
|
|
39
|
+
|
|
40
|
+
## 3. Stay on top of main
|
|
41
|
+
|
|
42
|
+
After each commit: `git rebase main`. On a conflict, resolve it if both sides' intent
|
|
43
|
+
is clear, rerun `node scripts/check.mjs`, then `git rebase --continue`. Otherwise
|
|
44
|
+
`git rebase --abort` and ask.
|
|
45
|
+
|
|
46
|
+
## 4. Merge into main: only with approval
|
|
47
|
+
|
|
48
|
+
1. The branch is rebased onto `main`, and `node scripts/check.mjs` passes.
|
|
49
|
+
2. Ask the user, stating the branch, its commits (`git log --oneline main..HEAD`) and
|
|
50
|
+
the checks run.
|
|
51
|
+
3. Once approved, from the branch's checkout: `node scripts/merge.mjs <branch>`. It
|
|
52
|
+
refuses unless the tree is clean, the branch is on top of `main` and the checks
|
|
53
|
+
pass. Then it fast-forwards `main` and deletes the branch. From a worktree, it
|
|
54
|
+
prints how to remove the worktree instead.
|
|
55
|
+
|
|
56
|
+
## With a remote
|
|
57
|
+
|
|
58
|
+
Only if `git remote` prints one:
|
|
59
|
+
- Branch from and rebase onto `origin/main`, after a `git fetch`.
|
|
60
|
+
- Push your branch after each rebase: `git push -u origin <branch>` the first time,
|
|
61
|
+
then `git push --force-with-lease` (your branch only, never `main`).
|
|
62
|
+
- After a merge, push `main` once the user agrees: `git push origin main`.
|
|
63
|
+
|
|
64
|
+
## Never, without asking
|
|
65
|
+
|
|
66
|
+
- `reset --hard`, `clean`, `checkout -- <file>`, `restore <file>`, `stash drop`,
|
|
67
|
+
`branch -D`. Undo committed work with `git revert`.
|
|
68
|
+
- Rewrite `main` or force-push it.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: todo
|
|
3
|
+
description: The work queue, kept by a script. Use when working on, adding or reviewing todos, on "next todo", or when work must wait for a trigger.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Todos: the queue, through its script
|
|
7
|
+
|
|
8
|
+
`todos/` and `todo-archive.md` are the script's data. **Never read or edit them
|
|
9
|
+
directly** (the settings deny it): go through the script, so the queue costs almost no
|
|
10
|
+
tokens.
|
|
11
|
+
|
|
12
|
+
## 1. Commands
|
|
13
|
+
|
|
14
|
+
`T` stands for `node .claude/skills/todo/scripts/todo.mjs`, run from the repo root.
|
|
15
|
+
|
|
16
|
+
| Command | What it does |
|
|
17
|
+
| :--- | :--- |
|
|
18
|
+
| `T next` | The best eligible item as its raw line, or `none` |
|
|
19
|
+
| `T list [-p N] [--tag X] [--all]` | Eligible items; `--all` adds blocked ones, marked `*` |
|
|
20
|
+
| `T show T-XXX` | The item's line, then its detail text if any |
|
|
21
|
+
| `T add "text" [-p 1-3] [--dep T-A,T-B] [--size S\|M\|L] [--tag a,b]` | Creates an item; prints only the new ID |
|
|
22
|
+
| `T set T-XXX [-p 1-3] [--dep T-A,T-B\|-] [--size S\|M\|L\|-]` | Changes priority, deps or size |
|
|
23
|
+
| `T edit T-XXX "new text"` | Replaces the one-line description |
|
|
24
|
+
| `T tag T-XXX a,b` | Replaces the tags (`-` clears them) |
|
|
25
|
+
| `T detail T-XXX 'text'` or `--file path` (`-`: stdin) [`--append`] | Sets the detail text (replaces it unless `--append`) |
|
|
26
|
+
| `T done T-XXX` | Archives it; prints `unblocked: ...` for items it freed |
|
|
27
|
+
| `T rm T-XXX` | Removes it without archiving (obsolete) |
|
|
28
|
+
| `T stats`, `T graph`, `T html [--out file]` | Counts, dependency tree, an HTML board |
|
|
29
|
+
|
|
30
|
+
Line format: `ID | P | dep | size | tags | description`.
|
|
31
|
+
|
|
32
|
+
- **Deps**: one ID, several comma-separated, or `-`. An item is eligible once none of
|
|
33
|
+
its deps are still open. Cycles are refused.
|
|
34
|
+
- **IDs** are random, `T-` plus 4 characters (`T-k7q3`), never reused. Typing them is
|
|
35
|
+
case-insensitive.
|
|
36
|
+
- **Tags**: lowercase, comma-separated, `-` for none. Use the project's own areas
|
|
37
|
+
(`setup`, `ui`, `data`...).
|
|
38
|
+
- **Detail text** is deleted with the item by `done` and `rm`; the archive keeps only
|
|
39
|
+
the line. Put anything worth keeping in the code or the commit.
|
|
40
|
+
- `next` picks the lowest P, then the oldest item.
|
|
41
|
+
- Output is plain when piped, which is how Claude gets it: don't pass color flags.
|
|
42
|
+
- **Quote text with single quotes.** Inside double quotes, Bash runs text between
|
|
43
|
+
backticks as a command, and PowerShell drops the backticks. For text with an
|
|
44
|
+
apostrophe, send it on stdin: `T detail <ID> --file - <<'EOF'`, the text, then `EOF`
|
|
45
|
+
(Bash); in PowerShell, write each apostrophe twice inside single quotes.
|
|
46
|
+
|
|
47
|
+
## 2. Working a todo
|
|
48
|
+
|
|
49
|
+
1. `T next`, then `T show <id>` if it may have detail text.
|
|
50
|
+
2. If its size is L, or the description is vague, outline a plan and confirm it with
|
|
51
|
+
the user before editing.
|
|
52
|
+
3. Do the work, focused on that one todo.
|
|
53
|
+
4. `T done <id>`.
|
|
54
|
+
5. `T add ...` for any follow-up work found, instead of growing the task.
|
|
55
|
+
6. Report in 1-2 sentences, then stop. Don't start the next todo unless the user asked
|
|
56
|
+
for a batch.
|
|
57
|
+
|
|
58
|
+
## 3. Deferred work
|
|
59
|
+
|
|
60
|
+
Work that waits on something ("when X ships, do Y") is a todo, not a note in chat:
|
|
61
|
+
|
|
62
|
+
T add '<what>' --tag <area>
|
|
63
|
+
T detail <ID> 'Trigger: <X>. Do: <Y>. Why: <reason>.'
|
|
64
|
+
|
|
65
|
+
The detail must stand alone: whoever picks it up won't have this conversation. Before
|
|
66
|
+
finishing any task, `T list --all` and look for todos the work just triggered.
|
|
67
|
+
|
|
68
|
+
## 4. Parallel worktrees
|
|
69
|
+
|
|
70
|
+
The queue is built for several agents in their own worktrees. Each todo is its own file
|
|
71
|
+
and IDs need no shared counter, so branches that touch different todos merge cleanly.
|
|
72
|
+
`todo-archive.md` only grows, and `.gitattributes` merges it with `merge=union`, so
|
|
73
|
+
both branches' `done` lines stay. The same todo changed on both sides is a real
|
|
74
|
+
conflict: keep the right version by hand.
|