@andares/pi-toolkits 0.10.0 → 0.11.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.
@@ -0,0 +1,131 @@
1
+ /**
2
+ * init feature — markdown fragments shared by the plan, the scaffold and the
3
+ * work order. Kept language-aware: the framework's own text is English, but
4
+ * anything written into a project follows that project's language.
5
+ */
6
+ import {
7
+ MEMORY_DIR,
8
+ MEMORY_FILES,
9
+ PLAN_FILE,
10
+ SPECS_DIR,
11
+ type MemoryRole,
12
+ type ProjectLanguage,
13
+ } from "./spec.js";
14
+ import type { Facts, RootInfo } from "./types.js";
15
+
16
+ const READ_WHEN: Record<MemoryRole, { zh: string; en: string }> = {
17
+ contract: { zh: "写记忆之前", en: "before writing memory" },
18
+ finished: { zh: "收口工作、查历史证据", en: "closing work, tracing evidence" },
19
+ future: { zh: "决定延期/放弃之前", en: "before deferring or rejecting work" },
20
+ architecture: { zh: "改分层、选型、跨模块改动前", en: "layering, versions, cross-module changes" },
21
+ design: { zh: "动界面视觉之前", en: "before touching visual design" },
22
+ terms: { zh: "命名、文案、界面术语之前", en: "naming, copy, UI terminology" },
23
+ review: { zh: "周期性评审、方向修正", en: "periodic review, direction changes" },
24
+ debugging: { zh: "排查运行期问题", en: "diagnosing runtime problems" },
25
+ function: { zh: "改这个模块的功能之前", en: "before changing that module" },
26
+ };
27
+
28
+ const INDEX_TITLES: Record<ProjectLanguage, { plan: string; memory: string; none: string }> = {
29
+ zh: { plan: "计划", memory: "记忆", none: "_(尚未出现)_" },
30
+ en: { plan: "Plan", memory: "Memory", none: "_(none yet)_" },
31
+ };
32
+
33
+ /** Rows for the plan table of the AGENTS.md index. */
34
+ export function planIndexRows(language: ProjectLanguage): string[] {
35
+ if (language === "zh") {
36
+ return [
37
+ `| \`${PLAN_FILE}\` | 路线级计划与未决问题 | 开工前 |`,
38
+ `| \`${SPECS_DIR}/<unit>.md\` | 单工作单元:需求原文 / 方案 / 验收清单 | 做这个单元时 |`,
39
+ ];
40
+ }
41
+ return [
42
+ `| \`${PLAN_FILE}\` | Route-level plan and open questions | before starting work |`,
43
+ `| \`${SPECS_DIR}/<unit>.md\` | One unit of work: requirement / approach / acceptance | when doing that unit |`,
44
+ ];
45
+ }
46
+
47
+ /** Rows for the memory table: files that exist now plus the core ones created now. */
48
+ export function memoryIndexRows(
49
+ facts: Facts,
50
+ language: ProjectLanguage,
51
+ created: ReadonlySet<string>,
52
+ ): string[] {
53
+ const rows: string[] = [];
54
+ for (const spec of MEMORY_FILES) {
55
+ const rel = `${MEMORY_DIR}/${spec.file}`;
56
+ const present = facts.memory.some((doc) => doc.rel === rel);
57
+ const legacyPresent = facts.legacyMemory.some(
58
+ (doc) => doc.rel === `memory/${spec.file}`,
59
+ );
60
+ const willExist = present || legacyPresent || created.has(rel);
61
+ if (!willExist) continue;
62
+ const label = spec.file.startsWith("FUNCTION-")
63
+ ? `${MEMORY_DIR}/FUNCTION-<MODULE>.md`
64
+ : rel;
65
+ rows.push(
66
+ language === "zh"
67
+ ? `| \`${label}\` | ${spec.owns} | ${READ_WHEN[spec.role].zh} |`
68
+ : `| \`${label}\` | ${spec.owns} | ${READ_WHEN[spec.role].en} |`,
69
+ );
70
+ }
71
+ if (created.has(`${MEMORY_DIR}/README.md`)) {
72
+ rows.unshift(
73
+ language === "zh"
74
+ ? `| \`${MEMORY_DIR}/README.md\` | 框架契约:文件职责、写入规则、预算、压缩法 | 写记忆之前 |`
75
+ : `| \`${MEMORY_DIR}/README.md\` | Framework contract: roles, write rules, budgets, compaction | before writing memory |`,
76
+ );
77
+ }
78
+ return rows;
79
+ }
80
+
81
+ /** The AGENTS.md index body (two labelled tables). */
82
+ export function indexBlock(
83
+ facts: Facts,
84
+ language: ProjectLanguage,
85
+ created: ReadonlySet<string>,
86
+ ): string {
87
+ const titles = INDEX_TITLES[language];
88
+ const planRows = planIndexRows(language);
89
+ const memoryRows = memoryIndexRows(facts, language, created);
90
+ const header =
91
+ language === "zh" ? "| 文件 | 拥有什么 | 何时读 |\n| --- | --- | --- |" : "| File | Owns | Read when |\n| --- | --- | --- |";
92
+ const parts = [
93
+ `### ${titles.plan}`,
94
+ "",
95
+ header,
96
+ ...planRows,
97
+ "",
98
+ `### ${titles.memory}`,
99
+ "",
100
+ header,
101
+ ...(memoryRows.length > 0 ? memoryRows : [titles.none]),
102
+ ];
103
+ return parts.join("\n");
104
+ }
105
+
106
+ /** The workspace-roots section, or an empty string when there are no roots. */
107
+ export function rootsBlock(roots: readonly RootInfo[], language: ProjectLanguage): string {
108
+ if (roots.length === 0) return "";
109
+ const title = language === "zh" ? "工作区根(多仓库)" : "Workspace roots";
110
+ const note =
111
+ language === "zh"
112
+ ? "> 记忆只住在主仓;下列目录的 `AGENTS.md` 只写本仓职责与本仓命令(≤30 行),不复制规则。"
113
+ : "> Memory lives in the main repository only. A listed root's `AGENTS.md` states its role and commands (≤30 lines), never a copy of the rules.";
114
+ const header =
115
+ language === "zh"
116
+ ? "| 根 | 路径 | 职责 | 它的记忆 |\n| --- | --- | --- | --- |"
117
+ : "| Root | Path | Role | Its memory |\n| --- | --- | --- | --- |";
118
+ const rows = roots.map((root) => {
119
+ const memory =
120
+ root.agentsMd === "independent"
121
+ ? language === "zh"
122
+ ? "独立项目(自带记忆,不接管)"
123
+ : "independent project (owns its memory)"
124
+ : language === "zh"
125
+ ? `主仓 \`${MEMORY_DIR}/\``
126
+ : `main repo \`${MEMORY_DIR}/\``;
127
+ const role = root.role ?? (language === "zh" ? "待补充" : "to be filled in");
128
+ return `| ${root.label} | \`${root.path}\`${root.exists ? "" : " (missing)"} | ${role} | ${memory} |`;
129
+ });
130
+ return [`## ${title}`, "", note, "", header, ...rows, ""].join("\n");
131
+ }
@@ -0,0 +1,429 @@
1
+ /**
2
+ * init feature — the agent-framework contract, as data.
3
+ *
4
+ * This file is the single source of truth for *where* the framework lives and
5
+ * *what it expects*. Everything else (detect / plan / apply / audit) reads it,
6
+ * so a layout change is one edit here plus a migration recipe.
7
+ *
8
+ * Layout principle (operator decision, 2026-10-26):
9
+ * - purely agent-facing content lives under `.agents/` (hidden, less noise at
10
+ * the repo root);
11
+ * - content people read stays at the root (`specs/`, `design/`, `docs/`, `legal/`).
12
+ *
13
+ * The three-way split is deliberate:
14
+ * `specs/` — the plan: what to do, how to accept it
15
+ * `.agents/memory/` — memory: what is known, decided, why
16
+ * `.agents/implementations/` — evidence: what was changed, when, with proof
17
+ * `.agents/prompts/` — input: the operator's own words (optional)
18
+ *
19
+ * `todos/` is retired: a requirement becomes a spec, and the verbatim wording
20
+ * goes into that spec's "requirement" section instead of a second directory.
21
+ */
22
+
23
+ /** Bump when the contract changes in a way existing projects must migrate. */
24
+ export const FRAMEWORK_VERSION = 1;
25
+
26
+ /** Identity written into state and reports. */
27
+ export const FRAMEWORK_ID = "agent-framework";
28
+
29
+ /* -------------------------------------------------------------------------- */
30
+ /* Paths */
31
+ /* -------------------------------------------------------------------------- */
32
+
33
+ export const AGENTS_FILE = "AGENTS.md";
34
+ export const CLAUDE_FILE = "CLAUDE.md";
35
+ export const OVERRIDE_FILE = "AGENTS.override.md";
36
+
37
+ /** Hidden home of everything that exists only for the agent. */
38
+ export const AGENTS_DIR = ".agents";
39
+ export const MEMORY_DIR = ".agents/memory";
40
+ export const IMPLEMENTATIONS_DIR = ".agents/implementations";
41
+ export const PROMPTS_DIR = ".agents/prompts";
42
+ export const FRAMEWORK_DIR = ".agents/framework";
43
+
44
+ export const STATE_FILE = ".agents/framework/state.toml";
45
+ export const STATE_GITIGNORE = ".agents/framework/.gitignore";
46
+ export const SNAPSHOTS_DIR = ".agents/framework/snapshots";
47
+ export const PLANS_DIR = ".agents/framework/plans";
48
+ export const REPORTS_DIR = ".agents/framework/reports";
49
+
50
+ /** The plan home stays at the root: humans review it. */
51
+ export const SPECS_DIR = "specs";
52
+ export const PLAN_FILE = "specs/PLAN.md";
53
+
54
+ /** The contract every agent reads before writing memory. */
55
+ export const CONTRACT_FILE = ".agents/memory/README.md";
56
+ /** A one-screen signpost for whoever opens `.agents/` first. */
57
+ export const SIGNPOST_FILE = ".agents/README.md";
58
+ /** Optional cascade of remembered decisions and functional specs. */
59
+ export const FUNCTION_PREFIX = "FUNCTION-";
60
+
61
+ /** Root-level plan/requirement files this framework supersedes. */
62
+ export const LEGACY_DOC_NAMES = [
63
+ "TODO.md",
64
+ "TASKS.md",
65
+ "ROADMAP.md",
66
+ "NOTES.md",
67
+ "DEVNOTES.md",
68
+ "DEVELOPMENT.md",
69
+ "PLAN.md",
70
+ ];
71
+
72
+ /** Directories that belong under `.agents/` in this framework. */
73
+ export const DEPRECATED_ROOT_DIRS = ["memory", "implementations", "prompts"] as const;
74
+
75
+ /** Retired entirely: requirement wording moves into `specs/<unit>.md`. */
76
+ export const RETIRED_ROOT_DIRS = ["todos"] as const;
77
+
78
+ /* -------------------------------------------------------------------------- */
79
+ /* Budgets */
80
+ /* -------------------------------------------------------------------------- */
81
+
82
+ /**
83
+ * AGENTS.md is paid for on *every* request, so it is the one file with a hard
84
+ * budget. `memory/*.md` is read on demand: its budget is about navigability,
85
+ * not tokens.
86
+ */
87
+ export const BUDGETS = {
88
+ /** Soft ceiling: the audit starts warning here. */
89
+ agentsMdSoftChars: 12_000,
90
+ /** Hard ceiling: the plan records the overflow as debt that must be paid. */
91
+ agentsMdHardChars: 20_000,
92
+ /** A memory file past this is hard to navigate; split or archive. */
93
+ memoryFileChars: 80_000,
94
+ /** Above this many change records, roll old ones up and archive them. */
95
+ implementationsFiles: 200,
96
+ } as const;
97
+
98
+ /* -------------------------------------------------------------------------- */
99
+ /* Memory files */
100
+ /* -------------------------------------------------------------------------- */
101
+
102
+ export type MemoryRole =
103
+ | "contract"
104
+ | "finished"
105
+ | "future"
106
+ | "architecture"
107
+ | "design"
108
+ | "terms"
109
+ | "review"
110
+ | "debugging"
111
+ | "function";
112
+
113
+ export interface MemoryFileSpec {
114
+ /** File name inside `.agents/memory/` (or `FUNCTION-*` pattern). */
115
+ readonly file: string;
116
+ readonly role: MemoryRole;
117
+ /** Always created (with a short seed) versus lazily on first use. */
118
+ readonly core: boolean;
119
+ /** One-line "owns what", used in plans, seeds and the index. */
120
+ readonly owns: string;
121
+ /** What must never be written there. */
122
+ readonly never: string;
123
+ }
124
+
125
+ export const MEMORY_FILES: readonly MemoryFileSpec[] = [
126
+ {
127
+ file: "FINISHED.md",
128
+ role: "finished",
129
+ core: true,
130
+ owns: "closed work: summary + evidence pointer + historical appendices",
131
+ never: "spec bodies, duplicated progress lists",
132
+ },
133
+ {
134
+ file: "FUTURE.md",
135
+ role: "future",
136
+ core: true,
137
+ owns: "deferred / rejected / waiting-for-a-trigger registry",
138
+ never: "schedule promises, half-plans that belong in specs/",
139
+ },
140
+ {
141
+ file: "ARCHITECTURE.md",
142
+ role: "architecture",
143
+ core: true,
144
+ owns: "layering, version baseline, decision records, investigation archive",
145
+ never: "visual specs, progress, functional behaviour owned by FUNCTION-*",
146
+ },
147
+ {
148
+ file: "DESIGN.md",
149
+ role: "design",
150
+ core: false,
151
+ owns: "visual single source of truth: tokens, palette, spacing, component looks",
152
+ never: "implementation details, component inventories",
153
+ },
154
+ {
155
+ file: "TERMS.md",
156
+ role: "terms",
157
+ core: false,
158
+ owns: "glossary and the discriminating rules behind each term",
159
+ never: "visual specs, API documentation",
160
+ },
161
+ {
162
+ file: "REVIEW.md",
163
+ role: "review",
164
+ core: false,
165
+ owns: "review ledger: judgement, trade-off, destination",
166
+ never: "a second copy of any spec",
167
+ },
168
+ {
169
+ file: "DEBUGGING.md",
170
+ role: "debugging",
171
+ core: false,
172
+ owns: "runtime diagnosis runbook (logs, crash dumps, live attach)",
173
+ never: "code facts that belong in ARCHITECTURE",
174
+ },
175
+ {
176
+ file: "FUNCTION-<MODULE>.md",
177
+ role: "function",
178
+ core: false,
179
+ owns: "one module's functional specification and its exact rules",
180
+ never: "copies of another module's rules",
181
+ },
182
+ ];
183
+
184
+ /** Memory file names that are recognised when auditing an existing project. */
185
+ export function isMemoryFileName(name: string): boolean {
186
+ if (MEMORY_FILES.some((spec) => spec.file === name)) return true;
187
+ return name.startsWith(FUNCTION_PREFIX) && name.endsWith(".md");
188
+ }
189
+
190
+ /* -------------------------------------------------------------------------- */
191
+ /* Optional root modules */
192
+ /* -------------------------------------------------------------------------- */
193
+
194
+ export interface RootModuleSpec {
195
+ readonly dir: string;
196
+ /** What the directory is for, in one line (English: shipped text). */
197
+ readonly owns: string;
198
+ }
199
+
200
+ export const ROOT_MODULES: readonly RootModuleSpec[] = [
201
+ { dir: "specs", owns: "plans and unit specs (the plan home)" },
202
+ { dir: "design", owns: "design sources and their paired notes" },
203
+ { dir: "docs", owns: "user- and contributor-facing documentation" },
204
+ { dir: "legal", owns: "license originals, third-party notices and provenance" },
205
+ ];
206
+
207
+ /* -------------------------------------------------------------------------- */
208
+ /* Scan limits */
209
+ /* -------------------------------------------------------------------------- */
210
+
211
+ export const SCAN = {
212
+ /** Files bigger than this are read for metadata only, never for content. */
213
+ maxFileBytes: 1_500_000,
214
+ /** Cap the tree walk so a runaway repo cannot stall the command. */
215
+ maxFiles: 20_000,
216
+ /** Depth for the generic walk. */
217
+ maxDepth: 6,
218
+ /** Directory names never descended into. */
219
+ ignoreDirs: new Set([
220
+ ".git",
221
+ "node_modules",
222
+ "target",
223
+ "dist",
224
+ "build",
225
+ "out",
226
+ "release-out",
227
+ ".venv",
228
+ "venv",
229
+ "__pycache__",
230
+ ".cache",
231
+ ".turbo",
232
+ ".next",
233
+ "coverage",
234
+ ".pytest_cache",
235
+ ".mypy_cache",
236
+ ]),
237
+ /** Text extensions counted for path references. */
238
+ refExtensions: new Set([
239
+ ".md",
240
+ ".mdx",
241
+ ".ts",
242
+ ".tsx",
243
+ ".js",
244
+ ".mjs",
245
+ ".cjs",
246
+ ".mts",
247
+ ".cts",
248
+ ".rs",
249
+ ".toml",
250
+ ".json",
251
+ ".yml",
252
+ ".yaml",
253
+ ".txt",
254
+ ".html",
255
+ ".css",
256
+ ".scss",
257
+ ".py",
258
+ ".sh",
259
+ ".fish",
260
+ ".pd",
261
+ ".nix",
262
+ ".go",
263
+ ".java",
264
+ ".kt",
265
+ ".swift",
266
+ ".c",
267
+ ".h",
268
+ ".cc",
269
+ ".cpp",
270
+ ]),
271
+ } as const;
272
+
273
+ /* -------------------------------------------------------------------------- */
274
+ /* Audit vocabulary */
275
+ /* -------------------------------------------------------------------------- */
276
+
277
+ export const AUDIT_CODES = {
278
+ pathBareRef: "E-PATH-01",
279
+ stateUntracked: "E-STATE-01",
280
+ stateUncommitted: "W-STATE-01",
281
+ stateVersion: "E-STATE-02",
282
+ indexMismatch: "E-INDEX-01",
283
+ brokenLink: "E-LINK-01",
284
+ rootAgentDir: "W-ROOT-01",
285
+ rootEmptyFile: "W-ROOT-02",
286
+ rootMissing: "W-ROOT-03",
287
+ rootCardTooBig: "W-ROOT-04",
288
+ todosRemain: "W-TODO-01",
289
+ budgetAgents: "W-BUDGET-01",
290
+ budgetMemory: "W-BUDGET-02",
291
+ duplicateFact: "W-DUP-01",
292
+ appendixOrder: "W-ORDER-01",
293
+ coverageOpen: "W-COV-01",
294
+ futureNoTrigger: "W-META-01",
295
+ finishedNoEvidence: "W-EVID-01",
296
+ overrideContext: "W-OVERRIDE-01",
297
+ contractMissing: "E-CONTRACT-01",
298
+ scaffoldLeftover: "W-SCAFFOLD-01",
299
+ agentsSkills: "I-AGENTS-01",
300
+ notInstalled: "I-INSTALL-01",
301
+ planSpecDrift: "W-PLAN-01",
302
+ } as const;
303
+
304
+ export type AuditCode = (typeof AUDIT_CODES)[keyof typeof AUDIT_CODES];
305
+
306
+ /* -------------------------------------------------------------------------- */
307
+ /* Messages */
308
+ /* -------------------------------------------------------------------------- */
309
+
310
+ /**
311
+ * Framework-owned text (contract, plan headers, audit codes) ships in English:
312
+ * it is read by models and published on npm. Text *written into a project*
313
+ * follows that project's language (`zh` when its docs are mostly CJK).
314
+ */
315
+ export type ProjectLanguage = "zh" | "en";
316
+
317
+ /** Seed bodies for core memory files, kept deliberately tiny. */
318
+ export const SEEDS: Record<ProjectLanguage, Record<string, string>> = {
319
+ en: {
320
+ finished: [
321
+ "# Finished work",
322
+ "",
323
+ "> Closed work only: a summary, the evidence pointer, and the historical appendix.",
324
+ "> Never restate a spec here; link to it. Never keep an open item here.",
325
+ "",
326
+ "## Summary",
327
+ "",
328
+ "_Nothing closed yet._",
329
+ "",
330
+ ].join("\n"),
331
+ future: [
332
+ "# Future and deferred",
333
+ "",
334
+ "> Every entry needs: what, why it waits, and the trigger that would bring it back.",
335
+ "> Adopted entries move to `specs/PLAN.md` and leave a one-line pointer behind.",
336
+ "",
337
+ "_Nothing registered yet._",
338
+ "",
339
+ ].join("\n"),
340
+ architecture: [
341
+ "# Architecture",
342
+ "",
343
+ "> Layering, version baseline, decision records (context / decision / consequence / date)",
344
+ "> and the investigation archive. One fact, one home.",
345
+ "",
346
+ "## Layering",
347
+ "",
348
+ "_To be filled in by the init run (evidence only — read the code, do not guess)._",
349
+ "",
350
+ "## Decisions",
351
+ "",
352
+ "_No decisions recorded yet._",
353
+ "",
354
+ ].join("\n"),
355
+ },
356
+ zh: {
357
+ finished: [
358
+ "# 已完成",
359
+ "",
360
+ "> 只放已收口的工作:摘要、证据指针、历史附录。",
361
+ "> 不在这里重述规格(给指针),也不留未完成项。",
362
+ "",
363
+ "## 摘要",
364
+ "",
365
+ "_还没有已收口的条目。_",
366
+ "",
367
+ ].join("\n"),
368
+ future: [
369
+ "# 远期与延期",
370
+ "",
371
+ "> 每条必须写清:是什么、为什么等、什么条件会把它拉回来(触发条件)。",
372
+ "> 被采纳的条目移入 `specs/PLAN.md`,这里留一行指针。",
373
+ "",
374
+ "_还没有登记。_",
375
+ "",
376
+ ].join("\n"),
377
+ architecture: [
378
+ "# 架构与决策",
379
+ "",
380
+ "> 分层、版本基线、决策记录(背景 / 决定 / 后果 / 日期)与调研存档。一个事实一个家。",
381
+ "",
382
+ "## 分层",
383
+ "",
384
+ "_由初始化那一轮填(只写读到的证据,不许猜)。_",
385
+ "",
386
+ "## 决策记录",
387
+ "",
388
+ "_还没有决策。_",
389
+ "",
390
+ ].join("\n"),
391
+ },
392
+ };
393
+
394
+ /** Seed body for `specs/PLAN.md`. */
395
+ export const PLAN_SEED: Record<ProjectLanguage, string> = {
396
+ en: [
397
+ "# Plan (open work)",
398
+ "",
399
+ "> Route-level plan and open questions only. A unit of work gets its own",
400
+ "> `specs/<unit>.md` before implementation starts; closed work moves to",
401
+ "> `.agents/memory/FINISHED.md` as a summary plus an evidence pointer.",
402
+ "> Progress itself lives in the todo tool — never here.",
403
+ "",
404
+ "## Route",
405
+ "",
406
+ "_No milestones recorded yet._",
407
+ "",
408
+ "## Open questions",
409
+ "",
410
+ "_None._",
411
+ "",
412
+ ].join("\n"),
413
+ zh: [
414
+ "# 计划(未完成)",
415
+ "",
416
+ "> 只放路线级计划与未决问题。每个工作单元开工前单独写 `specs/<unit>.md`;",
417
+ "> 已收口的工作移入 `.agents/memory/FINISHED.md`,只留摘要与证据指针。",
418
+ "> 进度本身只在 todo 工具里——这里不写。",
419
+ "",
420
+ "## 路线",
421
+ "",
422
+ "_还没有里程碑。_",
423
+ "",
424
+ "## 未决问题",
425
+ "",
426
+ "_无。_",
427
+ "",
428
+ ].join("\n"),
429
+ };
@@ -0,0 +1,44 @@
1
+ # {{project}} — {{docTitle}}
2
+
3
+ {{contract}}
4
+
5
+ > Created {{date}} by `/ask-init` (agent-framework v{{frameworkVersion}}).
6
+ <!-- TODO(ask-init): remove this line after reviewing the guide. -->
7
+
8
+ ## {{h_what}}
9
+
10
+ <!-- TODO(ask-init): one short paragraph: what this project is, who it serves, what it is not. Evidence only. -->
11
+
12
+ ## {{h_rules}}
13
+
14
+ <!-- TODO(ask-init): numbered invariants. Each ≤2 lines; a rule that needs detail points at the file that owns it. Never invent a rule: derive it from a manifest, a script, a CI gate, or an explicit decision. -->
15
+
16
+ ## {{h_commands}}
17
+
18
+ <!-- TODO(ask-init): copy-pasteable install / build / test / lint / run / release commands, read from manifests and CI. Mark anything unverified. -->
19
+
20
+ ## {{h_layout}}
21
+
22
+ <!-- TODO(ask-init): top-level tree with one line per entry, including .agents/ and specs/. -->
23
+
24
+ ## {{h_index}}
25
+
26
+ {{index}}
27
+
28
+ {{roots}}
29
+
30
+ ## {{h_impact}}
31
+
32
+ <!-- TODO(ask-init): change → code location → what else must be updated in the same change. Start with the areas the survey actually found. -->
33
+
34
+ ## {{h_terms}}
35
+
36
+ <!-- TODO(ask-init): only terms that get confused; the full glossary belongs in .agents/memory/TERMS.md. -->
37
+
38
+ ## {{h_maintenance}}
39
+
40
+ - framework: agent-framework v{{frameworkVersion}} (`{{statePath}}`)
41
+ - budgets: AGENTS.md soft {{softBudget}} / hard {{hardBudget}} characters; one memory file {{memoryBudget}}
42
+ - audit: `/ask-init check`
43
+ - before writing memory: read `{{contractPath}}`
44
+ - records: one file per change in `{{implementationsDir}}/`, first line carries the exact time