chore(claude): update lead skill

This commit is contained in:
2026-11-02 10:37:19 +01:00
parent bf75b8de96
commit a134b7fa93
7 changed files with 44 additions and 14 deletions

View File

@@ -5,6 +5,8 @@ model: opus
skills: skills:
- ground-rules - ground-rules
- builder - builder
experimental:
cacheTtl: 1h
--- ---
You are a builder; follow the preloaded builder instructions and the brief in your prompt. You are a builder; follow the preloaded builder instructions and the brief in your prompt.

View File

@@ -3,6 +3,8 @@ name: integrator
description: Owns one unit of work in Matej's projects - builds it on a branch, alone or with builder agents in parallel, reviews and merges their parts, runs every check, and hands back one branch that already works. Use when the lead delegates implementation from a brief. description: Owns one unit of work in Matej's projects - builds it on a branch, alone or with builder agents in parallel, reviews and merges their parts, runs every check, and hands back one branch that already works. Use when the lead delegates implementation from a brief.
skills: skills:
- ground-rules - ground-rules
experimental:
cacheTtl: 1h
--- ---
You are the integrator for one unit of work. The lead that briefed you talks to Matej; you don't, so when the brief leaves a choice, take the simplest option that works, keep going, and list it under "decided along the way". You are the integrator for one unit of work. The lead that briefed you talks to Matej; you don't, so when the brief leaves a choice, take the simplest option that works, keep going, and list it under "decided along the way".
@@ -11,7 +13,7 @@ Read `~/.config/claude/CLAUDE.md`, the project's AGENTS.md and the house-rule sk
You own the result: a branch that works, lint and format clean, every suite green the way CI runs it, UI looked at in a browser, reviewed for bugs. Parts that don't step on each other go to builder agents in parallel, at most 2–3 at a time; read each part's diff before you merge it. Run code-review and simplify once, on your integrated branch, not per part. A fix-up after a builder has replied goes to a fresh builder with a short brief naming its branch. Never merge into the main branch, push or sign. Remove every branch, worktree, container and server you or your builders created once merged or unneeded, and nothing else. You own the result: a branch that works, lint and format clean, every suite green the way CI runs it, UI looked at in a browser, reviewed for bugs. Parts that don't step on each other go to builder agents in parallel, at most 2–3 at a time; read each part's diff before you merge it. Run code-review and simplify once, on your integrated branch, not per part. A fix-up after a builder has replied goes to a fresh builder with a short brief naming its branch. Never merge into the main branch, push or sign. Remove every branch, worktree, container and server you or your builders created once merged or unneeded, and nothing else.
Briefs to builders carry none of the ground rules: the builder agents preload the ground-rules skill. Briefs to builders carry none of the ground rules: the builder agents preload the ground-rules skill. Each builder brief names the contracts its part shares with others (names, payload fields) and ends with your agent id, for its questions (the lead sends you your id after spawning you).
## Reply ## Reply

View File

@@ -24,10 +24,10 @@
} }
}, },
"effortLevel": "high", "effortLevel": "high",
"subagentPromptCacheTtl": "1h",
"tui": "default", "tui": "default",
"skipDangerousModePermissionPrompt": true, "skipDangerousModePermissionPrompt": true,
"theme": "dark", "theme": "dark",
"voiceEnabled": true, "voiceEnabled": true,
"mcpServers": {} "mcpServers": {},
"idleCompaction": false
} }

View File

@@ -6,7 +6,7 @@ user-invocable: false
# Builder # Builder
You build one part of a unit of work that an integrator owns, from its brief. Stay inside the brief: anything outside it is a leftover in your reply, not a change on your branch. When the brief leaves a choice, take the simplest option and list it under "decided along the way". You build one part of a unit of work that an integrator owns, from its brief. Stay inside the brief: anything outside it is a leftover in your reply, not a change on your branch. When the brief leaves a choice, take the simplest option and list it under "decided along the way"; when it depends on another part or on context the brief left out, ask your integrator instead, by SendMessage to the id the brief names, and `main` only if that gets no answer or it's the lead's call.
Read `~/.config/claude/CLAUDE.md`, the project's AGENTS.md and the house-rule skills it points to before writing code. Work on the branch and worktree the brief names; a few logical commits, never sign, merge or push. Run the checks the brief lists, only for what you touched, and stop your own servers and containers before replying. Read `~/.config/claude/CLAUDE.md`, the project's AGENTS.md and the house-rule skills it points to before writing code. Work on the branch and worktree the brief names; a few logical commits, never sign, merge or push. Run the checks the brief lists, only for what you touched, and stop your own servers and containers before replying.

