pi-matt-pocock 0.2.2 → 0.3.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.
Files changed (70) hide show
  1. package/ARCHITECTURE.zh-CN.md +37 -19
  2. package/README.md +80 -13
  3. package/package.json +12 -7
  4. package/procedures/code-review.md +25 -17
  5. package/procedures/codebase-design.md +11 -10
  6. package/procedures/deslop.md +4 -2
  7. package/procedures/diagnosing-bugs.md +25 -25
  8. package/procedures/domain-modeling.md +18 -20
  9. package/procedures/grill-me.md +1 -1
  10. package/procedures/grill-with-docs.md +1 -1
  11. package/procedures/grilling.md +29 -5
  12. package/procedures/handoff.md +1 -1
  13. package/procedures/implement.md +7 -1
  14. package/procedures/improve-codebase-architecture.md +22 -22
  15. package/procedures/pr.md +169 -0
  16. package/procedures/prototype.md +7 -6
  17. package/procedures/research.md +2 -2
  18. package/procedures/retro.md +42 -0
  19. package/procedures/setup-matt-pocock-skills.md +26 -22
  20. package/procedures/tdd.md +17 -15
  21. package/procedures/teach.md +11 -7
  22. package/procedures/to-questionnaire.md +7 -5
  23. package/procedures/to-spec.md +2 -2
  24. package/procedures/to-tickets.md +12 -12
  25. package/procedures/triage.md +22 -22
  26. package/procedures/wait-what.md +1 -1
  27. package/procedures/wayfinder.md +24 -24
  28. package/procedures/wizard.md +7 -7
  29. package/procedures/writing-for-agents.md +14 -14
  30. package/{procedures → references}/ADR-FORMAT.md +11 -11
  31. package/{procedures → references}/AGENT-BRIEF.md +4 -4
  32. package/{procedures → references}/DEEPENING.md +3 -3
  33. package/{procedures → references}/DESIGN-IT-TWICE.md +7 -7
  34. package/{procedures → references}/GLOSSARY-FORMAT.md +9 -2
  35. package/{procedures → references}/HTML-REPORT.md +15 -15
  36. package/{procedures → references}/LEARNING-RECORD-FORMAT.md +10 -10
  37. package/{procedures → references}/LOGIC.md +5 -5
  38. package/{procedures → references}/MISSION-FORMAT.md +2 -2
  39. package/{procedures → references}/OUT-OF-SCOPE.md +11 -11
  40. package/{procedures → references}/RESOURCES-FORMAT.md +1 -1
  41. package/{procedures → references}/SKILL-MECHANICS.md +3 -3
  42. package/{procedures → references}/UI.md +14 -14
  43. package/{procedures → references}/bdd-best-practices.md +3 -3
  44. package/{procedures → references}/bdd.md +9 -9
  45. package/{procedures → references}/domain.md +12 -12
  46. package/references/issue-tracker-github.md +50 -0
  47. package/{procedures → references}/issue-tracker-gitlab.md +9 -9
  48. package/{procedures → references}/issue-tracker-local.md +3 -3
  49. package/{procedures → references}/phase-boundaries.md +8 -8
  50. package/src/catalog.json +49 -28
  51. package/src/catalog.ts +58 -2
  52. package/src/index.ts +521 -383
  53. package/src/native-dialog.ts +149 -213
  54. package/src/resolver.ts +30 -14
  55. package/src/workflow.ts +55 -16
  56. package/upstream/UPSTREAM.md +116 -0
  57. package/{scripts → upstream}/check-upstream-sync.mjs +12 -12
  58. package/{upstream-selection.json → upstream/upstream-selection.json} +9 -7
  59. package/UPSTREAM.md +0 -63
  60. package/procedures/CONTEXT-FORMAT.md +0 -60
  61. package/procedures/issue-tracker-github.md +0 -45
  62. /package/{procedures → assets}/hitl-loop.template.sh +0 -0
  63. /package/{procedures → assets}/template.sh +0 -0
  64. /package/{procedures → references}/GLOSSARY.md +0 -0
  65. /package/{procedures → references}/gherkin-guide.md +0 -0
  66. /package/{procedures → references}/mocking.md +0 -0
  67. /package/{procedures → references}/testing-anti-patterns.md +0 -0
  68. /package/{procedures → references}/tests.md +0 -0
  69. /package/{procedures → references}/triage-labels.md +0 -0
  70. /package/{procedures → references}/writing-great-skills.md +0 -0
package/src/workflow.ts CHANGED
@@ -2,6 +2,7 @@ import {
2
2
  allowedTransitions,
3
3
  modelStandaloneCapabilities,
4
4
  normalizeProcedureId,
5
+ userStandaloneCapabilities,
5
6
  workflowEntry,
6
7
  workflowPlacement,
7
8
  workflowRoutes as catalogWorkflowRoutes,
@@ -61,6 +62,12 @@ export function routeEntryState(route: string, workItemId: string): WorkflowStat
61
62
  }
