@ai-content-space/loopx 0.2.8 → 0.2.10

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 (105) hide show
  1. package/README.md +26 -9
  2. package/README.zh-CN.md +26 -9
  3. package/docs/loopx/design/loopx-skill-suite-v1-design.md +12 -0
  4. package/docs/loopx/plans/2026-06-14-loopx-spec-memory-context-loading.md +948 -0
  5. package/docs/loopx/plans/2026-06-15-support-lens-skills-migration.md +1153 -0
  6. package/package.json +6 -1
  7. package/plugins/loopx/.codex-plugin/plugin.json +1 -1
  8. package/plugins/loopx/skills/api-designer/SKILL.md +232 -0
  9. package/plugins/loopx/skills/api-designer/references/error-handling.md +541 -0
  10. package/plugins/loopx/skills/api-designer/references/openapi.md +824 -0
  11. package/plugins/loopx/skills/api-designer/references/pagination.md +494 -0
  12. package/plugins/loopx/skills/api-designer/references/rest-patterns.md +335 -0
  13. package/plugins/loopx/skills/api-designer/references/versioning.md +391 -0
  14. package/plugins/loopx/skills/architecture-designer/SKILL.md +117 -0
  15. package/plugins/loopx/skills/architecture-designer/references/adr-template.md +116 -0
  16. package/plugins/loopx/skills/architecture-designer/references/architecture-patterns.md +346 -0
  17. package/plugins/loopx/skills/architecture-designer/references/database-selection.md +102 -0
  18. package/plugins/loopx/skills/architecture-designer/references/nfr-checklist.md +212 -0
  19. package/plugins/loopx/skills/architecture-designer/references/system-design.md +313 -0
  20. package/plugins/loopx/skills/clarify/SKILL.md +12 -1
  21. package/plugins/loopx/skills/cli-developer/SKILL.md +124 -0
  22. package/plugins/loopx/skills/cli-developer/references/design-patterns.md +221 -0
  23. package/plugins/loopx/skills/cli-developer/references/go-cli.md +540 -0
  24. package/plugins/loopx/skills/cli-developer/references/node-cli.md +383 -0
  25. package/plugins/loopx/skills/cli-developer/references/python-cli.md +422 -0
  26. package/plugins/loopx/skills/cli-developer/references/ux-patterns.md +448 -0
  27. package/plugins/loopx/skills/debug/SKILL.md +1 -1
  28. package/plugins/loopx/skills/doc-readability/SKILL.md +1 -1
  29. package/plugins/loopx/skills/exec/SKILL.md +1 -1
  30. package/plugins/loopx/skills/final-review/SKILL.md +1 -1
  31. package/plugins/loopx/skills/finish/SKILL.md +1 -1
  32. package/plugins/loopx/skills/fix-review/SKILL.md +1 -1
  33. package/plugins/loopx/skills/go-style/SKILL.md +1 -1
  34. package/plugins/loopx/skills/kratos/SKILL.md +2 -1
  35. package/plugins/loopx/skills/plan-to-exec/SKILL.md +12 -1
  36. package/plugins/loopx/skills/refactor-plan/SKILL.md +1 -1
  37. package/plugins/loopx/skills/requirement-analyzer/SKILL.md +161 -0
  38. package/plugins/loopx/skills/requirement-analyzer/references/example-reports.md +170 -0
  39. package/plugins/loopx/skills/requirement-analyzer/references/prd-gap-checklist.md +167 -0
  40. package/plugins/loopx/skills/requirement-analyzer/references/readiness-rubric.md +70 -0
  41. package/plugins/loopx/skills/requirement-analyzer/references/report-template.md +83 -0
  42. package/plugins/loopx/skills/review/SKILL.md +1 -1
  43. package/plugins/loopx/skills/spec/SKILL.md +12 -1
  44. package/plugins/loopx/skills/sql-style/SKILL.md +108 -0
  45. package/plugins/loopx/skills/sql-style/references/database-design.md +402 -0
  46. package/plugins/loopx/skills/sql-style/references/dialect-differences.md +419 -0
  47. package/plugins/loopx/skills/sql-style/references/optimization.md +384 -0
  48. package/plugins/loopx/skills/sql-style/references/query-patterns.md +285 -0
  49. package/plugins/loopx/skills/sql-style/references/window-functions.md +328 -0
  50. package/plugins/loopx/skills/subagent-exec/SKILL.md +1 -1
  51. package/plugins/loopx/skills/tdd/SKILL.md +1 -1
  52. package/plugins/loopx/skills/verify/SKILL.md +1 -1
  53. package/scripts/verify-skills.mjs +0 -2
  54. package/skills/RESOLVER.md +8 -1
  55. package/skills/api-designer/SKILL.md +232 -0
  56. package/skills/api-designer/references/error-handling.md +541 -0
  57. package/skills/api-designer/references/openapi.md +824 -0
  58. package/skills/api-designer/references/pagination.md +494 -0
  59. package/skills/api-designer/references/rest-patterns.md +335 -0
  60. package/skills/api-designer/references/versioning.md +391 -0
  61. package/skills/architecture-designer/SKILL.md +117 -0
  62. package/skills/architecture-designer/references/adr-template.md +116 -0
  63. package/skills/architecture-designer/references/architecture-patterns.md +346 -0
  64. package/skills/architecture-designer/references/database-selection.md +102 -0
  65. package/skills/architecture-designer/references/nfr-checklist.md +212 -0
  66. package/skills/architecture-designer/references/system-design.md +313 -0
  67. package/skills/clarify/SKILL.md +12 -1
  68. package/skills/cli-developer/SKILL.md +124 -0
  69. package/skills/cli-developer/references/design-patterns.md +221 -0
  70. package/skills/cli-developer/references/go-cli.md +540 -0
  71. package/skills/cli-developer/references/node-cli.md +383 -0
  72. package/skills/cli-developer/references/python-cli.md +422 -0
  73. package/skills/cli-developer/references/ux-patterns.md +448 -0
  74. package/skills/debug/SKILL.md +1 -1
  75. package/skills/doc-readability/SKILL.md +1 -1
  76. package/skills/exec/SKILL.md +1 -1
  77. package/skills/final-review/SKILL.md +1 -1
  78. package/skills/finish/SKILL.md +1 -1
  79. package/skills/fix-review/SKILL.md +1 -1
  80. package/skills/go-style/SKILL.md +1 -1
  81. package/skills/kratos/SKILL.md +2 -1
  82. package/skills/plan-to-exec/SKILL.md +12 -1
  83. package/skills/refactor-plan/SKILL.md +1 -1
  84. package/skills/requirement-analyzer/SKILL.md +161 -0
  85. package/skills/requirement-analyzer/references/example-reports.md +170 -0
  86. package/skills/requirement-analyzer/references/prd-gap-checklist.md +167 -0
  87. package/skills/requirement-analyzer/references/readiness-rubric.md +70 -0
  88. package/skills/requirement-analyzer/references/report-template.md +83 -0
  89. package/skills/review/SKILL.md +1 -1
  90. package/skills/spec/SKILL.md +12 -1
  91. package/skills/sql-style/SKILL.md +108 -0
  92. package/skills/sql-style/references/database-design.md +402 -0
  93. package/skills/sql-style/references/dialect-differences.md +419 -0
  94. package/skills/sql-style/references/optimization.md +384 -0
  95. package/skills/sql-style/references/query-patterns.md +285 -0
  96. package/skills/sql-style/references/window-functions.md +328 -0
  97. package/skills/subagent-exec/SKILL.md +1 -1
  98. package/skills/tdd/SKILL.md +1 -1
  99. package/skills/verify/SKILL.md +1 -1
  100. package/src/cli.mjs +4 -1
  101. package/src/context-manifest.mjs +51 -1
  102. package/src/install-discovery.mjs +114 -0
  103. package/src/loopx-context-artifacts.mjs +114 -0
  104. package/src/project-discovery.mjs +1 -0
  105. package/src/workflow.mjs +47 -3
@@ -0,0 +1,948 @@
1
+ # loopx Spec And Memory Context Loading Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use loopx:subagent-exec (recommended) or loopx:exec to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Source:** Current product decision from this conversation: loopx agents should read long-lived repo specs and curated memory before clarify/spec/plan work, should optionally offer user-level agent guidance on install (`AGENTS.md` for Codex and `CLAUDE.md` for Claude), and should include specs/memory in runtime context manifests as a fallback.
6
+
7
+ **Goal:** Make loopx specs and curated memory reliably visible to agents without requiring `loopx init`, without forcing a `docs/loopx/specs/index.md`, and without silently editing a user's global agent guidance files.
8
+
9
+ **Architecture:** Add the context rule to the canonical workflow skills first, because skills are the main entry point when users do not initialize a loopx runtime. Add a small runtime discovery helper that finds `docs/loopx/specs/` and `.loopx/memory/` when present, then wire it into plan source context and build/review context manifests. Add explicit opt-in managed blocks for Codex `AGENTS.md` and Claude `CLAUDE.md` during install so users can make the behavior global, while non-interactive installs only report the recommendation.
10
+
11
+ **Tech Stack:** Node.js ESM, `node:test`, `node:fs/promises`, existing loopx skill governance, install discovery, context manifest, workflow runtime tests.
12
+
13
+ ---
14
+
15
+ ### Task 1: Add Specs And Memory Reading Rules To Core Planning Skills
16
+
17
+ **Files:**
18
+ - Modify: `skills/clarify/SKILL.md`
19
+ - Modify: `skills/spec/SKILL.md`
20
+ - Modify: `skills/plan/SKILL.md`
21
+ - Modify: `plugins/loopx/skills/clarify/SKILL.md`
22
+ - Modify: `plugins/loopx/skills/spec/SKILL.md`
23
+ - Modify: `plugins/loopx/skills/plan/SKILL.md`
24
+ - Test: `test/skill-governance.test.mjs`
25
+
26
+ - [ ] **Step 1: Write the failing skill governance test**
27
+
28
+ Add these assertions inside the existing `keeps workflow skill handoff commands unambiguous` test in `test/skill-governance.test.mjs`, after each skill file is read:
29
+
30
+ ```js
31
+ for (const [skillName, text] of [
32
+ ['clarify', clarify],
33
+ ['spec', spec],
34
+ ['plan', plan],
35
+ ]) {
36
+ assert.match(text, /Repo Specs And Memory Context/, `${skillName} missing repo context rule`);
37
+ assert.match(text, /docs\/loopx\/specs\//, `${skillName} missing loopx specs guidance`);
38
+ assert.match(text, /\.loopx\/memory\/MEMORY\.md/, `${skillName} missing memory summary guidance`);
39
+ assert.match(text, /Memory is advisory/, `${skillName} missing memory priority guidance`);
40
+ assert.doesNotMatch(text, /must read every file under `docs\/loopx\/specs\/`/i);
41
+ }
42
+ ```
43
+
44
+ - [ ] **Step 2: Run the focused test to verify it fails**
45
+
46
+ Run:
47
+
48
+ ```bash
49
+ node --test test/skill-governance.test.mjs -t "keeps workflow skill handoff commands unambiguous"
50
+ ```
51
+
52
+ Expected: FAIL with an assertion like `clarify missing repo context rule`.
53
+
54
+ - [ ] **Step 3: Add the shared context rule to the three root skills**
55
+
56
+ Insert this section into `skills/clarify/SKILL.md` after `## Core Loop`, into `skills/spec/SKILL.md` after `## Inputs`, and into `skills/plan/SKILL.md` after the source list and before the "Do not re-decide..." paragraph:
57
+
58
+ ```md
59
+ ## Repo Specs And Memory Context
60
+
61
+ Before using this skill in a repository, inspect loopx long-lived context when it exists:
62
+
63
+ - If `docs/loopx/specs/` exists, inspect the directory names and filenames. If `docs/loopx/specs/index.md` exists, use it as a map, but do not require it. Read only specs relevant to the requested domain, affected files, workflow behavior, or named source document.
64
+ - If `.loopx/memory/MEMORY.md` exists, read it as curated project memory before deciding what is already known.
65
+ - If `.loopx/memory/index.jsonl` exists, use it only as a retrieval index for relevant active memory cards; do not treat it as an append-only log.
66
+ - Treat current user instructions and the named source document as highest priority, `docs/loopx/specs/` as binding long-lived repo rules, and `.loopx/memory/` as advisory context. Memory is advisory and must not override current task instructions, approved source docs, or repo specs.
67
+
68
+ Do not read every file under `docs/loopx/specs/` by default. Prefer relevant specs selected by filename, title, frontmatter such as `applies_to`, or the files/domains involved in the task.
69
+ ```
70
+
71
+ For `clarify`, make one local wording adjustment in the first bullet so it says "before asking questions" instead of "before deciding" only if that reads better in context; keep the exact phrases asserted by the test.
72
+
73
+ - [ ] **Step 4: Synchronize plugin skill mirrors**
74
+
75
+ Copy the edited root skill files to their plugin mirrors:
76
+
77
+ ```bash
78
+ cp skills/clarify/SKILL.md plugins/loopx/skills/clarify/SKILL.md
79
+ cp skills/spec/SKILL.md plugins/loopx/skills/spec/SKILL.md
80
+ cp skills/plan/SKILL.md plugins/loopx/skills/plan/SKILL.md
81
+ ```
82
+
83
+ Expected: no output.
84
+
85
+ - [ ] **Step 5: Run the focused test to verify it passes**
86
+
87
+ Run:
88
+
89
+ ```bash
90
+ node --test test/skill-governance.test.mjs -t "keeps workflow skill handoff commands unambiguous"
91
+ ```
92
+
93
+ Expected: PASS, including existing plugin mirror equality assertions.
94
+
95
+ - [ ] **Step 6: Commit**
96
+
97
+ ```bash
98
+ git add skills/clarify/SKILL.md skills/spec/SKILL.md skills/plan/SKILL.md plugins/loopx/skills/clarify/SKILL.md plugins/loopx/skills/spec/SKILL.md plugins/loopx/skills/plan/SKILL.md test/skill-governance.test.mjs
99
+ git commit -m "docs: teach core skills to read loopx specs and memory"
100
+ ```
101
+
102
+ ### Task 2: Add Runtime Discovery For loopx Specs And Memory
103
+
104
+ **Files:**
105
+ - Create: `src/loopx-context-artifacts.mjs`
106
+ - Modify: `src/project-discovery.mjs`
107
+ - Test: `test/trellis-hardening.test.mjs`
108
+ - Test: `test/workflow.test.mjs`
109
+
110
+ - [ ] **Step 1: Write the failing context discovery test**
111
+
112
+ Add this import to `test/trellis-hardening.test.mjs`:
113
+
114
+ ```js
115
+ import { discoverLoopxContextArtifacts } from '../src/loopx-context-artifacts.mjs';
116
+ ```
117
+
118
+ Add this test near the existing context manifest tests:
119
+
120
+ ```js
121
+ it('discovers loopx repo specs and curated memory without requiring an index file', async () => {
122
+ const wd = await mkdtemp(join(tmpdir(), 'loopx-context-artifacts-'));
123
+ await mkdir(join(wd, 'docs', 'loopx', 'specs'), { recursive: true });
124
+ await mkdir(join(wd, '.loopx', 'memory', 'entries'), { recursive: true });
125
+ await writeFile(join(wd, 'docs', 'loopx', 'specs', 'workflow-runtime.md'), [
126
+ '---',
127
+ 'applies_to:',
128
+ ' - src/workflow.mjs',
129
+ '---',
130
+ '# Workflow Runtime Spec',
131
+ '',
132
+ '- Build and review must consume manifests.',
133
+ ].join('\n'));
134
+ await writeFile(join(wd, 'docs', 'loopx', 'specs', 'skills.md'), '# Skills Spec\n');
135
+ await writeFile(join(wd, '.loopx', 'memory', 'MEMORY.md'), '# Memory\n\n- Prefer manifest evidence.\n');
136
+ await writeFile(join(wd, '.loopx', 'memory', 'index.jsonl'), `${JSON.stringify({
137
+ id: 'runtime-manifest',
138
+ path: 'entries/runtime-manifest.md',
139
+ tags: ['workflow'],
140
+ })}\n`);
141
+
142
+ const context = await discoverLoopxContextArtifacts(wd, { changedFiles: ['src/workflow.mjs'] });
143
+
144
+ assert.equal(context.specsRoot, 'docs/loopx/specs');
145
+ assert.deepEqual(context.specFiles.map((item) => item.path), ['docs/loopx/specs/workflow-runtime.md']);
146
+ assert.equal(context.memorySummary?.path, '.loopx/memory/MEMORY.md');
147
+ assert.equal(context.memoryIndex?.path, '.loopx/memory/index.jsonl');
148
+ });
149
+ ```
150
+
151
+ - [ ] **Step 2: Write the failing project discovery test update**
152
+
153
+ In `test/workflow.test.mjs`, in `initializes a loopx workspace and requires approval before planning`, create the loopx specs directory before `initWorkspace`:
154
+
155
+ ```js
156
+ await mkdir(join(wd, 'docs', 'loopx', 'specs'), { recursive: true });
157
+ await writeFile(join(wd, 'docs', 'loopx', 'specs', 'workflow.md'), '# Workflow spec\n');
158
+ ```
159
+
160
+ Change the expected `existing_spec_sources` assertion to include the loopx specs directory:
161
+
162
+ ```js
163
+ assert.deepEqual(
164
+ config.project_conventions.existing_spec_sources.map((item) => item.path),
165
+ ['docs/changes', 'docs/loopx/specs'],
166
+ );
167
+ ```
168
+
169
+ - [ ] **Step 3: Run focused tests to verify they fail**
170
+
171
+ Run:
172
+
173
+ ```bash
174
+ node --test test/trellis-hardening.test.mjs -t "discovers loopx repo specs"
175
+ node --test test/workflow.test.mjs -t "initializes a loopx workspace"
176
+ ```
177
+
178
+ Expected:
179
+ - first command FAILS because `src/loopx-context-artifacts.mjs` does not exist
180
+ - second command FAILS because `docs/loopx/specs` is not discovered
181
+
182
+ - [ ] **Step 4: Implement `src/loopx-context-artifacts.mjs`**
183
+
184
+ Create `src/loopx-context-artifacts.mjs` with these exports and behavior:
185
+
186
+ ```js
187
+ import { existsSync } from 'node:fs';
188
+ import { readFile, readdir } from 'node:fs/promises';
189
+ import { basename, join, relative, resolve } from 'node:path';
190
+
191
+ const MAX_SPEC_CONTEXT_FILES = 12;
192
+
193
+ function displayPath(cwd, path) {
194
+ const rel = relative(cwd, path);
195
+ return rel && !rel.startsWith('..') ? rel : path;
196
+ }
197
+
198
+ function normalizeChangedFiles(files = []) {
199
+ return Array.isArray(files)
200
+ ? files.map((file) => String(file || '').trim()).filter(Boolean)
201
+ : [];
202
+ }
203
+
204
+ async function listMarkdownFiles(root) {
205
+ if (!existsSync(root)) {
206
+ return [];
207
+ }
208
+ const found = [];
209
+ async function walk(dir) {
210
+ const entries = await readdir(dir, { withFileTypes: true });
211
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
212
+ const path = join(dir, entry.name);
213
+ if (entry.isDirectory()) {
214
+ await walk(path);
215
+ continue;
216
+ }
217
+ if (entry.isFile() && /\.md$/i.test(entry.name)) {
218
+ found.push(path);
219
+ }
220
+ }
221
+ }
222
+ await walk(root);
223
+ return found;
224
+ }
225
+
226
+ function pathParts(value) {
227
+ return String(value || '')
228
+ .toLowerCase()
229
+ .split(/[^a-z0-9]+/)
230
+ .filter((part) => part.length >= 3);
231
+ }
232
+
233
+ function frontmatterAppliesTo(text) {
234
+ if (!String(text || '').startsWith('---\n')) {
235
+ return [];
236
+ }
237
+ const end = text.indexOf('\n---\n', 4);
238
+ if (end === -1) {
239
+ return [];
240
+ }
241
+ const lines = text.slice(4, end).split('\n');
242
+ const values = [];
243
+ let inAppliesTo = false;
244
+ for (const line of lines) {
245
+ if (/^applies_to:\s*$/.test(line)) {
246
+ inAppliesTo = true;
247
+ continue;
248
+ }
249
+ if (inAppliesTo && /^\s+-\s+/.test(line)) {
250
+ values.push(line.replace(/^\s+-\s+/, '').trim().replace(/^['"]|['"]$/g, ''));
251
+ continue;
252
+ }
253
+ if (inAppliesTo && /^\S/.test(line)) {
254
+ inAppliesTo = false;
255
+ }
256
+ }
257
+ return values.filter(Boolean);
258
+ }
259
+
260
+ function appliesToChangedFile(pattern, changedFile) {
261
+ const normalizedPattern = String(pattern || '').replace(/\*\*?\/?/g, '').replace(/\/+$/, '');
262
+ const normalizedFile = String(changedFile || '');
263
+ return normalizedPattern && normalizedFile.includes(normalizedPattern);
264
+ }
265
+
266
+ async function specRecord(cwd, path, changedFiles) {
267
+ const text = await readFile(path, 'utf8');
268
+ const appliesTo = frontmatterAppliesTo(text);
269
+ const stemParts = pathParts(basename(path, '.md'));
270
+ const changedParts = new Set(changedFiles.flatMap(pathParts));
271
+ const filenameMatch = stemParts.some((part) => changedParts.has(part));
272
+ const appliesToMatch = appliesTo.some((pattern) => changedFiles.some((file) => appliesToChangedFile(pattern, file)));
273
+ const isIndex = /(^|\/)index\.md$/i.test(path);
274
+ const isInbox = /(^|\/)inbox\.md$/i.test(path);
275
+ return {
276
+ path: displayPath(cwd, path),
277
+ appliesTo,
278
+ relevant: isIndex || isInbox || filenameMatch || appliesToMatch || changedFiles.length === 0,
279
+ };
280
+ }
281
+
282
+ export async function discoverLoopxContextArtifacts(cwd, options = {}) {
283
+ const root = resolve(cwd);
284
+ const changedFiles = normalizeChangedFiles(options.changedFiles);
285
+ const specsRootPath = join(root, 'docs', 'loopx', 'specs');
286
+ const specPaths = await listMarkdownFiles(specsRootPath);
287
+ const records = await Promise.all(specPaths.map((path) => specRecord(root, path, changedFiles)));
288
+ const relevantSpecs = records
289
+ .filter((record) => record.relevant)
290
+ .sort((left, right) => left.path.localeCompare(right.path))
291
+ .slice(0, MAX_SPEC_CONTEXT_FILES);
292
+ const memorySummaryPath = join(root, '.loopx', 'memory', 'MEMORY.md');
293
+ const memoryIndexPath = join(root, '.loopx', 'memory', 'index.jsonl');
294
+ return {
295
+ specsRoot: existsSync(specsRootPath) ? displayPath(root, specsRootPath) : null,
296
+ specFiles: relevantSpecs,
297
+ memorySummary: existsSync(memorySummaryPath) ? { path: displayPath(root, memorySummaryPath) } : null,
298
+ memoryIndex: existsSync(memoryIndexPath) ? { path: displayPath(root, memoryIndexPath) } : null,
299
+ };
300
+ }
301
+ ```
302
+
303
+ This implementation intentionally makes `index.md` useful but optional.
304
+
305
+ - [ ] **Step 5: Update project discovery**
306
+
307
+ In `src/project-discovery.mjs`, add `docs/loopx/specs` to `discoverSpecSources` after `docs/specs` and before `docs/adr`:
308
+
309
+ ```js
310
+ candidate(join(cwd, 'docs', 'loopx', 'specs'), 'docs/loopx/specs'),
311
+ ```
312
+
313
+ Do not add `docs/loopx/design` as a spec source. Design docs are task-specific sources only when named by the current task or plan.
314
+
315
+ - [ ] **Step 6: Run focused tests to verify they pass**
316
+
317
+ Run:
318
+
319
+ ```bash
320
+ node --test test/trellis-hardening.test.mjs -t "discovers loopx repo specs"
321
+ node --test test/workflow.test.mjs -t "initializes a loopx workspace"
322
+ ```
323
+
324
+ Expected: both commands PASS.
325
+
326
+ - [ ] **Step 7: Commit**
327
+
328
+ ```bash
329
+ git add src/loopx-context-artifacts.mjs src/project-discovery.mjs test/trellis-hardening.test.mjs test/workflow.test.mjs
330
+ git commit -m "feat: discover loopx specs and curated memory"
331
+ ```
332
+
333
+ ### Task 3: Inject Specs And Memory Into Plan, Build, And Review Context
334
+
335
+ **Files:**
336
+ - Modify: `src/workflow.mjs`
337
+ - Modify: `src/context-manifest.mjs`
338
+ - Test: `test/trellis-hardening.test.mjs`
339
+
340
+ - [ ] **Step 1: Write the failing plan context test**
341
+
342
+ Add this test near the existing context manifest tests in `test/trellis-hardening.test.mjs`:
343
+
344
+ ```js
345
+ it('adds loopx specs and memory to plan source context', async () => {
346
+ const wd = await mkdtemp(join(tmpdir(), 'loopx-plan-repo-context-'));
347
+ const clarified = await clarifyStage(wd, 'plan-repo-context');
348
+ await writeResolvedSpec(clarified.root, 'plan-repo-context');
349
+ await mkdir(join(wd, 'docs', 'loopx', 'specs'), { recursive: true });
350
+ await mkdir(join(wd, '.loopx', 'memory'), { recursive: true });
351
+ await writeFile(join(wd, 'docs', 'loopx', 'specs', 'workflow-runtime.md'), [
352
+ '---',
353
+ 'applies_to:',
354
+ ' - src/workflow.mjs',
355
+ '---',
356
+ '# Workflow Runtime Spec',
357
+ '',
358
+ '- Plans must preserve explicit approvals.',
359
+ ].join('\n'));
360
+ await writeFile(join(wd, '.loopx', 'memory', 'MEMORY.md'), '# Memory\n\n- Prioritize manifest evidence.\n');
361
+ await approveStage(wd, 'plan-repo-context', { from: 'clarify', to: 'plan' });
362
+
363
+ const planned = await planStage(wd, 'plan-repo-context', { adapter: createScriptedPlanAdapter() });
364
+
365
+ assert.equal(planned.state.plan_source_document_paths.includes(join(wd, 'docs', 'loopx', 'specs', 'workflow-runtime.md')), true);
366
+ assert.equal(planned.state.plan_source_document_paths.includes(join(wd, '.loopx', 'memory', 'MEMORY.md')), true);
367
+ const traceability = await readFile(join(planned.root, 'requirement-traceability.md'), 'utf8');
368
+ assert.match(traceability, /Plans must preserve explicit approvals/);
369
+ assert.match(traceability, /Prioritize manifest evidence/);
370
+ });
371
+ ```
372
+
373
+ - [ ] **Step 2: Write the failing manifest rows test update**
374
+
375
+ In the existing test `generates context manifests, consumes them, and writes Chinese workspace journal`, create repo specs and memory before `planStage`:
376
+
377
+ ```js
378
+ await mkdir(join(wd, 'docs', 'loopx', 'specs'), { recursive: true });
379
+ await mkdir(join(wd, '.loopx', 'memory'), { recursive: true });
380
+ await writeFile(join(wd, 'docs', 'loopx', 'specs', 'workflow-runtime.md'), [
381
+ '---',
382
+ 'applies_to:',
383
+ ' - src/workflow.mjs',
384
+ '---',
385
+ '# Workflow Runtime Spec',
386
+ '',
387
+ '- Build and review must use context manifests.',
388
+ ].join('\n'));
389
+ await writeFile(join(wd, '.loopx', 'memory', 'MEMORY.md'), '# Memory\n\n- Review should preserve terminology.\n');
390
+ await writeFile(join(wd, '.loopx', 'memory', 'index.jsonl'), '{"id":"terminology","path":"entries/terminology.md"}\n');
391
+ ```
392
+
393
+ Add build manifest assertions after `buildRows` is read:
394
+
395
+ ```js
396
+ assert.equal(buildRows.some((row) => row.kind === 'repo-spec' && row.path === 'docs/loopx/specs/workflow-runtime.md'), true);
397
+ assert.equal(buildRows.some((row) => row.kind === 'memory-summary' && row.path === '.loopx/memory/MEMORY.md'), true);
398
+ assert.equal(buildRows.some((row) => row.kind === 'memory-index' && row.path === '.loopx/memory/index.jsonl'), true);
399
+ ```
400
+
401
+ Add review manifest assertions after `reviewRows` is read:
402
+
403
+ ```js
404
+ assert.equal(reviewRows.some((row) => row.kind === 'repo-spec' && row.path === 'docs/loopx/specs/workflow-runtime.md'), true);
405
+ assert.equal(reviewRows.some((row) => row.kind === 'memory-summary' && row.path === '.loopx/memory/MEMORY.md'), true);
406
+ ```
407
+
408
+ - [ ] **Step 3: Run focused tests to verify they fail**
409
+
410
+ Run:
411
+
412
+ ```bash
413
+ node --test test/trellis-hardening.test.mjs -t "adds loopx specs and memory to plan source context"
414
+ node --test test/trellis-hardening.test.mjs -t "generates context manifests"
415
+ ```
416
+
417
+ Expected: FAIL because plan source context and context manifests do not include loopx specs or memory yet.
418
+
419
+ - [ ] **Step 4: Append repo context to plan source text**
420
+
421
+ In `src/workflow.mjs`, import the discovery helper:
422
+
423
+ ```js
424
+ import { discoverLoopxContextArtifacts } from './loopx-context-artifacts.mjs';
425
+ ```
426
+
427
+ Add a helper near `readPlanSourceText`:
428
+
429
+ ```js
430
+ async function readLoopxRepoContextText(cwd, sourceSpecPath) {
431
+ const artifacts = await discoverLoopxContextArtifacts(cwd, {
432
+ changedFiles: [relative(cwd, sourceSpecPath)],
433
+ });
434
+ const paths = [
435
+ ...artifacts.specFiles.map((item) => item.path),
436
+ artifacts.memorySummary?.path,
437
+ ].filter(Boolean);
438
+ if (paths.length === 0) {
439
+ return { text: '', paths: [] };
440
+ }
441
+ const sections = [];
442
+ const loaded = [];
443
+ for (const display of paths) {
444
+ const absolute = resolve(cwd, display);
445
+ if (!existsSync(absolute)) {
446
+ continue;
447
+ }
448
+ const raw = await readFile(absolute, 'utf8');
449
+ loaded.push(absolute);
450
+ sections.push([
451
+ `# loopx context: ${display}`,
452
+ '',
453
+ compactPlanningText(raw),
454
+ ].join('\n'));
455
+ }
456
+ return {
457
+ text: [
458
+ '# loopx Repo Specs And Memory Context',
459
+ '',
460
+ 'Current task instructions and named source documents have priority. Repo specs are binding long-lived rules. Memory is advisory.',
461
+ '',
462
+ ...sections,
463
+ ].join('\n\n'),
464
+ paths: loaded,
465
+ };
466
+ }
467
+ ```
468
+
469
+ Then update `readPlanSourceText` so the returned `sourceText` includes this context and `sourceDocumentPaths` includes the loaded absolute paths:
470
+
471
+ ```js
472
+ const repoContext = await readLoopxRepoContextText(cwd, sourceSpecPath);
473
+ if (repoContext.text) {
474
+ parts.push(repoContext.text);
475
+ loaded.push(...repoContext.paths);
476
+ }
477
+ ```
478
+
479
+ Place this block after loading frontmatter/source-context documents so task-specific docs stay closest to the original source and repo context remains clearly labeled.
480
+
481
+ - [ ] **Step 5: Add repo context rows to build and review manifests**
482
+
483
+ In `src/context-manifest.mjs`, import:
484
+
485
+ ```js
486
+ import { discoverLoopxContextArtifacts } from './loopx-context-artifacts.mjs';
487
+ ```
488
+
489
+ Add this helper near `stableRows`:
490
+
491
+ ```js
492
+ async function loopxRepoContextRows(cwd, stage, priorityStart) {
493
+ const artifacts = await discoverLoopxContextArtifacts(cwd);
494
+ const rows = [];
495
+ let priority = priorityStart;
496
+ if (artifacts.specsRoot) {
497
+ rows.push(row(cwd, {
498
+ stage,
499
+ kind: 'repo-specs',
500
+ path: artifacts.specsRoot,
501
+ reason: 'long_lived_loopx_specs_directory',
502
+ priority: priority++,
503
+ required: false,
504
+ }));
505
+ }
506
+ for (const spec of artifacts.specFiles) {
507
+ rows.push(row(cwd, {
508
+ stage,
509
+ kind: 'repo-spec',
510
+ path: spec.path,
511
+ reason: 'long_lived_loopx_spec',
512
+ priority: priority++,
513
+ required: false,
514
+ }));
515
+ }
516
+ if (artifacts.memorySummary) {
517
+ rows.push(row(cwd, {
518
+ stage,
519
+ kind: 'memory-summary',
520
+ path: artifacts.memorySummary.path,
521
+ reason: 'curated_loopx_project_memory',
522
+ priority: priority++,
523
+ required: false,
524
+ }));
525
+ }
526
+ if (artifacts.memoryIndex) {
527
+ rows.push(row(cwd, {
528
+ stage,
529
+ kind: 'memory-index',
530
+ path: artifacts.memoryIndex.path,
531
+ reason: 'curated_loopx_memory_retrieval_index',
532
+ priority: priority++,
533
+ required: false,
534
+ }));
535
+ }
536
+ return rows;
537
+ }
538
+ ```
539
+
540
+ In `generateBuildContextManifest`, append:
541
+
542
+ ```js
543
+ ...await loopxRepoContextRows(cwd, 'build', 37),
544
+ ```
545
+
546
+ after the existing `workspace-config` row.
547
+
548
+ In `generateReviewContextManifest`, append:
549
+
550
+ ```js
551
+ ...await loopxRepoContextRows(cwd, 'review', 33),
552
+ ```
553
+
554
+ after the existing `workspace-config` row and before the required `state` row. Keep all repo spec and memory rows `required: false` so missing optional context cannot block build/review.
555
+
556
+ - [ ] **Step 6: Run focused tests to verify they pass**
557
+
558
+ Run:
559
+
560
+ ```bash
561
+ node --test test/trellis-hardening.test.mjs -t "adds loopx specs and memory to plan source context"
562
+ node --test test/trellis-hardening.test.mjs -t "generates context manifests"
563
+ ```
564
+
565
+ Expected: both commands PASS.
566
+
567
+ - [ ] **Step 7: Commit**
568
+
569
+ ```bash
570
+ git add src/workflow.mjs src/context-manifest.mjs test/trellis-hardening.test.mjs
571
+ git commit -m "feat: include loopx specs and memory in agent context"
572
+ ```
573
+
574
+ ### Task 4: Add Optional User Agent Guidance During Install
575
+
576
+ **Files:**
577
+ - Modify: `src/install-discovery.mjs`
578
+ - Modify: `src/cli.mjs`
579
+ - Test: `test/workflow.test.mjs`
580
+
581
+ - [ ] **Step 1: Write the failing install API test**
582
+
583
+ Add this test after `install-skills isolates codex and claude targets and honors custom directories` in `test/workflow.test.mjs`:
584
+
585
+ ```js
586
+ it('installs optional user agent guidance without overwriting user content', async () => {
587
+ const home = await mkdtemp(join(tmpdir(), 'loopx-agent-guidance-'));
588
+ const env = loopxEnv(home);
589
+ await mkdir(join(home, '.codex'), { recursive: true });
590
+ await mkdir(join(home, '.claude'), { recursive: true });
591
+ await writeFile(join(home, '.codex', 'AGENTS.md'), '# Existing guidance\n\n- Keep this line.\n');
592
+ await writeFile(join(home, '.claude', 'CLAUDE.md'), '# Existing Claude guidance\n\n- Keep this Claude line.\n');
593
+
594
+ const withoutGuidance = await installBundledSkills({
595
+ ...env,
596
+ LOOPX_INSTALL_TARGET: 'codex',
597
+ });
598
+ assert.equal(existsSync(join(home, '.codex', 'AGENTS.md')), true);
599
+ assert.doesNotMatch(await readFile(join(home, '.codex', 'AGENTS.md'), 'utf8'), /loopx Specs And Memory/);
600
+ assert.equal(withoutGuidance.agentGuidance.codex.status, 'recommended');
601
+
602
+ const withGuidance = await installBundledSkills({
603
+ ...env,
604
+ LOOPX_INSTALL_TARGET: 'codex',
605
+ }, {
606
+ target: 'codex',
607
+ agentGuidance: true,
608
+ });
609
+ const agentsText = await readFile(join(home, '.codex', 'AGENTS.md'), 'utf8');
610
+ assert.match(agentsText, /# Existing guidance/);
611
+ assert.match(agentsText, /<!-- loopx:managed:block specs-and-memory-context -->/);
612
+ assert.match(agentsText, /docs\/loopx\/specs\//);
613
+ assert.match(agentsText, /\.loopx\/memory\/MEMORY\.md/);
614
+ assert.equal(withGuidance.agentGuidance.codex.status, 'installed');
615
+
616
+ const second = await installBundledSkills({
617
+ ...env,
618
+ LOOPX_INSTALL_TARGET: 'codex',
619
+ }, {
620
+ target: 'codex',
621
+ agentGuidance: true,
622
+ });
623
+ assert.equal(second.agentGuidance.codex.status, 'already-current');
624
+ assert.equal(await readFile(join(home, '.codex', 'AGENTS.md'), 'utf8'), agentsText);
625
+
626
+ const claudeGuidance = await installBundledSkills({
627
+ ...env,
628
+ LOOPX_INSTALL_TARGET: 'claude',
629
+ }, {
630
+ target: 'claude',
631
+ agentGuidance: true,
632
+ });
633
+ const claudeText = await readFile(join(home, '.claude', 'CLAUDE.md'), 'utf8');
634
+ assert.match(claudeText, /# Existing Claude guidance/);
635
+ assert.match(claudeText, /<!-- loopx:managed:block specs-and-memory-context -->/);
636
+ assert.match(claudeText, /docs\/loopx\/specs\//);
637
+ assert.match(claudeText, /\.loopx\/memory\/MEMORY\.md/);
638
+ assert.equal(claudeGuidance.agentGuidance.claude.status, 'installed');
639
+ });
640
+ ```
641
+
642
+ - [ ] **Step 2: Write the failing CLI flag test**
643
+
644
+ Add this assertion to the same test or a new nearby test:
645
+
646
+ ```js
647
+ const cliHome = await mkdtemp(join(tmpdir(), 'loopx-agent-guidance-cli-'));
648
+ const { stdout } = await execFileAsync(process.execPath, [
649
+ cliPath,
650
+ 'install-skills',
651
+ '--target',
652
+ 'all',
653
+ '--yes',
654
+ '--add-agent-guidance',
655
+ ], {
656
+ cwd: repoRoot,
657
+ env: loopxEnv(cliHome),
658
+ });
659
+ const payload = JSON.parse(stdout);
660
+ assert.equal(payload.results.codex.agentGuidance.codex.status, 'created');
661
+ assert.equal(payload.results.claude.agentGuidance.claude.status, 'created');
662
+ assert.match(await readFile(join(cliHome, '.codex', 'AGENTS.md'), 'utf8'), /loopx Specs And Memory/);
663
+ assert.match(await readFile(join(cliHome, '.claude', 'CLAUDE.md'), 'utf8'), /loopx Specs And Memory/);
664
+ ```
665
+
666
+ - [ ] **Step 3: Run focused tests to verify they fail**
667
+
668
+ Run:
669
+
670
+ ```bash
671
+ node --test test/workflow.test.mjs -t "installs optional user agent guidance"
672
+ ```
673
+
674
+ Expected: FAIL because `agentGuidance`, Claude `CLAUDE.md` guidance, and `--add-agent-guidance` do not exist.
675
+
676
+ - [ ] **Step 4: Implement managed block helpers in `src/install-discovery.mjs`**
677
+
678
+ Update the import from `node:fs/promises` to include no new APIs beyond those already used. Add these helpers near the path helpers:
679
+
680
+ ```js
681
+ const AGENT_GUIDANCE_BLOCK_ID = 'specs-and-memory-context';
682
+
683
+ export function getCodexAgentsPath(env = process.env) {
684
+ const home = resolve(env.LOOPX_HOME || env.HOME || process.cwd());
685
+ return resolve(env.LOOPX_CODEX_AGENTS_PATH || join(home, '.codex', 'AGENTS.md'));
686
+ }
687
+
688
+ export function getClaudeAgentsPath(env = process.env, options = {}) {
689
+ if (options.project === true) {
690
+ return join(resolve(env.LOOPX_INSTALL_CWD || process.cwd()), 'CLAUDE.md');
691
+ }
692
+ const home = resolve(env.LOOPX_HOME || env.HOME || process.cwd());
693
+ return resolve(env.LOOPX_CLAUDE_AGENTS_PATH || join(home, '.claude', 'CLAUDE.md'));
694
+ }
695
+
696
+ function agentGuidanceBlock() {
697
+ return [
698
+ '<!-- loopx:managed:block specs-and-memory-context -->',
699
+ '## loopx Specs And Memory',
700
+ '',
701
+ 'When working in a repository that uses loopx:',
702
+ '',
703
+ '- If `docs/loopx/specs/` exists, inspect relevant specs before clarify, spec, plan, implementation, or review. Use `docs/loopx/specs/index.md` as a map when present, but do not require it.',
704
+ '- If `.loopx/memory/MEMORY.md` exists, read it as curated project memory.',
705
+ '- If `.loopx/memory/index.jsonl` exists, use it only to find relevant active memory cards.',
706
+ '- Treat current user instructions and named source documents as highest priority, repo specs as binding long-lived rules, and memory as advisory context.',
707
+ '<!-- /loopx:managed:block specs-and-memory-context -->',
708
+ ].join('\n');
709
+ }
710
+
711
+ function replaceManagedBlock(text, blockText) {
712
+ const pattern = /<!--\s*loopx:managed:block\s+specs-and-memory-context\s*-->[\s\S]*?<!--\s*\/loopx:managed:block\s+specs-and-memory-context\s*-->/;
713
+ if (pattern.test(text)) {
714
+ return text.replace(pattern, blockText);
715
+ }
716
+ return `${text.replace(/\s+$/, '')}${text.trim() ? '\n\n' : ''}${blockText}\n`;
717
+ }
718
+
719
+ async function installAgentGuidanceFile(path, { enabled = false } = {}) {
720
+ const block = agentGuidanceBlock();
721
+ const existing = existsSync(path) ? await readFile(path, 'utf8') : '';
722
+ if (!enabled) {
723
+ return {
724
+ status: /loopx:managed:block\s+specs-and-memory-context/.test(existing) ? 'already-current' : 'recommended',
725
+ path,
726
+ };
727
+ }
728
+ const next = replaceManagedBlock(existing, block);
729
+ if (next === existing) {
730
+ return { status: 'already-current', path };
731
+ }
732
+ await ensureDir(dirname(path));
733
+ await writeFile(path, `${next.replace(/\s+$/, '')}\n`);
734
+ return {
735
+ status: existing ? 'installed' : 'created',
736
+ path,
737
+ };
738
+ }
739
+
740
+ async function installAgentGuidance(env = process.env, options = {}) {
741
+ const target = options.target || env.LOOPX_INSTALL_TARGET || 'codex';
742
+ const enabled = Boolean(options.agentGuidance || options.codexAgentsGuidance);
743
+ return {
744
+ codex: target === 'codex'
745
+ ? await installAgentGuidanceFile(getCodexAgentsPath(env), { enabled })
746
+ : { status: 'not-applicable', path: getCodexAgentsPath(env) },
747
+ claude: target === 'claude'
748
+ ? await installAgentGuidanceFile(getClaudeAgentsPath(env, options), { enabled })
749
+ : { status: 'not-applicable', path: getClaudeAgentsPath(env, options) },
750
+ };
751
+ }
752
+ ```
753
+
754
+ At the end of `installBundledSkills`, before the final `return`, compute:
755
+
756
+ ```js
757
+ const agentGuidance = await installAgentGuidance(env, options);
758
+ ```
759
+
760
+ Include `agentGuidance` in the returned object.
761
+
762
+ Keep `options.codexAgentsGuidance` as a backwards-compatible alias in the helper even though the new public flag is `--add-agent-guidance`.
763
+
764
+ - [ ] **Step 5: Wire CLI prompt and flag**
765
+
766
+ In `src/cli.mjs`, update usage:
767
+
768
+ ```js
769
+ ' loopx install-skills [--target <codex|claude|all>] [--project] [--mode <copy|symlink>] [--dir <path>] [--add-agent-guidance] [--yes]',
770
+ ```
771
+
772
+ In `promptInstallOptions`, ask one more question after install mode:
773
+
774
+ ```js
775
+ const guidanceAnswer = (await rl.question('Add loopx agent guidance to Codex AGENTS.md / Claude CLAUDE.md? [y/N]: ')).trim().toLowerCase();
776
+ ```
777
+
778
+ Return:
779
+
780
+ ```js
781
+ agentGuidance: guidanceAnswer === 'y' || guidanceAnswer === 'yes',
782
+ ```
783
+
784
+ In `installOptionsFromArgs`, add:
785
+
786
+ ```js
787
+ agentGuidance: Boolean(options.get('--add-agent-guidance') || options.get('--add-codex-agents-guidance')),
788
+ ```
789
+
790
+ Do not make `--yes` imply global `AGENTS.md` or `CLAUDE.md` edits. The opt-in flag or interactive yes answer is required.
791
+
792
+ - [ ] **Step 6: Run focused tests to verify they pass**
793
+
794
+ Run:
795
+
796
+ ```bash
797
+ node --test test/workflow.test.mjs -t "installs optional user agent guidance"
798
+ ```
799
+
800
+ Expected: PASS.
801
+
802
+ - [ ] **Step 7: Commit**
803
+
804
+ ```bash
805
+ git add src/install-discovery.mjs src/cli.mjs test/workflow.test.mjs
806
+ git commit -m "feat: add optional loopx agent guidance"
807
+ ```
808
+
809
+ ### Task 5: Update Public Docs And Governance Checks
810
+
811
+ **Files:**
812
+ - Modify: `README.md`
813
+ - Modify: `README.zh-CN.md`
814
+ - Modify: `test/skill-governance.test.mjs`
815
+
816
+ - [ ] **Step 1: Write failing public docs assertions**
817
+
818
+ In `test/skill-governance.test.mjs`, in `keeps public docs structurally valid and bilingual release docs aligned`, add these required strings to the docs assertion lists:
819
+
820
+ ```js
821
+ '--add-agent-guidance',
822
+ 'Repo Specs And Memory',
823
+ ```
824
+
825
+ Also add:
826
+
827
+ ```js
828
+ 'docs/loopx/specs/ is binding long-lived repo context',
829
+ '.loopx/memory/MEMORY.md is advisory curated memory',
830
+ ```
831
+
832
+ For the Chinese README, assert the literal English strings above where possible; the current test checks both READMEs with the same strings, so use these exact English phrases in both docs to keep the test simple.
833
+
834
+ - [ ] **Step 2: Run the focused governance test to verify it fails**
835
+
836
+ Run:
837
+
838
+ ```bash
839
+ node --test test/skill-governance.test.mjs -t "keeps public docs structurally valid"
840
+ ```
841
+
842
+ Expected: FAIL because the README files do not mention the new install flag or context rule.
843
+
844
+ - [ ] **Step 3: Update README context documentation**
845
+
846
+ In `README.md`, after the `Local agent memory lives under .loopx/memory/` paragraph, add:
847
+
848
+ ```md
849
+ ## Repo Specs And Memory
850
+
851
+ `docs/loopx/specs/` is binding long-lived repo context. Agents using loopx skills should inspect relevant specs before clarify, spec, plan, implementation, or review. `docs/loopx/specs/index.md` is useful as a map when present, but it is not required.
852
+
853
+ `.loopx/memory/MEMORY.md` is advisory curated memory. Memory can help future agents avoid rework and preserve decisions, but it must not override current user instructions, named source documents, or repo specs.
854
+ ```
855
+
856
+ Add the new install command example:
857
+
858
+ ```bash
859
+ loopx install-skills --target all --add-agent-guidance
860
+ ```
861
+
862
+ And update the CLI usage line to include `--add-agent-guidance`.
863
+
864
+ Add a short sentence to Installation explaining that the flag writes an opt-in managed block to Codex `~/.codex/AGENTS.md` and Claude `~/.claude/CLAUDE.md` for user-level installs. For Claude project installs, document that the target guidance file is the repository `CLAUDE.md`.
865
+
866
+ - [ ] **Step 4: Update Chinese README with matching literals**
867
+
868
+ In `README.zh-CN.md`, add a Chinese explanation under the memory paragraph while preserving the exact asserted English literals:
869
+
870
+ ```md
871
+ ## Repo Specs And Memory
872
+
873
+ `docs/loopx/specs/` is binding long-lived repo context。使用 loopx skills 的 agent 在 clarify、spec、plan、implementation 或 review 前,应读取与当前领域、文件或 workflow 行为相关的 spec。`docs/loopx/specs/index.md` 可以作为索引,但不是必需协议。
874
+
875
+ `.loopx/memory/MEMORY.md` is advisory curated memory。Memory 用来帮助未来 agent 避免重复踩坑和保留决策,但不能覆盖当前用户指令、明确指定的 source document 或 repo specs。
876
+ ```
877
+
878
+ Add the same command example and CLI usage flag as in `README.md`.
879
+
880
+ - [ ] **Step 5: Run focused governance test to verify it passes**
881
+
882
+ Run:
883
+
884
+ ```bash
885
+ node --test test/skill-governance.test.mjs -t "keeps public docs structurally valid"
886
+ ```
887
+
888
+ Expected: PASS.
889
+
890
+ - [ ] **Step 6: Commit**
891
+
892
+ ```bash
893
+ git add README.md README.zh-CN.md test/skill-governance.test.mjs
894
+ git commit -m "docs: document loopx specs and memory context"
895
+ ```
896
+
897
+ ### Task 6: Full Verification
898
+
899
+ **Files:**
900
+ - No source edits expected unless verification exposes a defect.
901
+
902
+ - [ ] **Step 1: Run the full test suite**
903
+
904
+ Run:
905
+
906
+ ```bash
907
+ npm test
908
+ ```
909
+
910
+ Expected: PASS for all `node --test test/*.test.mjs` suites.
911
+
912
+ - [ ] **Step 2: Run skill verifier**
913
+
914
+ Run:
915
+
916
+ ```bash
917
+ node scripts/verify-skills.mjs
918
+ ```
919
+
920
+ Expected: PASS with no plugin mirror drift or frontmatter failures.
921
+
922
+ - [ ] **Step 3: Inspect git diff for generated state**
923
+
924
+ Run:
925
+
926
+ ```bash
927
+ git status --short
928
+ ```
929
+
930
+ Expected: only intentional source, docs, skill, and test files are changed. No `.loopx/`, ad hoc local runtime state, or generated install output should be staged.
931
+
932
+ - [ ] **Step 4: Commit final verification fixes if any**
933
+
934
+ If verification required any fixes, commit them:
935
+
936
+ ```bash
937
+ git add <fixed-files>
938
+ git commit -m "fix: stabilize loopx context loading"
939
+ ```
940
+
941
+ Expected: no commit is needed if Tasks 1-5 already pass cleanly.
942
+
943
+ ## Self-Review
944
+
945
+ - Spec coverage: The plan covers skill-level behavior for clarify/spec/plan, runtime discovery, plan/build/review context injection, optional Codex `AGENTS.md` and Claude `CLAUDE.md` guidance, and public docs.
946
+ - Placeholder scan: No `TBD`, `TODO`, or unspecified implementation step remains. Each code-changing task has exact files, test commands, and expected output.
947
+ - Type consistency: New runtime API is consistently named `discoverLoopxContextArtifacts`; manifest kinds are `repo-specs`, `repo-spec`, `memory-summary`, and `memory-index`; install result field is `agentGuidance`.
948
+ - Design drift: The plan keeps `docs/loopx/specs/index.md` optional, does not silently edit global `AGENTS.md` or `CLAUDE.md`, and treats memory as advisory rather than binding.