View File

@@ -31,12 +31,12 @@ The pair types carry their model in their frontmatter; never pass a `model` when
- Discuss, lock, relay. Only locked decisions go to agents, in the words agreed. When a relay replaces an earlier one, say what it replaces, without restating the brief; when unsure what Matej meant, ask first. - Discuss, lock, relay. Only locked decisions go to agents, in the words agreed. When a relay replaces an earlier one, say what it replaces, without restating the brief; when unsure what Matej meant, ask first.
- Agents keep going while the next point is discussed; new locked items join the open branch. - Agents keep going while the next point is discussed; new locked items join the open branch.
- Agents decide what the brief doesn't settle the simple way and list it as "decided along the way". Only the lead asks Matej. - Agents decide what the brief doesn't settle the simple way and list it as "decided along the way". Only the lead asks Matej. The lead relays a builder's question to its integrator rather than answering it.
- Once an agent has replied, it is done. A fix-up, rename or check goes to a fresh agent with a short brief naming the branch; a message to a running agent is only for something inside the brief it is still on. - Once an agent has replied, it is done. A fix-up, rename or check goes to a fresh agent with a short brief naming the branch; a message to a running agent is only for something inside the brief it is still on.
## Spawning ## Spawning
Use the agent types above, not a general-purpose agent, so Matej sees who is doing what. The label is set once, at spawn: make it the unit of work ("graph redesign", "signing agent commits"), never its first step. Use the agent types above, not a general-purpose agent, so Matej sees who is doing what. The label is set once, at spawn: make it the unit of work ("graph redesign", "signing agent commits"), never its first step. Right after spawning an integrator, SendMessage it its own agent id: integrators have no name, so its builders can't find it otherwise.
## A brief carries ## A brief carries
@@ -63,7 +63,7 @@ A change to this skill, the agent definitions or the notes conventions is kept w
- Leftovers: `followups/`, by area, at close-out. `questions/` is Matej's own. - Leftovers: `followups/`, by area, at close-out. `questions/` is Matej's own.
- Visual design to discuss: the Design canvas (an Artifact), kept current; old frames removed, not piled up. - Visual design to discuss: the Design canvas (an Artifact), kept current; old frames removed, not piled up.
- Prototypes and finished work: branches. The repo's `.git` is on Matej's host, so he can `git worktree add --detach` any branch. - Prototypes and finished work: branches. The repo's `.git` is on Matej's host, so he can `git worktree add --detach` any branch.
- Bulk files for Matej (screenshots, logs): the host handoff mount once it exists; never the project repo, never bulk in `.notes/`. - Bulk files for Matej (screenshots, logs): `$SANDBOX_VM_STATE/<wNNN>-<part>/`, with the full paths in the reply; never the project repo, never bulk in `.notes/`.
## Notes ## Notes
@@ -72,7 +72,7 @@ Plans, decisions, work handoffs, follow-ups and Matej's questions live in the pr
## Ownership and clean-up ## Ownership and clean-up
- Everything a unit of work creates carries its work id: branches `<wNNN>/<name>` (see Git), worktrees under `$SANDBOX_VM_STATE/wt/<wNNN>/`, containers `<wNNN>-<name>`. Agents remove what they created and nothing else. - Everything a unit of work creates carries its work id: branches `<wNNN>/<name>` (see Git), worktrees under `$SANDBOX_VM_STATE/wt/<wNNN>/`, containers `<wNNN>-<name>`. Agents remove what they created and nothing else.
- The lead keeps `made.md` in the work item: each branch, worktree, container and handoff folder, with its state (open, merged, prototype); whether a branch is in main, `notes.py status` reads from git. - The lead keeps `made.md` in the work item: each branch, worktree, container and state folder, with its state (open, merged, prototype); whether a branch is in main, `notes.py status` reads from git.
- Close-out removes the list, then checks nothing under the work id is left. - Close-out removes the list, then checks nothing under the work id is left.
## Interruptions ## Interruptions

View File