62
63
 
63
64
  export function transitionState(state: WorkflowState, target: string): WorkflowState {
65
+ const currentPlacement = workflowPlacement(state.route, state.procedure);
66
+ if (!currentPlacement || currentPlacement.phase !== state.phase) {
67
+ throw new Error(
68
+ `Cannot transition ${state.route} from ${state.procedure}: invalid current procedure state.`,
69
+ );
70
+ }
64
71
  const normalized = normalizeProcedureId(target);
65
72
  const allowed = allowedTransitions(state.route, state.procedure);
66
73
  if (!allowed.includes(normalized)) {
@@ -75,6 +82,7 @@ export function transitionState(state: WorkflowState, target: string): WorkflowS
75
82
  procedure: normalized,
76
83
  phase: placement.phase,
77
84
  loadedReferences: [],
85
+ deliveredProcedures: state.deliveredProcedures ?? [],
78
86
  };
79
87
  }
80
88
 
@@ -106,15 +114,19 @@ export function formatReadableWorkflowSubject(route: string, phase: string): str
106
114
  return `${readableRouteTitle(route)} · ${readablePhaseTitle(phase)}`;
107
115
  }
108
116
 
109
- export function isWorkflowState(value: unknown): value is WorkflowState {
110
- if (!value || typeof value !== "object") return false;
117
+ function workflowRecord(value: unknown): Record<string, unknown> | undefined {
118
+ if (!value || typeof value !== "object") return undefined;
111
119
  const candidate = value as Record<string, unknown>;
112
120
  return candidate.version === WORKFLOW_STATE_VERSION
113
- && typeof candidate.workItemId === "string"
121
+ && typeof candidate.workItemId === "string" && candidate.workItemId.trim().length > 0
114
122
  && typeof candidate.route === "string"
115
123
  && typeof candidate.procedure === "string"
116
- && typeof candidate.phase === "string"
117
- && candidate.status === "active"
124
+ && typeof candidate.phase === "string" ? candidate : undefined;
125
+ }
126
+
127
+ export function isWorkflowState(value: unknown): value is WorkflowState {
128
+ const candidate = workflowRecord(value);
129
+ return candidate !== undefined && candidate.status === "active"
118
130
  && Array.isArray(candidate.loadedReferences)
119
131
  && candidate.loadedReferences.every((reference) => typeof reference === "string")
120
132
  // Absent is tolerated so a workflow persisted before delivery tracking existed still
@@ -130,13 +142,8 @@ export function withDeliveryDefaults(state: WorkflowState): WorkflowState {
130
142
  }
131
143
 
132
144
  export function isTerminalWorkflowState(value: unknown): value is TerminalWorkflowState {
133
- if (!value || typeof value !== "object") return false;
134
- const candidate = value as Record<string, unknown>;
135
- return candidate.version === WORKFLOW_STATE_VERSION
136
- && typeof candidate.workItemId === "string"
137
- && typeof candidate.route === "string"
138
- && typeof candidate.procedure === "string"
139
- && typeof candidate.phase === "string"
145
+ const candidate = workflowRecord(value);
146
+ return candidate !== undefined
140
147
  && (candidate.status === "completed" || candidate.status === "cancelled");
141
148
  }
142
149
 
@@ -144,7 +151,9 @@ export function latestWorkflowRecord(entries: unknown[]): WorkflowSessionData |
144
151
  for (let index = entries.length - 1; index >= 0; index -= 1) {
145
152
  const entry = entries[index] as { type?: unknown; customType?: unknown; data?: unknown } | undefined;
146
153
  if (entry?.type !== "custom" || entry.customType !== WORKFLOW_STATE_ENTRY) continue;
147
- if (isWorkflowState(entry.data) || isTerminalWorkflowState(entry.data)) return entry.data;
154
+ // The newest entry is authoritative even when incompatible. Never resurrect
155
+ // an older active workflow by skipping a malformed terminal or future version.
156
+ return isWorkflowState(entry.data) || isTerminalWorkflowState(entry.data) ? entry.data : undefined;
148
157
  }
149
158
  return undefined;
150
159
  }
@@ -161,17 +170,42 @@ Work item: ${state.workItemId}. Follow the loaded ${state.procedure} procedure.
161
170
 
162
171
  Drive the current procedure to its end in this turn. A multi-step deliverable is not finished because one step passed: keep implementing, testing and fixing until every step the procedure covers is done, rather than stopping at the first green slice or handing back a plan for the remainder. Do not end the turn to ask whether to continue.
163
172
 
164
- Use matt_pocock_active to transition only to: ${next.join(", ") || "none"}; load an available reference; complete the work; or cancel it with a reason. Available references: ${availableReferences.join(", ") || "none"}. Exact shapes: {"action": "transition", "target": "<allowedNext id>"}; {"action": "load", "reference": "<availableReferences id>"}; {"action": "complete"}; {"action": "cancel", "reason": "<why>"}. Proceed autonomously through non-user-owned work: transition to the next applicable procedure as soon as this one's deliverables are complete, without stopping to ask permission. Ask only for a genuinely user-owned decision, an unavailable fact, or a required external action, and use matt_pocock_ask for those.
173
+ Use matt_pocock_active to transition only to: ${next.join(", ") || "none"}; load an available reference; complete the work; or cancel it with a reason. Available references: ${availableReferences.join(", ") || "none"}. Exact shapes: {"action": "transition", "target": "<allowedNext id>"}; {"action": "load", "reference": "<availableReferences id>"}; {"action": "complete"}; {"action": "cancel", "reason": "<why>"}. Proceed autonomously through non-user-owned work: transition to the next applicable procedure as soon as this one's deliverables are complete, without stopping to ask permission. Ask only for a genuinely user-owned decision, an unavailable fact, or a required external action, and use matt_pocock_ask for those, with the required recommended option its deadline adopts.
165
174
 
166
175
  Yield only when the remaining work genuinely depends on an external actor, on a teammate result you cannot produce yourself, or on context you no longer have — and when you yield, state plainly what is unfinished rather than implying completion. Never announce completion early: call matt_pocock_active with action complete only once the integrated candidate has applicable verification and all blocking reviews have returned with their findings resolved; a completed review assignment is not itself a PASS verdict, and evidence must match that candidate.`;
167
176
  }
168
177
 
178
+ /** One terse line per user-invoked capability. The prompt budget governs this
179
+ * section, so it names the id and its subject rather than repeating the full
180
+ * catalog description the menu and the tool schema already carry. */
181
+ function userCapabilitySummary(definition: { id: string; label: string }): string {
182
+ return userCapabilitySummaries[definition.id] ?? definition.label;
183
+ }
184
+
185
+ const userCapabilitySummaries: Record<string, string> = {
186
+ "grill-me": "relentless one-decision-at-a-time interview; \"grill me\" names it",
187
+ handoff: "handoff document another agent can pick up cold",
188
+ retro: "review recent work and record what to change",
189
+ "improve-codebase-architecture": "rank and improve architecture deepening opportunities",
190
+ "setup-matt-pocock-skills": "configure the repository tracker and document layout",
191
+ teach: "teach a concept step by step",
192
+ "to-questionnaire": "turn a decision blocked on someone else into a questionnaire",
193
+ "wait-what": "re-pitch the last message with the missing context",
194
+ };
195
+
169
196
  export function availableWorkflowsGuidance(): string {
170
197
  const workflows = workflowRoutes()
171
- .map((route) => `- ${route.route}: ${route.description}`)
198
+ .map((route) => `- ${route.route}: ${route.description} Call: ${JSON.stringify({ mode: "workflow", route: route.route })}`)
172
199
  .join("\n");
173
200
  const capabilities = modelStandaloneCapabilities()
174
- .map((capability) => `- ${capability.id}: ${capability.description}`)
201
+ .map((capability) => `- ${capability.id}: ${capability.description} Call: ${JSON.stringify({ mode: "capability", capability: capability.id })}`)
202
+ .join("\n");
203
+ // Without this list the user-invoked capabilities are invisible here, so a request
204
+ // like "grill me" has no route and the package is silently skipped. The entries stay
205
+ // terse on purpose: the gateway schema carries the authoritative ids, so the prompt
206
+ // only has to name them and give one call shape.
207
+ const userCapabilities = userStandaloneCapabilities()
208
+ .map((capability) => `- ${capability.id}: ${userCapabilitySummary(capability)}`)
175
209
  .join("\n");
176
210
  return `## Available Matt Pocock Workflows and Capabilities
177
211
 
@@ -190,5 +224,10 @@ ${workflows}
190
224
  Model-reachable standalone capabilities:
191
225
  ${capabilities}
192
226
 
227
+ User-invoked capabilities: the user starts these by name, so run one only when the user explicitly asked for it, and never substitute a different capability. Call: {"mode":"user-capability","capability":"<id>"}.
228
+ ${userCapabilities}
229
+
230
+ For an explicitly requested capability, load its listed call before applying its method. A schema rejection means the capability was not loaded: correct mode and required fields using the exact call above; do not repeat the same rejected arguments or silently claim execution.
231
+
193
232
  Workflow state is deliberate and task-scoped. When relevant, start a workflow first with matt_pocock_workflow (mode: "workflow"); the started workflow carries its procedure and next-step guidance.`;
194
233
  }
@@ -0,0 +1,116 @@
1
+ # Upstream synchronization
2
+
3
+ ## Recorded revisions
4
+
5
+ - Repository: `mattpocock/skills`
6
+ - Compared commit: `4ae2317ddb22b046e26455e4f9c9b3aaaf62212d`
7
+ - Comparison tag: `v1.3.2`
8
+ - Resolved tag commit: `d1478fcb140db0b93c0c8df17bcfd311844749d0`
9
+ - Latest checked commit: `4ae2317ddb22b046e26455e4f9c9b3aaaf62212d`
10
+
11
+ These values describe different roles. The compared commit is the content
12
+ baseline, the comparison tag is the human-readable release marker, the resolved
13
+ tag commit records what that tag points to, and the latest checked commit is
14
+ the newest upstream tree reviewed for additions or removals. Two roles may
15
+ legitimately resolve to the same commit when upstream history makes that true;
16
+ the checker validates each role against Git rather than requiring artificial
17
+ distinctions. The newest tag is not necessarily the reviewed tree: when the
18
+ baseline runs ahead of it, the tag names the newest release marker reachable
19
+ from the baseline, and the checked commits between them carry the skills
20
+ changes adopted here. At this revision the checked tree carries three commits
21
+ after `v1.3.2`: fresh-context-window guidance for delegated work, the setup
22
+ procedure's legacy glossary migration and reachable-repo requirement, and the
23
+ new `software-factory` in-progress skill. The full compare always reads the
24
+ checkout at the latest checked commit.
25
+
26
+ The machine-readable selection is in
27
+ [`upstream-selection.json`](upstream-selection.json). It classifies every
28
+ upstream `SKILL.md` present at the latest checked commit as either promoted or
29
+ intentionally excluded. Each promoted skill names its local catalog capability,
30
+ plain Markdown resource, and upstream invocation mode. Each exclusion carries a
31
+ reason; Claude Code hooks and background-agent commands are identified as
32
+ host-specific rather than silently ignored.
33
+
34
+ ## Harness architecture
35
+
36
+ Upstream distributes nested `SKILL.md` files. Pi recursively discovers any
37
+ such file under a declared skill root, which exposes generic names such as
38
+ `tdd`, `code-review`, and `research` alongside unrelated installed skills.
39
+
40
+ This package exposes one extension command, `/matt-pocock`. The extension
41
+ selects and injects plain Markdown procedures from `procedures/`, `references/`
42
+ and `assets/`; none are Pi skills, and the package contains no `SKILL.md` file.
43
+
44
+ ## Sync rules
45
+
46
+ 1. Clone upstream separately and inspect both the compared and latest checked
47
+ commits before changing local resources.
48
+ 2. Run the local metadata check without an upstream checkout:
49
+
50
+ ```bash
51
+ node packages/matt-pocock/upstream/check-upstream-sync.mjs
52
+ ```
53
+
54
+ 3. Run the complete inventory, invocation, and content comparison against an
55
+ already-cloned checkout. The checker never clones or fetches:
56
+
57
+ ```bash
58
+ node packages/matt-pocock/upstream/check-upstream-sync.mjs --upstream /path/to/mattpocock-skills
59
+ ```
60
+
61
+ To compare a temporary selection fixture without mutating the package
62
+ metadata, add `--selection /path/to/selection.json`.
63
+
64
+ 4. Copy selected workflows and supporting files into `procedures/`; never
65
+ overwrite the extension harness wholesale.
66
+ 5. Rename copied upstream `SKILL.md` files to their catalog id plus `.md`.
67
+ Strip frontmatter, and never ship a `SKILL.md` file.
68
+ 6. Remove Claude-only frontmatter, tools, paths, and invocation syntax from
69
+ copied content. Replace cross-procedure calls with relative links.
70
+ 7. Preserve the local BDD/TDD split and Pi-specific interaction,
71
+ collaboration, instruction-file, and git-agent guidance. Follow the upstream
72
+ typography: adopted text keeps upstream punctuation rather than a local variant.
73
+ An adapted content
74
+ result is expected when these local contracts differ from upstream.
75
+ Four procedures carry such local lines for the task-path policy, which says an
76
+ explicit task path wins, otherwise the procedure's own default applies.
77
+ `procedures/pr.md`, `procedures/to-questionnaire.md`, and
78
+ `procedures/improve-codebase-architecture.md` each state that the deliverable
79
+ is a written file which must exist before the turn ends, and
80
+ `procedures/improve-codebase-architecture.md` also states that its survey step
81
+ writes the report and nothing else. `procedures/implement.md` forbids a
82
+ defensive default for a value the trusted path cannot miss. A second local
83
+ policy covers interactive questions: `procedures/grilling.md`,
84
+ `procedures/grill-me.md`, `procedures/grill-with-docs.md`, and
85
+ `procedures/to-tickets.md` require a `recommended` option whose deadline
86
+ adopts it, because `matt_pocock_ask` refuses a question without one; `grilling.md`
87
+ keeps the upstream design-tree, frontier and rounds model and delivers each
88
+ frontier question through that tool. A real-upstream
89
+ comparison that reports `adapted` above zero for these files is therefore
90
+ expected, not drift. The isolated sync test compares against a fixture
91
+ generated from the local files, so it stays exact either way. Upstream since
92
+ `v1.3.1` also asks that delegated work start with a fresh context window;
93
+ local wording keeps the teammate-or-current-context rule and adds that a
94
+ delegated teammate starts fresh rather than inheriting parent history. Local
95
+ procedure text names bun as the default task runner and uses bun-workspace
96
+ signals instead of upstream's other-package-manager examples. The package's
97
+ tests, contributor commands, and reproduction notes run on bun only.
98
+ 8. Classify every new or removed upstream skill in
99
+ `upstream-selection.json`, then update the four revision fields together.
100
+ This tree has 39 `SKILL.md` files: 25 selected, 14 excluded. Promoted `pr`
101
+ and `retro` are adapted to the Pi catalog. `implement-spec` remains excluded
102
+ because it requires the upstream Skill tool, a fresh background implementer
103
+ subagent per ticket in its own worktree, and integration-branch
104
+ orchestration, which this package's gateway does not implement. The new
105
+ `software-factory` in-progress skill is excluded because it defines a
106
+ vocabulary for agent factory infrastructure the gateway does not run. The
107
+ removed `resolving-merge-conflicts` capability remains locally for
108
+ compatibility but is no longer claimed as upstream content.
109
+ 9. Re-run the harness feature, isolated sync tests, package tests, and package
110
+ dry-run after a sync.
111
+ 10. Supporting references and assets are not classified by
112
+ `upstream-selection.json`, which records `SKILL.md` files only. Match them to
113
+ their upstream counterparts by name, keep the local file name and its catalog
114
+ id, and apply the same content and typography rules. `pr` reproduces the
115
+ `show-me` visual menu, so it carries that attribution directly instead of
116
+ upstream's separate `CREDITS.md`, which this package does not ship.
@@ -9,7 +9,7 @@ const execFileAsync = promisify(execFile);
9
9
  import { fileURLToPath } from "node:url";
10
10
 
11
11
  const packageDirectory = resolve(dirname(fileURLToPath(import.meta.url)), "..");
12
- const selectionPath = resolve(packageDirectory, "upstream-selection.json");
12
+ const selectionPath = resolve(packageDirectory, "upstream/upstream-selection.json");
13
13
 
14
14
  function fail(message) {
15
15
  throw new Error(message);
@@ -54,9 +54,16 @@ function normalizedBody(value) {
54
54
  }
55
55
 
56
56
  function parseArguments(argv) {
57
- if (argv.length === 0) return {};
58
- if (argv.length === 2 && argv[0] === "--upstream") return { upstream: argv[1] };
59
- fail("usage: node scripts/check-upstream-sync.mjs [--upstream <already-cloned-path>]");
57
+ const options = {};
58
+ for (let index = 0; index < argv.length; index += 2) {
59
+ const key = { "--upstream": "upstream", "--selection": "selection" }[argv[index]];
60
+ const value = argv[index + 1];
61
+ if (!key || options[key] || !value || value.startsWith("--")) {
62
+ fail("usage: node upstream/check-upstream-sync.mjs [--upstream <already-cloned-path>] [--selection <metadata-file>]");
63
+ }
64
+ options[key] = value;
65
+ }
66
+ return options;
60
67
  }
61
68
 
62
69
  async function validateCatalogMappings(metadata) {
@@ -82,13 +89,6 @@ async function validateMetadata(metadata) {
82
89
  requireCommit(metadata.resolvedTagCommit, "resolvedTagCommit");
83
90
  requireCommit(metadata.latestCheckedCommit, "latestCheckedCommit");
84
91
 
85
- const revisions = [
86
- metadata.comparedCommit,
87
- metadata.comparisonTag,
88
- metadata.resolvedTagCommit,
89
- metadata.latestCheckedCommit,
90
- ];
91
- if (new Set(revisions).size !== revisions.length) fail("upstream revision fields must be distinct");
92
92
  if (!Array.isArray(metadata.selected) || metadata.selected.length === 0) fail("selected must be non-empty");
93
93
  if (!Array.isArray(metadata.excluded) || metadata.excluded.length === 0) fail("excluded must be non-empty");
94
94
 
@@ -196,7 +196,7 @@ async function compareUpstream(metadata, upstreamArgument) {
196
196
 
197
197
  try {
198
198
  const args = parseArguments(process.argv.slice(2));
199
- const metadata = JSON.parse(await readFile(selectionPath, "utf8"));
199
+ const metadata = JSON.parse(await readFile(args.selection ?? selectionPath, "utf8"));
200
200
  await validateMetadata(metadata);
201
201
  const comparison = args.upstream ? await compareUpstream(metadata, args.upstream) : {};
202
202
  console.log(JSON.stringify({
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "repository": "mattpocock/skills",
4
- "comparedCommit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76",
5
- "comparisonTag": "v1.2.3",
6
- "resolvedTagCommit": "6acc160e4e0cd062dbbbd7a1b26ae92855edf07e",
7
- "latestCheckedCommit": "3cca18b368ae95cdbdebbff572ccafa662551015",
4
+ "comparedCommit": "4ae2317ddb22b046e26455e4f9c9b3aaaf62212d",
5
+ "comparisonTag": "v1.3.2",
6
+ "resolvedTagCommit": "d1478fcb140db0b93c0c8df17bcfd311844749d0",
7
+ "latestCheckedCommit": "4ae2317ddb22b046e26455e4f9c9b3aaaf62212d",
8
8
  "selected": [
9
9
  { "upstreamSkill": "code-review", "upstreamPath": "skills/engineering/code-review/SKILL.md", "upstreamInvocation": "model", "localCatalogId": "code-review", "localResource": "procedures/code-review.md" },
10
10
  { "upstreamSkill": "codebase-design", "upstreamPath": "skills/engineering/codebase-design/SKILL.md", "upstreamInvocation": "model", "localCatalogId": "codebase-design", "localResource": "procedures/codebase-design.md" },
@@ -14,8 +14,9 @@
14
14
  { "upstreamSkill": "implement", "upstreamPath": "skills/engineering/implement/SKILL.md", "upstreamInvocation": "user", "localCatalogId": "implement", "localResource": "procedures/implement.md" },
15
15
  { "upstreamSkill": "improve-codebase-architecture", "upstreamPath": "skills/engineering/improve-codebase-architecture/SKILL.md", "upstreamInvocation": "user", "localCatalogId": "improve-codebase-architecture", "localResource": "procedures/improve-codebase-architecture.md" },
16
16
  { "upstreamSkill": "prototype", "upstreamPath": "skills/engineering/prototype/SKILL.md", "upstreamInvocation": "model", "localCatalogId": "prototype", "localResource": "procedures/prototype.md" },
17
+ { "upstreamSkill": "retro", "upstreamPath": "skills/engineering/retro/SKILL.md", "upstreamInvocation": "user", "localCatalogId": "retro", "localResource": "procedures/retro.md" },
17
18
  { "upstreamSkill": "research", "upstreamPath": "skills/engineering/research/SKILL.md", "upstreamInvocation": "model", "localCatalogId": "research", "localResource": "procedures/research.md" },
18
- { "upstreamSkill": "resolving-merge-conflicts", "upstreamPath": "skills/engineering/resolving-merge-conflicts/SKILL.md", "upstreamInvocation": "model", "localCatalogId": "resolving-merge-conflicts", "localResource": "procedures/resolving-merge-conflicts.md" },
19
+ { "upstreamSkill": "pr", "upstreamPath": "skills/engineering/pr/SKILL.md", "upstreamInvocation": "model", "localCatalogId": "pr", "localResource": "procedures/pr.md" },
19
20
  { "upstreamSkill": "setup-matt-pocock-skills", "upstreamPath": "skills/engineering/setup-matt-pocock-skills/SKILL.md", "upstreamInvocation": "user", "localCatalogId": "setup-matt-pocock-skills", "localResource": "procedures/setup-matt-pocock-skills.md" },
20
21
  { "upstreamSkill": "tdd", "upstreamPath": "skills/engineering/tdd/SKILL.md", "upstreamInvocation": "model", "localCatalogId": "tdd", "localResource": "procedures/tdd.md" },
21
22
  { "upstreamSkill": "to-spec", "upstreamPath": "skills/engineering/to-spec/SKILL.md", "upstreamInvocation": "user", "localCatalogId": "to-spec", "localResource": "procedures/to-spec.md" },
@@ -33,11 +34,12 @@
33
34
  ],
34
35
  "excluded": [
35
36
  { "upstreamSkill": "ask-matt", "upstreamPath": "skills/engineering/ask-matt/SKILL.md", "reason": "Replaced by the single /matt-pocock Pi command and its catalog-backed routing gateway." },
37
+ { "upstreamSkill": "chief-of-staff", "upstreamPath": "skills/in-progress/chief-of-staff/SKILL.md", "reason": "Experimental in-progress skill that depends on recurring schedules, background subagents, a dated wiki, and reading other skills' SKILL.md files; the Pi v1 gateway implements none of those contracts." },
36
38
  { "upstreamSkill": "claude-handoff", "upstreamPath": "skills/in-progress/claude-handoff/SKILL.md", "reason": "Host-specific: launches Claude Code background agents and duplicates the selected host-neutral handoff capability." },
37
- { "upstreamSkill": "implement-spec", "upstreamPath": "skills/in-progress/implement-spec/SKILL.md", "reason": "Experimental duplicate of the selected implement capability; the local workflow catalog supplies the sequencing contract." },
39
+ { "upstreamSkill": "implement-spec", "upstreamPath": "skills/engineering/implement-spec/SKILL.md", "reason": "Requires the upstream Skill tool, a fresh background implementer subagent per ticket in its own worktree, and integration-branch orchestration; this package's Pi v1 gateway does not implement that host contract." },
38
40
  { "upstreamSkill": "loop-me", "upstreamPath": "skills/in-progress/loop-me/SKILL.md", "reason": "Experimental stateful Claude skill composition is superseded by the persisted Pi workflow harness." },
39
- { "upstreamSkill": "retro", "upstreamPath": "skills/in-progress/retro/SKILL.md", "reason": "Experimental capability is outside the approved promoted engineering and productivity catalog." },
40
41
  { "upstreamSkill": "setup-ts-deep-modules", "upstreamPath": "skills/in-progress/setup-ts-deep-modules/SKILL.md", "reason": "Experimental TypeScript-specific setup is narrower than the selected host-neutral codebase-design procedure." },
42
+ { "upstreamSkill": "software-factory", "upstreamPath": "skills/in-progress/software-factory/SKILL.md", "reason": "Experimental in-progress vocabulary for designing an agent software factory (runners, orchestrators, ticket sources); the Pi v1 gateway implements no factory runtime and this package ships no SKILL.md files." },
41
43
  { "upstreamSkill": "writing-beats", "upstreamPath": "skills/in-progress/writing-beats/SKILL.md", "reason": "Experimental editorial workflow is outside this package's engineering workflow scope." },
42
44
  { "upstreamSkill": "writing-fragments", "upstreamPath": "skills/in-progress/writing-fragments/SKILL.md", "reason": "Experimental editorial workflow is outside this package's engineering workflow scope." },
43
45
  { "upstreamSkill": "writing-shape", "upstreamPath": "skills/in-progress/writing-shape/SKILL.md", "reason": "Experimental editorial workflow is outside this package's engineering workflow scope." },
package/UPSTREAM.md DELETED
@@ -1,63 +0,0 @@
1
- # Upstream synchronization
2
-
3
- ## Recorded revisions
4
-
5
- - Repository: `mattpocock/skills`
6
- - Compared commit: `6654f6b60cd9d5be8b54c6fafe44346dabeb3b76`
7
- - Comparison tag: `v1.2.3`
8
- - Resolved tag commit: `6acc160e4e0cd062dbbbd7a1b26ae92855edf07e`
9
- - Latest checked commit: `3cca18b368ae95cdbdebbff572ccafa662551015`
10
-
11
- These values are deliberately separate. The compared commit is the content
12
- baseline, the comparison tag is the human-readable release marker, the resolved
13
- tag commit records what that tag pointed to, and the latest checked commit is
14
- the newest upstream tree reviewed for additions or removals.
15
-
16
- The machine-readable selection is in
17
- [`upstream-selection.json`](upstream-selection.json). It classifies every
18
- upstream `SKILL.md` present at the latest checked commit as either promoted or
19
- intentionally excluded. Each promoted skill names its local catalog capability,
20
- plain Markdown resource, and upstream invocation mode. Each exclusion carries a
21
- reason; Claude Code hooks and background-agent commands are identified as
22
- host-specific rather than silently ignored.
23
-
24
- ## Harness architecture
25
-
26
- Upstream distributes nested `SKILL.md` files. Pi recursively discovers any
27
- such file under a declared skill root, which exposes generic names such as
28
- `tdd`, `code-review`, and `research` alongside unrelated installed skills.
29
-
30
- This package exposes one extension command, `/matt-pocock`. The extension
31
- selects and injects plain Markdown procedures from `procedures/`; none are Pi
32
- skills, and the package contains no `SKILL.md` file.
33
-
34
- ## Sync rules
35
-
36
- 1. Clone upstream separately and inspect both the compared and latest checked
37
- commits before changing local resources.
38
- 2. Run the local metadata check without an upstream checkout:
39
-
40
- ```bash
41
- node scripts/check-upstream-sync.mjs
42
- ```
43
-
44
- 3. Run the complete inventory, invocation, and content comparison against an
45
- already-cloned checkout. The checker never clones or fetches:
46
-
47
- ```bash
48
- node scripts/check-upstream-sync.mjs --upstream /path/to/mattpocock-skills
49
- ```
50
-
51
- 4. Copy selected workflows and supporting files into `procedures/`; never
52
- overwrite the extension harness wholesale.
53
- 5. Rename copied upstream `SKILL.md` files to their catalog id plus `.md`.
54
- Strip frontmatter, and never ship a `SKILL.md` file.
55
- 6. Remove Claude-only frontmatter, tools, paths, and invocation syntax from
56
- copied content. Replace cross-procedure calls with relative links.
57
- 7. Preserve the local BDD/TDD split and Pi-specific interaction,
58
- collaboration, instruction-file, and git-agent guidance. An adapted content
59
- result is expected when these local contracts differ from upstream.
60
- 8. Classify every new or removed upstream skill in
61
- `upstream-selection.json`, then update the four revision fields together.
62
- 9. Re-run the harness feature, isolated sync tests, package tests, and package
63
- dry-run after a sync.
@@ -1,60 +0,0 @@
1
- # CONTEXT.md Format
2
-
3
- ## Structure
4
-
5
- ```md
6
- # {Context Name}
7
-
8
- {One or two sentence description of what this context is and why it exists.}
9
-
10
- ## Language
11
-
12
- **Order**:
13
- {A one or two sentence description of the term}
14
- _Avoid_: Purchase, transaction
15
-
16
- **Invoice**:
17
- A request for payment sent to a customer after delivery.
18
- _Avoid_: Bill, payment request
19
-
20
- **Customer**:
21
- A person or organization that places orders.
22
- _Avoid_: Client, buyer, account
23
- ```
24
-
25
- ## Rules
26
-
27
- - **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`.
28
- - **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does.
29
- - **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs.
30
- - **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine.
31
-
32
- ## Single vs multi-context repos
33
-
34
- **Single context (most repos):** One `CONTEXT.md` at the repo root.
35
-
36
- **Multiple contexts:** A `CONTEXT-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other:
37
-
38
- ```md
39
- # Context Map
40
-
41
- ## Contexts
42
-
43
- - [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders
44
- - [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments
45
- - [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping
46
-
47
- ## Relationships
48
-
49
- - **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking
50
- - **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices
51
- - **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money`
52
- ```
53
-
54
- The skill infers which structure applies:
55
-
56
- - If `CONTEXT-MAP.md` exists, read it to find contexts
57
- - If only a root `CONTEXT.md` exists, single context
58
- - If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved
59
-
60
- When multiple contexts exist, infer which one the current topic relates to. If unclear, ask.
@@ -1,45 +0,0 @@
1
- # Issue tracker: GitHub
2
-
3
- Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all operations.
4
-
5
- ## Conventions
6
-
7
- - **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies.
8
- - **Read an issue**: `gh issue view <number> --comments`, filtering comments by `jq` and also fetching labels.
9
- - **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters.
10
- - **Comment on an issue**: `gh issue comment <number> --body "..."`
11
- - **Apply / remove labels**: `gh issue edit <number> --add-label "..."` / `--remove-label "..."`
12
- - **Close**: `gh issue close <number> --comment "..."`
13
-
14
- Infer the repo from `git remote -v` — `gh` does this automatically when run inside a clone.
15
-
16
- ## Pull requests as a triage surface
17
-
18
- **PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; [triage](triage.md) reads this flag.)_
19
-
20
- When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents:
21
-
22
- - **Read a PR**: `gh pr view <number> --comments` and `gh pr diff <number>` for the diff.
23
- - **List external PRs for triage**: `gh pr list --state open --json number,title,body,labels,author,authorAssociation,comments` then keep only `authorAssociation` of `CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`, or `NONE` (drop `OWNER`/`MEMBER`/`COLLABORATOR`).
24
- - **Comment / label / close**: `gh pr comment`, `gh pr edit --add-label`/`--remove-label`, `gh pr close`.
25
-
26
- GitHub shares one number space across issues and PRs, so a bare `#42` may be either — resolve with `gh pr view 42` and fall back to `gh issue view 42`.
27
-
28
- ## When a skill says "publish to the issue tracker"
29
-
30
- Create a GitHub issue.
31
-
32
- ## When a skill says "fetch the relevant ticket"
33
-
34
- Run `gh issue view <number> --comments`.
35
-
36
- ## Wayfinding operations
37
-
38
- Used by [wayfinder](wayfinder.md). The **map** is a single issue with **child** issues as tickets.
39
-
40
- - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`.
41
- - **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #<map>` at the top of the child body. Labels: `wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev.
42
- - **Blocking**: GitHub's **native issue dependencies** — the canonical, UI-visible representation. Add an edge with `gh api --method POST repos/<owner>/<repo>/issues/<child>/dependencies/blocked_by -F issue_id=<blocker-db-id>`, where `<blocker-db-id>` is the blocker's numeric **database id** (`gh api repos/<owner>/<repo>/issues/<n> --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only — the live gate). Where dependencies aren't available, fall back to a `Blocked by: #<n>, #<n>` line at the top of the child body. A ticket is unblocked when every blocker is closed.
43
- - **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins.
44
- - **Claim**: `gh issue edit <n> --add-assignee @me` — the session's first write.
45
- - **Resolve**: `gh issue comment <n> --body "<answer>"`, then `gh issue close <n>`, then append a context pointer (gist + link) to the map's Decisions-so-far.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes