@stackmemoryai/stackmemory 1.10.4 → 1.12.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 (95) hide show
  1. package/README.md +104 -23
  2. package/dist/src/cli/claude-sm.js +266 -84
  3. package/dist/src/cli/codex-sm.js +185 -33
  4. package/dist/src/cli/commands/bench.js +209 -2
  5. package/dist/src/cli/commands/cache.js +126 -0
  6. package/dist/src/cli/commands/daemon.js +41 -0
  7. package/dist/src/cli/commands/handoff.js +40 -9
  8. package/dist/src/cli/commands/onboard.js +70 -3
  9. package/dist/src/cli/commands/optimize.js +117 -0
  10. package/dist/src/cli/commands/orchestrate.js +230 -5
  11. package/dist/src/cli/commands/orchestrator.js +312 -24
  12. package/dist/src/cli/commands/pack.js +322 -0
  13. package/dist/src/cli/commands/search.js +40 -1
  14. package/dist/src/cli/commands/setup.js +177 -7
  15. package/dist/src/cli/commands/skills.js +10 -1
  16. package/dist/src/cli/commands/state.js +265 -0
  17. package/dist/src/cli/commands/wiki.js +33 -0
  18. package/dist/src/cli/gemini-sm.js +19 -29
  19. package/dist/src/cli/index.js +90 -29
  20. package/dist/src/cli/opencode-sm.js +38 -21
  21. package/dist/src/cli/utils/determinism-watcher.js +66 -0
  22. package/dist/src/cli/utils/real-cli-bin.js +44 -0
  23. package/dist/src/core/cache/content-cache.js +238 -0
  24. package/dist/src/core/cache/index.js +11 -0
  25. package/dist/src/core/cache/token-estimator.js +16 -0
  26. package/dist/src/core/context/frame-database.js +38 -30
  27. package/dist/src/core/cross-search/cross-project-search.js +269 -0
  28. package/dist/src/core/{merge → cross-search}/index.js +6 -4
  29. package/dist/src/core/database/sqlite-adapter.js +0 -83
  30. package/dist/src/core/extensions/provider-adapter.js +5 -0
  31. package/dist/src/core/models/model-router.js +22 -2
  32. package/dist/src/core/monitoring/logger.js +2 -1
  33. package/dist/src/core/optimization/trace-optimizer.js +413 -0
  34. package/dist/src/core/provenance/confidence-scorer.js +128 -0
  35. package/dist/src/core/provenance/index.js +40 -0
  36. package/dist/src/core/provenance/provenance-store.js +194 -0
  37. package/dist/src/core/provenance/types.js +82 -0
  38. package/dist/src/core/session/project-handoff.js +64 -0
  39. package/dist/src/core/session/session-manager.js +28 -0
  40. package/dist/src/core/shared-state/canonical-store.js +564 -0
  41. package/dist/src/core/skill-packs/index.js +18 -0
  42. package/dist/src/core/skill-packs/parser.js +42 -0
  43. package/dist/src/core/skill-packs/registry.js +224 -0
  44. package/dist/src/core/skill-packs/types.js +66 -0
  45. package/dist/src/core/trace/trace-event-store.js +282 -0
  46. package/dist/src/core/trace/trace-event.js +4 -0
  47. package/dist/src/core/wiki/wiki-compiler.js +219 -0
  48. package/dist/src/daemon/daemon-config.js +7 -0
  49. package/dist/src/daemon/services/github-service.js +126 -0
  50. package/dist/src/daemon/unified-daemon.js +30 -0
  51. package/dist/src/features/sweep/pty-wrapper.js +13 -5
  52. package/dist/src/hooks/schemas.js +2 -0
  53. package/dist/src/integrations/claude-code/subagent-client.js +89 -0
  54. package/dist/src/integrations/github/pr-state.js +158 -0
  55. package/dist/src/integrations/linear/client.js +4 -1
  56. package/dist/src/integrations/mcp/handlers/cross-search-handlers.js +188 -0
  57. package/dist/src/integrations/mcp/handlers/index.js +40 -59
  58. package/dist/src/integrations/mcp/server.js +425 -311
  59. package/dist/src/integrations/mcp/tool-alias-registry.js +370 -0
  60. package/dist/src/integrations/mcp/tool-definitions.js +98 -229
  61. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +3 -40
  62. package/dist/src/integrations/ralph/learning/pattern-learner.js +1 -20
  63. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -2
  64. package/dist/src/mcp/stackmemory-mcp-server.js +315 -0
  65. package/dist/src/orchestrators/multimodal/determinism.js +243 -0
  66. package/dist/src/orchestrators/multimodal/harness.js +147 -77
  67. package/dist/src/orchestrators/multimodal/providers.js +44 -3
  68. package/dist/src/utils/hook-installer.js +8 -8
  69. package/package.json +10 -1
  70. package/packs/coding/python-fastapi/instructions.md +60 -0
  71. package/packs/coding/python-fastapi/pack.yaml +28 -0
  72. package/packs/coding/typescript-react/instructions.md +47 -0
  73. package/packs/coding/typescript-react/pack.yaml +28 -0
  74. package/packs/core/commands/capture.md +32 -0
  75. package/packs/core/commands/learn.md +73 -0
  76. package/packs/core/commands/next.md +36 -0
  77. package/packs/core/commands/restart.md +58 -0
  78. package/packs/core/commands/restore.md +29 -0
  79. package/packs/core/commands/start.md +57 -0
  80. package/packs/core/commands/stop.md +65 -0
  81. package/packs/core/commands/summary.md +40 -0
  82. package/packs/core/manifest.json +24 -0
  83. package/packs/ops/decision-recovery/instructions.md +65 -0
  84. package/packs/ops/decision-recovery/pack.yaml +89 -0
  85. package/templates/claude-hooks/doc-ingest.js +76 -0
  86. package/dist/src/cli/commands/team.js +0 -168
  87. package/dist/src/core/context/shared-context-layer.js +0 -620
  88. package/dist/src/core/context/stack-merge-resolver.js +0 -748
  89. package/dist/src/core/merge/conflict-detector.js +0 -430
  90. package/dist/src/core/merge/resolution-engine.js +0 -557
  91. package/dist/src/core/merge/stack-diff.js +0 -531
  92. package/dist/src/core/merge/unified-merge-resolver.js +0 -302
  93. package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
  94. package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
  95. /package/dist/src/core/{merge → cache}/types.js +0 -0
@@ -51,6 +51,45 @@ function heuristicPlan(input) {
51
51
  ]
52
52
  };
53
53
  }
54
+ function deterministicCritique(args) {
55
+ const issues = [];
56
+ const suggestions = [];
57
+ if (!args.ok) {
58
+ issues.push("Implementer command failed");
59
+ suggestions.push("Fix the command invocation before retrying");
60
+ }
61
+ if (args.diff.includes("<<<<<<<") || args.diff.includes(">>>>>>>")) {
62
+ issues.push("Merge conflict markers detected in diff");
63
+ suggestions.push("Resolve conflict markers before approval");
64
+ }
65
+ if (args.checks && !args.checks.lintOk) {
66
+ issues.push("Lint checks failed");
67
+ suggestions.push("Address lint failures before approval");
68
+ }
69
+ if (args.checks && !args.checks.testsOk) {
70
+ issues.push("Tests failed");
71
+ suggestions.push("Fix failing tests before approval");
72
+ }
73
+ const failedVerifications = args.checks?.verifications.filter((verification) => !verification.ok) || [];
74
+ if (failedVerifications.length > 0) {
75
+ issues.push(
76
+ `Verification command failed: ${failedVerifications[0]?.command}`
77
+ );
78
+ suggestions.push(
79
+ "Use the verification output as the primary repro signal and fix the root cause"
80
+ );
81
+ }
82
+ if (!args.diff || args.diff.startsWith("(no changes detected)")) {
83
+ suggestions.push(
84
+ "No code changes detected; verify the task can be satisfied without edits"
85
+ );
86
+ }
87
+ return {
88
+ approved: issues.length === 0,
89
+ issues,
90
+ suggestions
91
+ };
92
+ }
54
93
  async function runSpike(input, options = {}) {
55
94
  const plannerSystem = `You write concise, actionable implementation plans. Output raw JSON only (no markdown code fences). Schema: { "summary": "string", "steps": [{ "id": "step-1", "title": "string", "rationale": "string", "acceptanceCriteria": ["string"] }], "risks": ["string"] }`;
56
95
  const contextSummary = getLocalContextSummary(input.repoPath);
@@ -61,23 +100,28 @@ ${contextSummary}
61
100
  Constraints: Keep the plan minimal and implementable in a single PR.`;
62
101
  const t0 = Date.now();
63
102
  let plan;
64
- try {
65
- const raw = await callClaude(plannerPrompt, {
66
- model: options.plannerModel,
67
- system: plannerSystem
68
- });
103
+ if (options.deterministicFixture) {
104
+ plan = heuristicPlan(input);
105
+ } else {
69
106
  try {
70
- const cleaned = raw.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
71
- plan = JSON.parse(cleaned);
107
+ const raw = await callClaude(plannerPrompt, {
108
+ model: options.plannerModel,
109
+ system: plannerSystem
110
+ });
111
+ try {
112
+ const cleaned = raw.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
113
+ plan = JSON.parse(cleaned);
114
+ } catch {
115
+ plan = heuristicPlan(input);
116
+ }
72
117
  } catch {
73
118
  plan = heuristicPlan(input);
74
119
  }
75
- } catch {
76
- plan = heuristicPlan(input);
77
120
  }
78
121
  const planLatencyMs = Date.now() - t0;
79
122
  const implementer = options.implementer || "codex";
80
123
  const maxIters = Math.max(1, options.maxIters ?? 2);
124
+ const verificationCommands = options.verificationCommands || [];
81
125
  const iterations = [];
82
126
  let approved = false;
83
127
  let lastCommand = "";
@@ -89,10 +133,14 @@ Constraints: Keep the plan minimal and implementable in a single PR.`;
89
133
  };