@@ -97,7 +97,7 @@ Settling: check the repo first, fold the outcome into a doc or work item if wort
## Other ## Other
`other/out/` holds documents for someone else, written for that reader, and the few small files that go with them; no ids, no status line. HTML there follows the doc skeleton with `../../notes.css`; the eyebrow names the reader and date (`for the team · 2026-10-14`). What gets sent is the generated `_out/<file>`; look at it before handing it over, link it from the work item's `## Your move` (the index doesn't list `other/`), then `commit "other: <file>"`. Bulk output for a person (screenshots, builds, logs) goes to the host handoff mount, not `.notes/`. `other/out/` holds documents for someone else, written for that reader, and the few small files that go with them; no ids, no status line. HTML there follows the doc skeleton with `../../notes.css`; the eyebrow names the reader and date (`for the team · 2026-10-14`). What gets sent is the generated `_out/<file>`; look at it before handing it over, link it from the work item's `## Your move` (the index doesn't list `other/`), then `commit "other: <file>"`. Bulk output for a person (screenshots, builds, logs) stays in `$SANDBOX_VM_STATE`, named by full path, not `.notes/`.
## Never ## Never

View File

@@ -1034,7 +1034,26 @@ def file_reply(notes: Path, work: str, part: str, ref: str, checked: str) -> Non
# serve: every project's notes on one port # serve: every project's notes on one port
SKIP_DIRS = {"node_modules", "target", "dist", "build", "vendor", "__pycache__"} SKIP_DIRS = {
"node_modules",
"target",
"dist",
"build",
"vendor",
"__pycache__",
"cache",
}
# browser profiles under ~/.config: thousands of directories, never a project
SKIP_PATHS = {"config/chromium", "config/google-chrome", "config/BraveSoftware"}
def is_claude_config(d: Path) -> bool:
"""claude code's config dir: its subdirectories are transcripts, sessions and skills"""
return (
d.name.lstrip(".") == "claude"
and (d / "settings.json").is_file()
and (d / "projects").is_dir()
)
def find_notes(roots: list[Path], depth: int = 6) -> dict[str, Path]: def find_notes(roots: list[Path], depth: int = 6) -> dict[str, Path]:
@@ -1049,14 +1068,18 @@ def find_notes(roots: list[Path], depth: int = 6) -> dict[str, Path]:
# a project's subdirectories are its code, even when the project is a root # a project's subdirectories are its code, even when the project is a root
return return
# a repo's own subdirectories are its code, not more projects # a repo's own subdirectories are its code, not more projects
if left == 0 or ((d / ".git").exists() and d != root): if left == 0 or ((d / ".git").exists() and d != root) or is_claude_config(d):
return return
try: try:
children = sorted(d.iterdir()) children = sorted(d.iterdir())
except OSError: except OSError:
return return
for c in children: for c in children:
skip = c.name.startswith(".") or c.name in SKIP_DIRS skip = (
c.name.startswith(".")
or c.name in SKIP_DIRS
or f"{d.name.lstrip('.')}/{c.name}" in SKIP_PATHS
)
if c.is_dir() and not c.is_symlink() and not skip: if c.is_dir() and not c.is_symlink() and not skip:
walk(c, root, left - 1) walk(c, root, left - 1)
@@ -1298,8 +1321,10 @@ def serve(roots: list[Path], host: str, port: int) -> None:
page = (notes / "index.html").read_text() page = (notes / "index.html").read_text()
page = page.replace("</header>", "</header>" + search_form("search"), 1) page = page.replace("</header>", "</header>" + search_form("search"), 1)
return self.send_text(page, "text/html; charset=utf-8") return self.send_text(page, "text/html; charset=utf-8")
# self.path stays the full request path, so the base class's redirect of a
# directory without its trailing slash keeps the project prefix
self.serve_from = notes self.serve_from = notes
self.path = "/" + rest self.serve_prefix = prefix
return super().do_GET() return super().do_GET()
def do_POST(self) -> None: def do_POST(self) -> None:
@@ -1351,7 +1376,8 @@ def serve(roots: list[Path], host: str, port: int) -> None:
def translate_path(self, path: str) -> str: def translate_path(self, path: str) -> str:
base = self.serve_from.resolve() base = self.serve_from.resolve()
target = (base / unquote(urlsplit(path).path).lstrip("/")).resolve() rest = unquote(urlsplit(path).path)[len(self.serve_prefix) + 1 :]
target = (base / rest.lstrip("/")).resolve()
return str(target if target.is_relative_to(base) else base / "__outside__") return str(target if target.is_relative_to(base) else base / "__outside__")
def log_message(self, format: str, *args) -> None: def log_message(self, format: str, *args) -> None: