@evertonferreira96/agents 0.1.3 → 0.1.5

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.
Files changed (35) hide show
  1. package/.claude/agents/api.md +2 -3
  2. package/.claude/agents/app.md +2 -2
  3. package/.claude/agents/product.md +18 -7
  4. package/.claude/agents/quick.md +1 -1
  5. package/.claude/agents/ui.md +1 -1
  6. package/.claude/agents/verifier.md +8 -4
  7. package/.claude/agents/web.md +2 -2
  8. package/.claude/hooks/orchestrator-guard.sh +3 -1
  9. package/.claude/hooks/post-compact.sh +20 -4
  10. package/.claude/hooks/stop-verify.sh +8 -3
  11. package/.claude/rules/adr.md +42 -0
  12. package/.claude/skills/arch-api/references/review.md +17 -0
  13. package/.claude/skills/arch-app/references/review.md +15 -0
  14. package/.claude/skills/arch-db/references/review.md +2 -0
  15. package/.claude/skills/arch-web/references/tests.md +15 -0
  16. package/.claude/skills/brief/SKILL.md +32 -3
  17. package/.claude/skills/domain-modeling/ADR-FORMAT.md +47 -0
  18. package/.claude/skills/domain-modeling/GLOSSARY-FORMAT.md +60 -0
  19. package/.claude/skills/domain-modeling/SKILL.md +74 -0
  20. package/.claude/skills/domain-modeling/agents/openai.yaml +3 -0
  21. package/.claude/skills/grill-with-docs/SKILL.md +10 -16
  22. package/.claude/skills/orchestrate/SKILL.md +20 -13
  23. package/.claude/skills/project-docs/SKILL.md +1 -14
  24. package/.claude/skills/review/SKILL.md +3 -3
  25. package/.claude/skills/wayfinder/SKILL.md +146 -0
  26. package/.claude/skills/wayfinder/agents/openai.yaml +5 -0
  27. package/README.md +18 -14
  28. package/VERSION +1 -1
  29. package/docs/plans/README.md +38 -7
  30. package/package.json +1 -2
  31. package/scripts/bootstrap.mjs +19 -5
  32. package/scripts/check-catalog.mjs +4 -1
  33. package/skills-lock.json +18 -3
  34. package/templates/CLAUDE.project.md +1 -1
  35. package/docs/adr/README.md +0 -31
@@ -7,9 +7,11 @@ The newest plan is re-injected after context compaction by the post-compact hook
7
7
  Rules of the file:
8
8
 
9
9
  - Paths appear only under Scope. Decisions name modules, interfaces and contracts, never files or code.
10
- - Test seams are the contract between `/product`, the implementers (`tdd`) and `/verifier`: a seam not listed here is not tested, a seam listed here must be.
10
+ - Test seams are the contract between `/product`, the implementers (`tdd`) and `/verifier`: a seam not listed here is not tested, a seam listed here must be. One row per level (e2e, entry, service, repository, unit) and public interface; each row says which criteria it proves, what it catches and what it leaves to another level. The user confirms the table at the ticket gate (`Confirmed:` line), which makes the rows the pre-agreed seams `tdd` asks for: implementers never ask, and never add a row.
11
+ - Terms holds the domain words this plan introduces or uses differently from `GLOSSARY.md`. The user confirms them at the ticket gate and the orchestrator moves them into `GLOSSARY.md` (skill `domain-modeling`).
11
12
  - Tickets are vertical slices with `Blocked by` edges; the orchestrator works the frontier (tickets whose blockers are done) and marks Status as they land.
12
13
  - Session state is the compaction insurance: everything the orchestrator would lose with its window goes there first (skill `orchestrate` section 14).
14
+ - Grill record is the grill on paper: the orchestrator appends to it after every round, while the conversation is still in its window, and `/product` plans from it. Nobody rewrites it later; corrections are appended. It is the last section because the post-compact hook re-injects only the first 120 lines, which must keep carrying Session state and the tickets; for the same reason Test seams, which grows with the levels, comes after Tickets.
13
15
  - A section that does not apply says `n/a` and why, so a reader knows it was considered.
14
16
 
15
17
  ## Template
@@ -48,20 +50,27 @@ Size: S | M | L
48
50
  ## Decisions
49
51
  - <decision> - <why> (modules, interfaces, schema, contracts; architect verdict and constraints)
50
52
 
51
- ## Test seams
52
- | Seam | Catches | Misses | Prior art |
53
- |------|---------|--------|-----------|
54
- | S1: <public interface> | <behavior it proves> | <what it cannot see> | <existing test, or none> |
55
-
56
53
  ## Tickets