90
134
  for (let i = 0; i < maxIters; i++) {
91
135
  const stepsList = plan.steps.map((s, idx) => `${idx + 1}. ${s.title}`).join("\n");
136
+ const verificationPrompt = verificationCommands.length > 0 ? `
137
+
138
+ Verification commands that must pass:
139
+ ${verificationCommands.map((command) => `- ${command}`).join("\n")}` : "\n\nIf this task fixes uncertain behavior, first create or identify a deterministic repro/test/trace that fails for the current behavior, then use it to guide the fix.";
92
140
  const basePrompt = `Implement the following plan:
93
141
  ${stepsList}
94
142
 
95
- Keep changes minimal and focused. Avoid unrelated edits.`;
143
+ Keep changes minimal and focused. Avoid unrelated edits.${verificationPrompt}`;
96
144
  const refine = i === 0 ? "" : `
97
145
  Incorporate reviewer suggestions: ${lastCritique.suggestions.join("; ")}`;
98
146
  const implPrompt = basePrompt + refine;
@@ -116,14 +164,20 @@ Incorporate reviewer suggestions: ${lastCritique.suggestions.join("; ")}`;
116
164
  _lastOutput = impl.output;
117
165
  }
118
166
  const diff = options.dryRun !== false ? "(dry run \u2014 no diff)" : captureGitDiff(input.repoPath);
119
- const checks = options.dryRun !== false ? null : runPostImplChecks(input.repoPath);
167
+ const checks = options.dryRun !== false ? null : runPostImplChecks(input.repoPath, verificationCommands);
168
+ const verificationSection = checks && checks.verifications.length > 0 ? `
169
+ Custom verification:
170
+ ${checks.verifications.map(
171
+ (verification) => ` - ${verification.ok ? "PASS" : "FAIL"} ${verification.command}
172
+ ${verification.output}`
173
+ ).join("\n")}` : "";
120
174
  const checksSection = checks ? `
121
175
 
122
176
  Post-implementation checks:
123
177
  Lint: ${checks.lintOk ? "PASS" : "FAIL"}
124
178
  ${checks.lintOutput}
125
179
  Tests: ${checks.testsOk ? "PASS" : "FAIL"}
126
- ${checks.testOutput}` : "";
180
+ ${checks.testOutput}${verificationSection}` : "";
127
181
  const criticSystem = `You are a strict code reviewer. Review the git diff against the plan. Check for: correctness, missing steps, unrelated changes, bugs, security issues. Also review lint and test results if provided. Return raw JSON only (no markdown fences): { "approved": boolean, "issues": ["string"], "suggestions": ["string"] }`;
128
182
  const criticPrompt = `Plan: ${plan.summary}
129
183
  Acceptance criteria:
@@ -134,25 +188,35 @@ Implementer exit: ${ok ? "success" : "failed"}
134
188
 
135
189
  Git diff:
136
190
  ${diff}${checksSection}`;
137
- try {
138
- const raw = await callClaude(criticPrompt, {
139
- model: options.reviewerModel,
140
- system: criticSystem
191
+ if (options.deterministicFixture) {
192
+ lastCritique = deterministicCritique({
193
+ plan,
194
+ ok,
195
+ diff,
196
+ checks
141
197
  });
142
- const cleaned = raw.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
143
- lastCritique = JSON.parse(cleaned);
144
- } catch {
145
- lastCritique = {
146
- approved: ok,
147
- issues: ok ? [] : ["Critique failed"],
148
- suggestions: []
149
- };
198
+ } else {
199
+ try {
200
+ const raw = await callClaude(criticPrompt, {
201
+ model: options.reviewerModel,
202
+ system: criticSystem
203
+ });
204
+ const cleaned = raw.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
205
+ lastCritique = JSON.parse(cleaned);
206
+ } catch {
207
+ lastCritique = {
208
+ approved: ok,
209
+ issues: ok ? [] : ["Critique failed"],
210
+ suggestions: []
211
+ };
212
+ }
150
213
  }
151
214
  iterations.push({
152
215
  command: lastCommand,
153
216
  ok,
154
217
  outputPreview: diff.slice(0, 2e3),
155
- critique: lastCritique
218
+ critique: lastCritique,
219
+ checks
156
220
  });
157
221
  if (lastCritique.approved) {
158
222
  approved = true;
@@ -177,62 +241,64 @@ ${diff}${checksSection}`;
177
241
  editFuzzyFallbacks: editMetrics.editFuzzyFallbacks,
178
242
  contextTokens: Math.ceil(finalDiff.length / 4)
179
243
  };