57
54
  <one ticket = one tracer bullet = one brief = one agent = one context window>
58
55
  | # | Ticket | Delivers | Blocked by | Agent | Paths | Seams | Status |
59
56
  |---|--------|----------|------------|-------|-------|-------|--------|
60
57
  | 1 | <title> | <end-to-end behavior, from the user's perspective> | - | /api | <globs> | S1 | todo |
61
58
 
59
+ ## Test seams
60
+ <one row per level and public interface; default levels per size in agent `product` (step 6); levels per stack in the `arch-*` testing references>
61
+ Confirmed: <YYYY-MM-DD at the ticket gate | pending>
62
+ | # | Level | Seam (public interface) | ACs | Catches | Leaves to | Prior art |
63
+ |---|-------|-------------------------|-----|---------|-----------|-----------|
64
+ | S1 | e2e | <flow: create -> approve -> list> | AC1, AC2 | <the flow end to end, happy path and the failures that hurt most> | <rule detail: S3, S5> | <existing test, or none> |
65
+ | S2 | entry | <POST /invoices> | AC1 | <contract, validation, authorization, error codes> | <business rule: S3> | <...> |
66
+ | S3 | service | <CreateInvoice use case> | AC3 | <business rules and decisions, ports faked> | <SQL: S4> | <...> |
67
+ | S4 | repository | <invoices repository adapter> | AC4 | <SQL, mapping, constraints, pagination, real database> | <-> | <...> |
68
+ | S5 | unit | <invoice rules> | AC3 | <every edge case of the pure rule> | <-> | <...> |
69
+
62
70
  ## Definition of Done
63
71
  - [ ] lint, build, tests green (evidence pasted)
64
- - [ ] a test exists at every seam listed above
72
+ - [ ] a test exists at every seam listed above, at its level
73
+ - [ ] the slow suites (integration, e2e) ran in `/verifier`; the Stop hook runs only the fast one
65
74
  - [ ] diff only inside scoped paths
66
75
  - [ ] docs updated if route/job/store/integration/fallback changed
67
76
  - [ ] no secrets in diff
@@ -70,4 +79,26 @@ Size: S | M | L
70
79
 
71
80
  ## Open questions
72
81
  - ...
82
+
83
+ ## Terms
84
+ <domain words this plan introduces or uses differently from GLOSSARY.md, confirmed by the user at the ticket gate and then written to GLOSSARY.md; n/a when the plan uses only glossary terms>
85
+ - **<Term>**: <one or two sentences: what it is> _Avoid_: <synonyms> - new | conflicts with GLOSSARY.md (<entry>) | confirmed
86
+
87
+ ## Grill record
88
+ <appended by the orchestrator after every grill round; never rewritten, corrections appended; n/a when no grill ran (S, or M with no open decision)>
89
+ - Q<n> <question title>: <decision> - why: <reason, in the user's words when they add nuance>
90
+ - Rejected: <alternative> - <why not>
91
+ - Constraint: <anything said in passing that binds the work>
73
92
  ```
93
+
94
+ ## Wayfinder efforts
95
+
96
+ Work too big and too foggy for one plan (the destination is clear, the way is not) is charted by skill `wayfinder` in its own folder, one level down so the post-compact hook never mistakes it for a task plan:
97
+
98
+ ```
99
+ docs/plans/<effort>/
100
+ map.md Status, Destination, Notes, Decisions so far, Not yet specified, Out of scope
101
+ decisions/NN-<slug>.md one question per file: Type, Status, Blocked by, ## Question, ## Answer
102
+ ```
103
+
104
+ The map is an index: a decision lives in its ticket, and the map only gists it and links. When the map is done, the build starts as an L task with its own `docs/plans/<task>.md`, and `/product` reads the map as the source of the decisions already made.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evertonferreira96/agents",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Personal agents, rules, hooks and skills for Claude Code (portable to Cursor and Codex through AGENTS.md), installable into any project.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,7 +20,6 @@
20
20
  "AGENTS.md",
21
21
  ".worktreeinclude",
22
22
  "docs/plans/README.md",
23
- "docs/adr/README.md",
24
23
  "docs/brief-template.md",
25
24
  "scripts/bootstrap.mjs",
26
25
  "scripts/check-catalog.mjs",
@@ -7,6 +7,9 @@
7
7
  // node scripts/bootstrap.mjs <target> --force update --force: also overwrite files edited in the project
8
8
  // node scripts/bootstrap.mjs --sync inside a project bootstrapped from a local clone: pull it, then update
9
9
  // Protected (never written over): CLAUDE.md, .claude/settings.local.json, .claude/agent-memory/**
10
+ // Project-owned (never shipped, written over or deleted, even with --force): the project's README.md, GLOSSARY.md and GLOSSARY-MAP.md,
11
+ // docs/adr/** (no README either: the ADR template is rule .claude/rules/adr.md), docs/plans/** except its README.md template,
12
+ // .claude/agent-memory/**, .claude/handoffs/**. check-catalog.mjs fails if SYNC would ship one.
10
13
  // .claude/config-manifest.json records the hash of every file the config installed. `update` uses it to tell a file that is
11
14
  // only outdated (overwritten) from one edited in the project (kept unless --force), and deletes files that left the config
12
15
  // only when the project copy is untouched.
@@ -17,9 +20,16 @@ import { dirname, join, relative, resolve, sep } from "node:path";
17
20
  import { fileURLToPath } from "node:url";
18
21
 
19
22
  export const SYNC = [".claude/agents", ".claude/hooks", ".claude/rules", ".claude/skills", ".claude/settings.json", "AGENTS.md", ".worktreeinclude",
20
- "docs/plans/README.md", "docs/adr/README.md", "docs/brief-template.md", "scripts/skills-update.mjs", "scripts/check-catalog.mjs", "scripts/bootstrap.mjs", "skills-lock.json"];
23
+ "docs/plans/README.md", "docs/brief-template.md", "scripts/skills-update.mjs", "scripts/check-catalog.mjs", "scripts/bootstrap.mjs", "skills-lock.json"];
21
24
  export const SKIP = /(^|\/)(scripts\/bin|__pycache__|node_modules|\.context-band)(\/|$)|\.pyc$/;
22
25
  export const PROTECTED = /^(CLAUDE\.md|\.claude\/settings\.local\.json|\.claude\/agent-memory\/.*)$/;
26
+ // What belongs to the project and its work: its README, plans, wayfinder maps, ADRs, glossaries, agent memory, handoffs.
27
+ // The config ships only the plan template (docs/plans/README.md).
28
+ export const PROJECT_OWNED = /^(README\.md|(?!\.claude\/)(.+\/)?GLOSSARY\.md|GLOSSARY-MAP\.md|docs\/plans\/(?!README\.md$).+|((?!\.claude\/).+\/)?docs\/adr\/.+|\.claude\/agent-memory\/.+|\.claude\/handoffs\/.+)$/;
29
+ // Files older versions shipped into a project-owned folder: update removes them when untouched, like any file that left the config,
30
+ // and otherwise stops tracking them. docs/adr/README.md was the ADR template before it became rule adr (ADR 0013).
31
+ export const RETIRED = new Set(["docs/adr/README.md"]);
32
+ const isProtected = (rel) => PROTECTED.test(rel) || PROJECT_OWNED.test(rel);
23
33
  export const GITIGNORE = [".claude/worktrees/", ".claude/handoffs/", ".claude/.context-band", ".claude/.stop-verify-ran", ".claude/settings.local.json",
24
34
  ".claude/agent-memory-local/", "graphify-out/", ".claude/skills/impeccable/scripts/bin/", "__pycache__/", "*.pyc"];
25
35
  export const MANIFEST = ".claude/config-manifest.json";
@@ -45,14 +55,15 @@ export function readPackage(src = DEFAULT_SRC) {
45
55
  }
46
56
 
47
57
  // Every file the config installs, keyed by its path relative to the config root (forward slashes).
48
- export function configFiles(src = DEFAULT_SRC) {
58
+ // Project-owned paths are never installed; `includeProjectOwned` lists them anyway, for check-catalog.mjs.
59
+ export function configFiles(src = DEFAULT_SRC, { includeProjectOwned = false } = {}) {
49
60
  const files = new Map();
50
61
  for (const entry of SYNC) {
51
62
  const abs = join(src, entry);
52
63
  if (!existsSync(abs)) continue;
53
64
  for (const f of walk(abs)) {
54
65
  const rel = relative(src, f).split(sep).join("/");
55
- if (!SKIP.test(rel)) files.set(rel, f);
66
+ if (!SKIP.test(rel) && (includeProjectOwned || !PROJECT_OWNED.test(rel))) files.set(rel, f);
56
67
  }
57
68
  }
58
69
  return files;
@@ -184,7 +195,7 @@ export function install({ src = DEFAULT_SRC, target, mode = "init", force = fals
184
195
  }
185
196
  const untouched = installed?.[rel] === have;
186
197
  if (mode === "check") { (untouched ? r.outdated : r.edited).push(rel); continue; }
187
- if (mode === "update" && (untouched || force) && !PROTECTED.test(rel)) {
198
+ if (mode === "update" && (untouched || force) && !isProtected(rel)) {
188
199
  if (write) copyFileSync(abs, dst);
189
200
  r.updated.push(rel); next[rel] = want;
190
201
  continue;
@@ -196,16 +207,19 @@ export function install({ src = DEFAULT_SRC, target, mode = "init", force = fals
196
207
 
197
208
  for (const [rel, hash] of Object.entries(installed ?? {})) {
198
209
  if (files.has(rel)) continue;
210
+ const retired = RETIRED.has(rel);
211
+ if (PROJECT_OWNED.test(rel) && !retired) continue; // an older config shipped it: it is the project's now, so stop tracking it, never delete it
199
212
  const dst = join(target, rel);
200
213
  if (!existsSync(dst)) continue;
201
214
  const untouched = sha(dst) === hash;
202
215
  if (mode === "check") { r.obsolete.push(rel); continue; }
203
- if (mode === "update" && untouched && !PROTECTED.test(rel)) {
216
+ if (mode === "update" && untouched && (retired || !isProtected(rel))) {
204
217
  if (write) { rmSync(dst); removeEmptyParents(target, rel); }
205
218
  r.removed.push(rel);
206
219
  continue;
207
220
  }
208
221
  if (mode === "update") r.obsoleteKept.push(rel);
222
+ if (retired && mode === "update") continue; // edited here: it is the project's file now
209
223
  next[rel] = hash; // keep tracking it so a later update can still remove it
210
224
  }
211
225
 
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
- // Drift checks: skills on disk vs docs/skills.md vs frontmatter vs skills-lock.json vs agents' skills: vs settings hooks.
2
+ // Drift checks: skills on disk vs docs/skills.md vs frontmatter vs skills-lock.json vs agents' skills: vs settings hooks,
3
+ // and no project-owned path (plans, ADRs, glossary, agent memory, handoffs) among the files the config ships.
3
4
  // Exit 1 on any error. Warnings do not fail.
4
5
  import { existsSync, readFileSync, readdirSync } from "node:fs";
6
+ import { configFiles, PROJECT_OWNED } from "./bootstrap.mjs";
5
7
  const errors = [], warnings = [];
6
8
  const read = (p) => readFileSync(p, "utf8");
7
9
  const fm = (p) => read(p).split("---")[1] ?? "";
@@ -37,6 +39,7 @@ for (const list of Object.values(settings.hooks ?? {})) for (const e of list) fo
37
39
  const m = /\$CLAUDE_PROJECT_DIR\/(\.claude\/hooks\/[^" ]+)/.exec(h.command ?? "");
38
40
  if (m && !existsSync(m[1])) errors.push(`settings.json: hook file ${m[1]} does not exist`);
39
41
  }
42
+ for (const rel of configFiles(undefined, { includeProjectOwned: true }).keys()) if (PROJECT_OWNED.test(rel)) errors.push(`${rel}: project-owned path shipped by the config (scripts/bootstrap.mjs SYNC)`);
40
43
  for (const w of warnings) console.log(`warn ${w}`);
41
44
  for (const e of errors) console.log(`ERROR ${e}`);
42
45
  console.log(`${skills.length} skills, ${rows.size} catalog rows, ${Object.keys(lock).length} lock entries: ${errors.length} error(s), ${warnings.length} warning(s)`);
package/skills-lock.json CHANGED
@@ -69,6 +69,13 @@
69
69
  "skillPath": "skills/engineering/diagnosing-bugs/SKILL.md",
70
70
  "sha256": "849198df88cdb65fd0d97236604c1fca7ff2f22d2f705f9724a800d0266b118d"
71
71
  },
72
+ "domain-modeling": {
73
+ "source": "mattpocock/skills",
74
+ "sourceType": "github",
75
+ "sourceCommit": "49dd158",
76
+ "skillPath": "skills/engineering/domain-modeling/SKILL.md",
77
+ "sha256": "7b925d7b1e341a2eeae33ad68a8a8c0ab889a38ddd22a7598e4c240e5a7556a3"
78
+ },
72
79
  "emil-design-eng": {
73
80
  "source": "emilkowalski/skills",
74
81
  "sourceType": "github",
@@ -107,10 +114,9 @@
107
114
  "sourceType": "github",
108
115
  "sourceCommit": "49dd158",
109
116
  "skillPath": "skills/engineering/grill-with-docs/SKILL.md",
110
- "note": "adapted: upstream calls grilling + domain-modeling; local version inlines glossary/ADR rules and adds docs/plans read-first, graphify and the decisions block for the orchestrator",
117
+ "note": "adapted: calls grilling + domain-modeling like upstream; adds docs/plans read-first, graphify, the Grill record, the ADR template and lifecycle of rule adr (.claude/rules/adr.md) (which wins over domain-modeling's ADR-FORMAT.md) and the decisions block for the orchestrator",
111
118
  "adapted": true,
112
- "sha256": "4a6d8bb82e01431ecee9a13b06ccfc4b911f6ee2efcf09bc6686a8e4cee58f72",
113
- "sha256Note": "baseline taken from the local file on 2026-10-17; replaced by the upstream hash on the next `skills-update.mjs --lock`"
119
+ "sha256": "7de372c13488f1ee96cc11cd8907b56b6809cc93eef776eeddd37de6b6cbe3fe"
114
120
  },
115
121
  "grilling": {
116
122
  "source": "mattpocock/skills",
@@ -253,6 +259,15 @@
253
259
  "adapted": true,
254
260
  "adaptedNote": "frontmatter only: disable-model-invocation: true (preloaded by the agents that use it)"
255
261
  },
262
+ "wayfinder": {
263
+ "source": "mattpocock/skills",
264
+ "sourceType": "github",
265
+ "sourceCommit": "49dd158",
266
+ "skillPath": "skills/engineering/wayfinder/SKILL.md",
267
+ "sha256": "9be7b478c389605a24517d27752f278933588da97a1b5921b165f455edf4c5b7",
268
+ "adapted": true,
269
+ "adaptedNote": "no issue tracker: the map is docs/plans/<effort>/map.md (with a Status line for the post-compact hook) and tickets are docs/plans/<effort>/decisions/NN-<slug>.md with Type, Status and Blocked by lines (upstream's local-markdown layout, moved under docs/plans); research tickets run as a read-only subagent with a brief instead of skill research (not vendored); prototype tickets go to /ui (skill prototype, emilkowalski) or the owning implementer in a spike worktree, never merged or pushed, since this repo's prototype is a different skill; sessions end with /clear; adds the hand-off to an L task in orchestrate when the way is clear (ADR 0012)"
270
+ },
256
271
  "writing-for-agents": {
257
272
  "source": "mattpocock/skills",
258
273
  "sourceType": "github",
@@ -27,7 +27,7 @@
27
27
  - Skills: `.claude/skills/` (catalog and wiring: docs/skills.md)
28
28
  - Architecture skills: arch-api (NestJS), arch-web (Next.js), arch-app (Expo), arch-db (Postgres/MySQL; loaded by rule db.md)
29
29
  - Plans: `docs/plans/` (template in docs/plans/README.md)
30
- - ADRs: `docs/adr/` (template and numbering in docs/adr/README.md)
30
+ - ADRs: `docs/adr/` (template and numbering in rule `.claude/rules/adr.md`; the folder is yours, the config never writes to it)
31
31
  - Brief template: skill `brief` (`docs/brief-template.md` points there)
32
32
  - Vendored skills: origins in `skills-lock.json`; check upstream with `node scripts/skills-update.mjs`
33
33
  - Decisions about this repo: `docs/adr/`; changes: `CHANGELOG.md`
@@ -1,31 +0,0 @@
1
- # ADRs
2
-
3
- One file per architecture decision: `docs/adr/NNNN-<slug>.md`.
4
-
5
- ## Numbering
6
-
7
- - `NNNN` is 4 digits, zero-padded, next after the highest existing number (`0001`, `0002`, ...). Never reuse a number.
8
- - `<slug>` is lowercase kebab-case of the title.
9
- - ADRs are immutable once Accepted. To change a decision, write a new ADR and set the old one to `Superseded by NNNN`.
10
-
11
- ## Flow
12
-
13
- `/architect` returns an ADR proposal, the orchestrator copies it into `docs/plans/<task>.md`, and at DoD creates the ADR file in the same diff as the change.
14
-
15
- ## Template
16
-
17
- ```markdown
18
- # NNNN - <title>
19
-
20
- Status: Proposed | Accepted | Superseded by NNNN | Deprecated
21
- Date: YYYY-MM-DD
22
-
23
- ## Context
24
- <forces, constraints, the problem; link the plan>
25
-
26
- ## Decision
27
- <what we do, in present tense>
28
-
29
- ## Consequences
30
- <what gets easier, what gets harder, rejected alternatives and why>
31
- ```