180
- try {
181
- const dir = options.auditDir || path.join(input.repoPath, ".stackmemory", "build");
182
- fs.mkdirSync(dir, { recursive: true });
183
- const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
184
- const file = path.join(dir, `spike-${stamp}.json`);
185
- fs.writeFileSync(
186
- file,
187
- JSON.stringify(
188
- {
189
- input,
190
- options: { ...options, auditDir: void 0 },
191
- plan,
192
- iterations,
193
- metrics: runMetrics
194
- },
195
- null,
196
- 2
197
- )
198
- );
199
- const metricsFile = path.join(dir, "harness-metrics.jsonl");
200
- fs.appendFileSync(metricsFile, JSON.stringify(runMetrics) + "\n");
244
+ if (options.persistAudit !== false) {
201
245
  try {
202
- const lines = fs.readFileSync(metricsFile, "utf-8").split("\n").filter((l) => l.trim());
203
- const recent = lines.slice(-10).map((l) => JSON.parse(l));
204
- if (recent.length >= 3) {
205
- const summary = summarizeRuns(recent);
206
- if (summary.approvalRate < HARNESS_TARGETS.firstPassApprovalRate) {
207
- feedbackLoops.fire(
208
- "harnessRegression",
209
- "metrics_append",
210
- {
211
- metric: "approvalRate",
212
- current: summary.approvalRate,
213
- target: HARNESS_TARGETS.firstPassApprovalRate,
214
- window: recent.length
215
- },
216
- "regression_alert"
217
- );
218
- }
219
- if (summary.p95TotalLatencyMs > HARNESS_TARGETS.totalLatencyP95Ms) {
220
- feedbackLoops.fire(
221
- "harnessRegression",
222
- "metrics_append",
223
- {
224
- metric: "totalLatencyP95",
225
- current: summary.p95TotalLatencyMs,
226
- target: HARNESS_TARGETS.totalLatencyP95Ms,
227
- window: recent.length
228
- },
229
- "regression_alert"
230
- );
246
+ const dir = options.auditDir || path.join(input.repoPath, ".stackmemory", "build");
247
+ fs.mkdirSync(dir, { recursive: true });
248
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
249
+ const file = path.join(dir, `spike-${stamp}.json`);
250
+ fs.writeFileSync(
251
+ file,
252
+ JSON.stringify(
253
+ {
254
+ input,
255
+ options: { ...options, auditDir: void 0 },
256
+ plan,
257
+ iterations,
258
+ metrics: runMetrics
259
+ },
260
+ null,
261
+ 2
262
+ )
263
+ );
264
+ const metricsFile = path.join(dir, "harness-metrics.jsonl");
265
+ fs.appendFileSync(metricsFile, JSON.stringify(runMetrics) + "\n");
266
+ try {
267
+ const lines = fs.readFileSync(metricsFile, "utf-8").split("\n").filter((l) => l.trim());
268
+ const recent = lines.slice(-10).map((l) => JSON.parse(l));
269
+ if (recent.length >= 3) {
270
+ const summary = summarizeRuns(recent);
271
+ if (summary.approvalRate < HARNESS_TARGETS.firstPassApprovalRate) {
272
+ feedbackLoops.fire(
273
+ "harnessRegression",
274
+ "metrics_append",
275
+ {
276
+ metric: "approvalRate",
277
+ current: summary.approvalRate,
278
+ target: HARNESS_TARGETS.firstPassApprovalRate,
279
+ window: recent.length
280
+ },
281
+ "regression_alert"
282
+ );
283
+ }
284
+ if (summary.p95TotalLatencyMs > HARNESS_TARGETS.totalLatencyP95Ms) {
285
+ feedbackLoops.fire(
286
+ "harnessRegression",
287
+ "metrics_append",
288
+ {
289
+ metric: "totalLatencyP95",
290
+ current: summary.p95TotalLatencyMs,
291
+ target: HARNESS_TARGETS.totalLatencyP95Ms,
292
+ window: recent.length
293
+ },
294
+ "regression_alert"
295
+ );
296
+ }
231
297
  }
298
+ } catch {
232
299
  }
233
300
  } catch {
234
301
  }
235
- } catch {
236
302
  }
237
303
  if (options.record) {
238
304
  void recordContext(
@@ -265,7 +331,8 @@ ${diff}${checksSection}`;
265
331
  commands: iterations.map((it) => it.command)
266
332
  },
267
333
  critique: lastCritique,
268
- iterations
334
+ iterations,
335
+ verification: iterations.at(-1)?.checks || null
269
336
  };
270
337
  }
271
338
  const runPlanAndCode = runSpike;
@@ -341,6 +408,9 @@ Repo: ${input.repoPath}
341
408
  Notes: ${input.contextNotes || "(none)"}
342
409
  ${contextSummary}
343
410
  Constraints: Keep the plan minimal and implementable in a single PR.`;
411
+ if (options.deterministicFixture) {
412
+ return heuristicPlan(input);
413
+ }
344
414
  try {
345
415
  const raw = await callClaude(plannerPrompt, {
346
416
  model: options.plannerModel,
@@ -115,7 +115,7 @@ ${newFiles.join("\n")}`;
115
115
  return "(git diff failed)";
116
116
  }
117
117
  }
118
- function runPostImplChecks(cwd) {
118
+ function runPostImplChecks(cwd, verificationCommands = []) {
119
119
  const maxOutput = 2e3;
120
120
  function truncate(s) {
121
121
  if (s.length <= maxOutput) return s;
@@ -152,7 +152,47 @@ function runPostImplChecks(cwd) {
152
152
  } catch (e) {
153
153
  testOutput = truncate(e instanceof Error ? e.message : String(e));
154
154
  }
155
- return { lintOk, lintOutput, testsOk, testOutput };
155
+ return {
156
+ lintOk,
157
+ lintOutput,
158
+ testsOk,
159
+ testOutput,
160
+ verifications: runVerificationCommands(cwd, verificationCommands)
161
+ };
162
+ }
163
+ function runVerificationCommands(cwd, commands, options = {}) {
164
+ const timeout = options.timeoutMs ?? 12e4;
165
+ const maxOutput = options.maxOutput ?? 4e3;
166
+ const truncate = (value) => {
167
+ if (value.length <= maxOutput) return value;
168
+ return value.slice(0, maxOutput) + `
169
+ ... (truncated, ${value.length} total chars)`;
170
+ };
171
+ return commands.map((command) => command.trim()).filter(Boolean).map((command) => {
172
+ try {
173
+ const result = spawnSync(command, {
174
+ cwd,
175
+ encoding: "utf8",
176
+ shell: true,
177
+ timeout,
178
+ maxBuffer: Math.max(maxOutput * 4, 1024 * 1024)
179
+ });
180
+ const output = truncate((result.stdout || "") + (result.stderr || ""));
181
+ return {
182
+ command,
183
+ ok: result.status === 0,
184
+ output: output || (result.status === 0 ? "(command completed with no output)" : `(command failed with exit ${result.status ?? "unknown"})`)
185
+ };
186
+ } catch (error) {
187
+ return {
188
+ command,
189
+ ok: false,
190
+ output: truncate(
191
+ error instanceof Error ? error.message : String(error)
192
+ )
193
+ };
194
+ }
195
+ });
156
196
  }
157
197
  function parseEditMetrics(diff) {
158
198
  if (!diff || diff.startsWith("(")) {
@@ -204,5 +244,6 @@ export {
204
244
  captureGitDiff,
205
245
  implementWithClaude,
206
246
  parseEditMetrics,
207
- runPostImplChecks
247
+ runPostImplChecks,
248
+ runVerificationCommands
208
249
  };
@@ -32,14 +32,6 @@ const CANONICAL_HOOKS = [
32
32
  commandPrefix: "node",
33
33
  required: true
34
34
  },
35
- {
36
- scriptName: "cord-trace.js",
37
- eventType: "PostToolUse",
38
- matcher: "mcp__.*__cord_(spawn|fork|complete|ask|tree)",
39
- timeout: 2,
40
- commandPrefix: "node",
41
- required: true
42
- },
43
35
  {
44
36
  scriptName: "theory-capture.js",
45
37
  eventType: "PostToolUse",
@@ -89,6 +81,14 @@ const CANONICAL_HOOKS = [
89
81
  timeout: 10,
90
82
  commandPrefix: "node",
91
83
  required: false
84
+ },
85
+ {
86
+ scriptName: "doc-ingest.js",
87
+ eventType: "PostToolUse",
88
+ matcher: "WebFetch",
89
+ timeout: 15,
90
+ commandPrefix: "node",
91
+ required: false
92
92
  }
93
93
  ];
94
94
  const DEAD_HOOKS = ["sms-response-handler.js"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackmemoryai/stackmemory",
3
- "version": "1.10.4",
3
+ "version": "1.12.0",
4
4
  "description": "Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, and automatic hooks.",
5
5
  "engines": {
6
6
  "node": ">=20.0.0",
@@ -45,6 +45,7 @@
45
45
  "scripts/verify-dist.cjs",
46
46
  "scripts/smoke-init-db.sh",
47
47
  "templates",
48
+ "packs",
48
49
  "README.md",
49
50
  "LICENSE"
50
51
  ],
@@ -114,6 +115,11 @@
114
115
  "test:run": "vitest run",
115
116
  "test:pre-publish": "./scripts/test-pre-publish-quick.sh",
116
117
  "test:pre-commit": "vitest related --run --reporter=dot --silent --bail=1",
118
+ "determinism:smoke": "node --import tsx src/cli/index.ts bench determinism --task \"Determinism probe\" --runs 5",
119
+ "determinism:watch": "node --import tsx src/cli/index.ts bench determinism --task \"Determinism probe\" --runs 3 --watch",
120
+ "determinism:latest": "node --import tsx src/cli/index.ts bench determinism --latest --json",
121
+ "determinism:test": "npx vitest run src/orchestrators/multimodal/__tests__/determinism.test.ts --reporter=dot",
122
+ "determinism:pre-commit": "bash scripts/determinism-pre-commit.sh",
117
123
  "prepublishOnly": "npm run build && npm run verify:dist && npm run test:pre-publish",
118
124
  "quality": "npm run lint && npm run test:run && npm run build",
119
125
  "dev": "tsx watch src/integrations/mcp/server.ts",
@@ -136,6 +142,9 @@
136
142
  "sync:start": "node scripts/background-sync-manager.js",
137
143
  "sync:setup": "./scripts/setup-background-sync.sh",
138
144
  "eval:cord": "npx tsx scripts/evals/cord-vs-flat-eval.ts",
145
+ "gepa:eval": "node scripts/gepa/eval-phases.js",
146
+ "gepa:eval:json": "node scripts/gepa/eval-phases.js --json",
147
+ "gepa:mine": "node scripts/gepa/gold/mine-traces.js",
139
148
  "prepare": "echo 'Prepare step completed'",
140
149
  "verify:dist": "node scripts/verify-dist.cjs",
141
150
  "test:smoke-db": "bash scripts/smoke-init-db.sh",
@@ -0,0 +1,60 @@
1
+ # coding/python-fastapi
2
+
3
+ ## Python Conventions
4
+
5
+ - **Python 3.11+.** Use modern syntax: `match/case`, `type` aliases, `ExceptionGroup`.
6
+ - **Type hints everywhere.** All function signatures, return types, and class attributes. Use `from __future__ import annotations` for forward references.
7
+ - **Pydantic v2 for data validation.** `BaseModel` for schemas, `model_validator` for complex validation. Never use raw dicts for API I/O.
8
+ - **Async by default.** Use `async def` for route handlers and DB operations. Use `asyncio.gather` for concurrent I/O.
9
+ - **No global mutable state.** Use dependency injection via FastAPI's `Depends()`.
10
+ - **Naming.** snake_case for functions/variables. PascalCase for classes. UPPER_SNAKE for constants.
11
+
12
+ ## FastAPI Patterns
13
+
14
+ - **Router per domain.** `app/routers/users.py`, `app/routers/items.py`. Mount with `app.include_router()`.
15
+ - **Pydantic schemas for I/O.** Separate `Create`, `Update`, `Response` schemas. Never expose ORM models directly.
16
+ - **Dependency injection.** DB sessions, auth, config — all via `Depends()`. Define in `app/dependencies.py`.
17
+ - **Status codes.** Use `status.HTTP_201_CREATED` for creates, `HTTP_204_NO_CONTENT` for deletes. Raise `HTTPException` with proper codes.
18
+ - **Background tasks.** Use `BackgroundTasks` for fire-and-forget. Use Celery/ARQ for durable jobs.
19
+ - **Middleware.** CORS, request logging, error handling. Define in `app/middleware.py`.
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ app/
25
+ main.py # FastAPI app instance + startup
26
+ core/
27
+ config.py # Settings via pydantic-settings
28
+ security.py # Auth utilities
29
+ routers/ # APIRouter modules
30
+ models/ # SQLAlchemy/SQLModel ORM models
31
+ schemas/ # Pydantic request/response models
32
+ dependencies.py # Shared Depends() callables
33
+ middleware.py # Middleware stack
34
+ tests/
35
+ conftest.py # Fixtures (test client, DB)
36
+ test_*.py # Test modules
37
+ ```
38
+
39
+ ## Database
40
+
41
+ - **SQLAlchemy 2.0 style.** `select()` not `query()`. Mapped classes with `Mapped[]` annotations.
42
+ - **Alembic for migrations.** Auto-generate with `alembic revision --autogenerate`. Never edit the DB schema manually.
43
+ - **Session management.** Async sessions via `async_sessionmaker`. Yield in dependency.
44
+ - **Connection pooling.** Configure `pool_size`, `max_overflow` in production.
45
+
46
+ ## Testing
47
+
48
+ - **pytest + httpx.** Use `AsyncClient` with `app` for integration tests.
49
+ - **Fixtures for DB.** Create test database, run migrations, yield session, rollback.
50
+ - **Factory pattern for test data.** Use `factory_boy` or simple fixture functions.
51
+ - **Test the API, not internals.** Call endpoints via client, assert response shape + status.
52
+
53
+ ## Common Anti-Patterns to Catch
54
+
55
+ - Synchronous DB calls in async handlers → blocks the event loop
56
+ - Raw SQL without parameterization → SQL injection risk
57
+ - Returning ORM models from endpoints → use Pydantic response models
58
+ - Missing `async` on route handlers with I/O → blocks worker threads
59
+ - Hardcoded secrets → use environment variables via pydantic-settings
60
+ - Missing input validation → always validate via Pydantic schemas
@@ -0,0 +1,28 @@
1
+ name: coding/python-fastapi
2
+ version: 1.0.0
3
+ description: Python + FastAPI conventions, patterns, and guardrails for AI coding agents
4
+ author: stackmemory
5
+ license: MIT
6
+ runtime:
7
+ type: local
8
+ ingestion:
9
+ sources: []
10
+ ontology:
11
+ entities:
12
+ - endpoint
13
+ - model
14
+ - schema
15
+ - dependency
16
+ - middleware
17
+ relations:
18
+ - handles
19
+ - validates
20
+ - depends-on
21
+ mcp:
22
+ tools: []
23
+ examples:
24
+ - input: "Create a CRUD API endpoint"
25
+ output: "Use Pydantic models for request/response, dependency injection for DB session, proper HTTP status codes, async handlers"
26
+ - input: "How should I structure a FastAPI project?"
27
+ output: "app/ with routers/, models/, schemas/, dependencies/, core/ (config, security). Use APIRouter per domain."
28
+ instructions: instructions.md
@@ -0,0 +1,47 @@
1
+ # coding/typescript-react
2
+
3
+ ## TypeScript Conventions
4
+
5
+ - **Strict mode always.** `"strict": true` in tsconfig.json. No `any` unless genuinely unavoidable — use `unknown` and narrow.
6
+ - **ESM imports.** Always add `.js` extension to relative imports in ESM projects. Use `type` imports for type-only references.
7
+ - **Prefer interfaces** for object shapes. Use `type` for unions, intersections, and mapped types.
8
+ - **No enums.** Use `as const` objects or union types instead. Enums have runtime cost and poor tree-shaking.
9
+ - **Error handling.** Return `undefined` over throwing. If you must throw, use typed error classes. Never `catch (e: any)`.
10
+ - **Naming.** PascalCase for types/interfaces/components. camelCase for variables/functions. UPPER_SNAKE for constants.
11
+
12
+ ## React Patterns
13
+
14
+ - **Functional components only.** No class components.
15
+ - **Custom hooks for data fetching.** Extract `useQuery`/`useMutation` patterns into `use*` hooks. Never fetch in component body.
16
+ - **State management.** useState for local, useReducer for complex local, Context for cross-tree, Zustand/Jotai for global.
17
+ - **Memoization.** Don't prematurely memo. Use `React.memo` only when profiler shows re-render cost. `useMemo`/`useCallback` for referential stability when passed to children.
18
+ - **Keys.** Never use array index as key. Use stable IDs from data.
19
+ - **Error boundaries.** Wrap route-level components. Use `react-error-boundary` library.
20
+
21
+ ## File Structure
22
+
23
+ ```
24
+ src/
25
+ components/ # Shared UI components
26
+ features/ # Feature-scoped modules (components + hooks + types)
27
+ hooks/ # Shared custom hooks
28
+ lib/ # Non-React utilities
29
+ types/ # Shared type definitions
30
+ routes/ # Route components (if not using file-based routing)
31
+ ```
32
+
33
+ ## Testing
34
+
35
+ - **Vitest or Jest** for unit tests. React Testing Library for component tests.
36
+ - **Test behavior, not implementation.** Query by role/text, not test-id.
37
+ - **No snapshot tests** unless testing serialized output.
38
+ - **Mock at boundaries.** Mock API calls (MSW), not internal modules.
39
+
40
+ ## Common Anti-Patterns to Catch
41
+
42
+ - `useEffect` with missing dependencies → use ESLint exhaustive-deps rule
43
+ - Prop drilling > 2 levels → extract to Context or composition
44
+ - Giant components > 200 lines → split into smaller components
45
+ - Inline styles → use CSS modules, Tailwind, or styled-components
46
+ - `any` type assertions → narrow with type guards
47
+ - Non-null assertions (`!`) → handle the null case explicitly
@@ -0,0 +1,28 @@
1
+ name: coding/typescript-react
2
+ version: 1.0.0
3
+ description: TypeScript + React conventions, patterns, and guardrails for AI coding agents
4
+ author: stackmemory
5
+ license: MIT
6
+ runtime:
7
+ type: local
8
+ ingestion:
9
+ sources: []
10
+ ontology:
11
+ entities:
12
+ - component
13
+ - hook
14
+ - context
15
+ - route
16
+ - api-endpoint
17
+ relations:
18
+ - renders
19
+ - depends-on
20
+ - provides
21
+ mcp:
22
+ tools: []
23
+ examples:
24
+ - input: "Create a React component that fetches data"
25
+ output: "Use a custom hook with useEffect + useState, handle loading/error states, return typed JSX"
26
+ - input: "How should I structure my TypeScript types?"
27
+ output: "Prefer interfaces for object shapes, use type for unions/intersections, export from a types.ts barrel file"
28
+ instructions: instructions.md
@@ -0,0 +1,32 @@
1
+ # /capture — Save session context via StackMemory
2
+
3
+ Run `stackmemory capture` to commit current work and generate a handoff prompt for the next session.
4
+
5
+ ## Usage
6
+
7
+ `$ARGUMENTS` — optional flags passed directly to `stackmemory capture`.
8
+
9
+ ## Behavior
10
+
11
+ 1. Run `stackmemory capture $ARGUMENTS`
12
+ 2. Display the generated handoff prompt
13
+ 3. If `--copy` flag is present, confirm the prompt was copied to clipboard
14
+
15
+ ## Common flags
16
+
17
+ | Flag | Effect |
18
+ |------|--------|
19
+ | `-m "message"` | Custom commit message |
20
+ | `--no-commit` | Skip git commit, just generate handoff |
21
+ | `--copy` | Copy handoff prompt to clipboard |
22
+ | `--format ultra` | Ultra-compact pipe-delimited format |
23
+ | `--format verbose` | Full markdown format |
24
+
25
+ ## Examples
26
+
27
+ ```
28
+ /capture # Default capture with auto-format
29
+ /capture -m "privacy policy PR" # With custom message
30
+ /capture --copy # Capture and copy to clipboard
31
+ /capture --no-commit --copy # Just generate handoff, no commit
32
+ ```