milens 0.7.1 → 0.7.3

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 (119) hide show
  1. package/.agents/skills/adapters/SKILL.md +59 -54
  2. package/.agents/skills/analyzer/SKILL.md +83 -78
  3. package/.agents/skills/apps/SKILL.md +65 -60
  4. package/.agents/skills/docs/SKILL.md +63 -58
  5. package/.agents/skills/milens/SKILL.md +322 -319
  6. package/.agents/skills/milens-security-review/SKILL.md +224 -224
  7. package/.agents/skills/orchestrator/SKILL.md +64 -59
  8. package/.agents/skills/parser/SKILL.md +86 -81
  9. package/.agents/skills/root/SKILL.md +89 -84
  10. package/.agents/skills/scripts/SKILL.md +56 -51
  11. package/.agents/skills/security/SKILL.md +67 -62
  12. package/.agents/skills/server/SKILL.md +84 -77
  13. package/.agents/skills/store/SKILL.md +77 -72
  14. package/.agents/skills/test/SKILL.md +155 -148
  15. package/.agents/skills/ui/SKILL.md +56 -51
  16. package/README.md +577 -577
  17. package/adapters/README.md +144 -144
  18. package/adapters/claude-code/.claude/mcp.json +9 -9
  19. package/adapters/claude-code/.claude/settings.json.hooks-snippet.json +26 -26
  20. package/adapters/claude-code/.claude-plugin/plugin.json +11 -11
  21. package/adapters/claude-code/.mcp.json +9 -9
  22. package/adapters/claude-code/CLAUDE.md +81 -79
  23. package/adapters/claude-code/hooks/hooks.json +27 -0
  24. package/adapters/codex/.codex/config.toml +3 -3
  25. package/adapters/copilot/.vscode/mcp.json +10 -10
  26. package/adapters/cursor/.cursor/mcp.json +9 -9
  27. package/adapters/cursor/.cursorrules +69 -69
  28. package/adapters/gemini/.gemini/context.md +81 -81
  29. package/adapters/gemini/.gemini/settings.json +9 -9
  30. package/adapters/opencode/.opencode/config.json +8 -8
  31. package/adapters/zed/.zed/settings.json +8 -8
  32. package/dist/agents-md.d.ts +1 -0
  33. package/dist/agents-md.js +45 -1
  34. package/dist/agents-md.js.map +1 -1
  35. package/dist/analyzer/config.js +32 -0
  36. package/dist/analyzer/config.js.map +1 -1
  37. package/dist/analyzer/engine.js +26 -2
  38. package/dist/analyzer/engine.js.map +1 -1
  39. package/dist/analyzer/enrich.js +68 -1
  40. package/dist/analyzer/enrich.js.map +1 -1
  41. package/dist/analyzer/resolver.d.ts +4 -1
  42. package/dist/analyzer/resolver.js +241 -38
  43. package/dist/analyzer/resolver.js.map +1 -1
  44. package/dist/analyzer/review.js +32 -2
  45. package/dist/analyzer/review.js.map +1 -1
  46. package/dist/analyzer/scanner.js +3 -0
  47. package/dist/analyzer/scanner.js.map +1 -1
  48. package/dist/analyzer/scope-resolver.js +1 -1
  49. package/dist/analyzer/scope-resolver.js.map +1 -1
  50. package/dist/build-info.d.ts +2 -2
  51. package/dist/build-info.js +2 -2
  52. package/dist/cli.js +566 -497
  53. package/dist/cli.js.map +1 -1
  54. package/dist/orchestrator/orchestrator.d.ts +1 -1
  55. package/dist/orchestrator/orchestrator.js +14 -6
  56. package/dist/orchestrator/orchestrator.js.map +1 -1
  57. package/dist/parser/extract.d.ts +7 -0
  58. package/dist/parser/extract.js +23 -1
  59. package/dist/parser/extract.js.map +1 -1
  60. package/dist/parser/lang-css.js +18 -6
  61. package/dist/parser/lang-css.js.map +1 -1
  62. package/dist/parser/lang-go.js +58 -58
  63. package/dist/parser/lang-html.js +3 -3
  64. package/dist/parser/lang-java.js +37 -37
  65. package/dist/parser/lang-js.js +120 -109
  66. package/dist/parser/lang-js.js.map +1 -1
  67. package/dist/parser/lang-md.js +1 -0
  68. package/dist/parser/lang-md.js.map +1 -1
  69. package/dist/parser/lang-php.js +45 -45
  70. package/dist/parser/lang-py.js +43 -43
  71. package/dist/parser/lang-ruby.js +28 -28
  72. package/dist/parser/lang-rust.js +48 -48
  73. package/dist/parser/lang-ts.js +230 -196
  74. package/dist/parser/lang-ts.js.map +1 -1
  75. package/dist/parser/lang-vue.js +0 -21
  76. package/dist/parser/lang-vue.js.map +1 -1
  77. package/dist/security/rules.js +22 -23
  78. package/dist/security/rules.js.map +1 -1
  79. package/dist/server/guard-hook.d.ts +10 -0
  80. package/dist/server/guard-hook.js +179 -0
  81. package/dist/server/guard-hook.js.map +1 -0
  82. package/dist/server/hooks.js +2 -1
  83. package/dist/server/hooks.js.map +1 -1
  84. package/dist/server/mcp-prompts.js +502 -502
  85. package/dist/server/mcp.js +228 -86
  86. package/dist/server/mcp.js.map +1 -1
  87. package/dist/server/test-plan.d.ts +1 -0
  88. package/dist/server/test-plan.js +25 -7
  89. package/dist/server/test-plan.js.map +1 -1
  90. package/dist/server/tools/findings-report.d.ts +3 -0
  91. package/dist/server/tools/findings-report.js +170 -0
  92. package/dist/server/tools/findings-report.js.map +1 -0
  93. package/dist/server/tools/security.js +61 -5
  94. package/dist/server/tools/security.js.map +1 -1
  95. package/dist/server/tools/session.js +37 -17
  96. package/dist/server/tools/session.js.map +1 -1
  97. package/dist/server/tools/testing.js +58 -11
  98. package/dist/server/tools/testing.js.map +1 -1
  99. package/dist/skills.js +307 -301
  100. package/dist/skills.js.map +1 -1
  101. package/dist/store/annotations.d.ts +5 -0
  102. package/dist/store/annotations.js +45 -9
  103. package/dist/store/annotations.js.map +1 -1
  104. package/dist/store/db.d.ts +13 -0
  105. package/dist/store/db.js +318 -205
  106. package/dist/store/db.js.map +1 -1
  107. package/dist/store/registry.d.ts +1 -0
  108. package/dist/store/registry.js +17 -6
  109. package/dist/store/registry.js.map +1 -1
  110. package/dist/store/schema.sql +144 -143
  111. package/dist/store/vectors.js +2 -2
  112. package/dist/types.d.ts +16 -1
  113. package/dist/uninstall.d.ts +1 -0
  114. package/dist/uninstall.js +33 -10
  115. package/dist/uninstall.js.map +1 -1
  116. package/dist/utils.d.ts +1 -1
  117. package/dist/utils.js +0 -0
  118. package/dist/utils.js.map +1 -1
  119. package/package.json +85 -85
package/dist/skills.js CHANGED
@@ -62,7 +62,7 @@ export function generateSkills(db, rootDir, editors) {
62
62
  writeFileSync(join(claudeAreaDir, 'SKILL.md'), content);
63
63
  // Also generate path-scoped rule (loaded when Claude reads matching files)
64
64
  if (area.prefix) {
65
- writeFileSync(join(claudeRulesDir, `${areaName}.md`), `---\npaths:\n - "${area.prefix}/**"\n---\n\n${content}`);
65
+ writeFileSync(join(claudeRulesDir, `${areaName}.md`), `---\ngenerated-by: milens\npaths:\n - "${area.prefix}/**"\n---\n\n${content}`);
66
66
  }
67
67
  }
68
68
  if (has('agents')) {
@@ -148,6 +148,7 @@ function buildCrossAreaLinks(links, symbolMap) {
148
148
  }
149
149
  function renderSkillContent(areaName, area, incomingCount, crossArea) {
150
150
  const lines = [];
151
+ lines.push('<!-- Generated by milens — safe to delete/regenerate -->');
151
152
  lines.push(`# ${capitalize(areaName)}`);
152
153
  lines.push('');
153
154
  lines.push('## Working with this area');
@@ -170,6 +171,9 @@ function renderSkillContent(areaName, area, incomingCount, crossArea) {
170
171
  lines.push('| Text search across files | `mcp_milens_grep` |');
171
172
  lines.push('| See file symbols | `mcp_milens_get_file_symbols` |');
172
173
  lines.push('');
174
+ lines.push('### Edit-safety enforcement');
175
+ lines.push('A `PreToolUse` hook (warn mode by default) reminds you if no milens safety check (`impact`/`context`/`overview`/`guard_edit_check`/`edit_check`/`smart_context`) was called before an `Edit`/`Write`/`MultiEdit`. Opt-in strict deny mode is available via `milens hooks guard-set-mode --mode strict`. Both modes consume the check after one edit. See `.milens/hook-state/config.json`. Known caveat: the underlying `PreToolUse` deny mechanism has at least one reliability issue (https://github.com/anthropics/claude-code/issues/4362).');
176
+ lines.push('');
173
177
  lines.push('## Overview');
174
178
  lines.push(`Contains ${area.symbols.length} symbols (${area.exported.length} exported) across ${area.files.size} files.`);
175
179
  lines.push('');
@@ -230,14 +234,14 @@ function capitalize(s) {
230
234
  function renderCopilot(area, content) {
231
235
  if (!area.prefix)
232
236
  return content;
233
- return `---\napplyTo: "${area.prefix}/**"\n---\n\n${content}`;
237
+ return `---\ngenerated-by: milens\napplyTo: "${area.prefix}/**"\n---\n\n${content}`;
234
238
  }
235
239
  function renderCursor(area, content) {
236
240
  const glob = area.prefix ? `${area.prefix}/**` : '**';
237
- return `---\ndescription: Code intelligence for ${area.name} area\nglobs: ${glob}\nalwaysApply: false\n---\n\n${content}`;
241
+ return `---\ngenerated-by: milens\ndescription: Code intelligence for ${area.name} area\nglobs: ${glob}\nalwaysApply: false\n---\n\n${content}`;
238
242
  }
239
243
  function renderAgentSkill(areaName, content) {
240
- return `---\nname: milens-${areaName}\ndescription: Code intelligence for the ${areaName} area — symbols, dependencies, and entry points\n---\n\n${content}`;
244
+ return `---\ngenerated-by: milens\nname: milens-${areaName}\ndescription: Code intelligence for the ${areaName} area — symbols, dependencies, and entry points\n---\n\n${content}`;
241
245
  }
242
246
  function editorSkillPath(editor, name) {
243
247
  switch (editor) {
@@ -254,307 +258,309 @@ function renderMilensInstructions(_rootDir, stats, areaNames, editor) {
254
258
  const domainRows = areaNames.map(a => `| Work in the ${capitalize(a)} area | \`${editorSkillPath(editor, a)}\` |`).join('\n');
255
259
  const workflowRows = workflowSkillNames.map(a => `| Execute ${a} workflow | \`${editorSkillPath(editor, a)}\` |`).join('\n');
256
260
  const skillsRows = domainRows + '\n' + workflowRows;
257
- return `<!-- milens:start -->
258
- # Milens — AI-DOS
259
-
260
- The Operating System for AI-Driven Development. This project is indexed by milens (${stats.symbols} symbols, ${stats.links} links, ${stats.files} files).
261
-
262
- > **CRITICAL:** All milens MCP tool calls MUST include the \`repo\` parameter set to the **absolute path of the workspace root** (the folder containing this file) — without it, the tools may fail with "No index" error when multiple repos are indexed.
263
-
264
- > **CRITICAL:** milens MCP tools are **deferred** in most editors. Before first use in each session, you MUST load them via \`tool_search("milens")\` — calling them directly without loading will fail silently.
265
-
266
- ## ⚠️ HARD RULE: Use Milens MCP Tools BEFORE Built-in Tools
267
-
268
- **Not a suggestion — execute automatically without asking.**
269
-
270
- This project is indexed by milens. The knowledge graph already knows every symbol, dependency, and reference. Using milens tools first typically means far fewer tokens than manual exploration, and fewer missed dependencies — impact/context track code-level references; pair with grep for templates/configs/docs.
271
-
272
- | Situation | Built-in approach (❌ BAD) | Milens approach (✅ GOOD) |
273
- |---|---|---|
274
- | Understand a function | Read 3-10 source files | \`${t('overview')}({name: "X"})\` — 1 call replaces 3-5 file reads |
275
- | Find all references | Built-in grep in source files | \`${t('grep')}({pattern: "X"})\` — searches code, templates, configs, docs, styles |
276
- | Check edit safety | Hope nothing breaks | \`${t('impact')}({target: "X"})\` — exact blast radius before touching code |
277
- | Start working | Read README, explore directories | \`${t('codebase_summary')}()\` — 500 token project overview |
278
- | Before commit | \`git diff\` manually | \`${t('detect_changes')}()\` — symbols changed + direct dependents + risk |
279
- | Find where X is defined | Read files one by one | \`${t('query')}({query: "X"})\` — FTS5 instant search |
280
-
281
- **If you skip milens tools, you're wasting tokens and risking breaking changes you didn't know about.**
282
-
283
- ## Mandatory Workflows
284
-
285
- These are **hard pre-conditions**, not guidelines. Execute them automatically without asking.
286
-
287
- ### Before editing any function, class, or method:
288
- 1. \`${t('impact')}({target: "<symbolName>", repo: "<workspaceRoot>"})\` — check blast radius
289
- 2. If depth-1 dependents > 5 → **STOP and warn the user** before proceeding
290
- 3. \`${t('context')}({name: "<symbolName>", repo: "<workspaceRoot>"})\` — see all callers/callees
291
- 4. Only then make the edit
292
-
293
- ### Before committing:
294
- 1. \`${t('detect_changes')}({repo: "<workspaceRoot>"})\` — verify only expected files changed
295
- 2. If unexpected files appear → **STOP and report** before committing
296
-
297
- ### Before deleting or renaming a symbol:
298
- 1. \`${t('grep')}({pattern: "<symbolName>", repo: "<workspaceRoot>"})\` — find ALL text references (templates, configs, routes, docs)
299
- 2. \`${t('impact')}({target: "<symbolName>", direction: "upstream", repo: "<workspaceRoot>"})\` — find code-level dependents
300
- 3. Combine both results — grep catches what impact misses
301
-
302
- ## Tool Selection Rules
303
-
304
- **Choose the right tool on the FIRST call** — do not try \`query\` then fall back to \`grep\`.
305
-
306
- ### Use \`${t('grep')}\` when the search term:
307
- - Contains **spaces** (e.g. "store purchase header", "user not found")
308
- - Looks like a **UI label, error message, or display string**
309
- - Is a **multi-word phrase** that is NOT camelCase/snake_case/PascalCase
310
- - You need to find references in **templates, styles, configs, routes, or docs**
311
-
312
- ### Use \`${t('query')}\` when the search term:
313
- - Looks like a **code identifier** (camelCase, PascalCase, snake_case)
314
- - Is a **function, class, method, or interface name**
315
- - You want to find **symbol definitions** in indexed code files
316
-
317
- ### When in doubt → use \`${t('grep')}\` first
318
- \`grep\` searches everything. \`query\` only searches indexed symbol definitions.
319
-
320
- > **⚠️ \`${t('grep')}\` default is LITERAL mode (isRegex: false).** Characters \`| . * + ?\` are escaped as plain text. To use regex patterns like \`error|fail|panic\` or \`TODO.*urgent\`, you MUST set \`isRegex: true\`. The tool will warn you if you forget.
321
-
322
- ## Workflow Triggers
323
-
324
- When the user says... → do this FIRST:
325
-
326
- | User intent | First action |
327
- |---|---|
328
- | "edit/change/modify/fix \`X\`" | \`${t('impact')}({target: "X", repo: "<workspaceRoot>"})\` |
329
- | "delete/remove \`X\`" | \`${t('grep')}({pattern: "X", repo: "<workspaceRoot>"})\` then \`${t('impact')}\` |
330
- | "rename \`X\`" | \`${t('grep')}({pattern: "X", repo: "<workspaceRoot>"})\` then \`${t('impact')}\` |
331
- | "find/search for \`X\`" | Choose \`query\` or \`grep\` per rules above |
332
- | "commit" / "push" | \`${t('detect_changes')}({repo: "<workspaceRoot>"})\` |
333
- | "what calls/uses \`X\`" | \`${t('context')}({name: "X", repo: "<workspaceRoot>"})\` |
334
- | "what happens if I change \`X\`" | \`${t('impact')}({target: "X", repo: "<workspaceRoot>"})\` |
335
- | "how are \`A\` and \`B\` connected" | \`${t('explain_relationship')}({from: "A", to: "B", repo: "<workspaceRoot>"})\` |
336
- | "explore/understand \`X\`" | \`${t('context')}({name: "X", repo: "<workspaceRoot>"})\` |
337
- | "update/write docs for \`X\`" | \`${t('grep')}({pattern: "X", include: "**/*.md"})\` — find existing docs mentioning X, then \`${t('context')}({name: "X"})\` for full symbol info |
338
- | "research/explore docs" | \`${t('get_file_symbols')}({file: "<doc.md>"})\` — see document outline (headings as sections) |
339
- | "what docs mention \`X\`" | \`${t('grep')}({pattern: "X", include: "**/*.md"})\` — find all markdown references |
340
- | "review this PR" | \`${t('review_pr')}({repo: "<workspaceRoot>"})\` — risk assessment for changed files |
341
- | "is \`X\` risky to change" | \`${t('review_symbol')}({name: "X", repo: "<workspaceRoot>"})\` |
342
- | "write tests for \`X\`" | \`${t('test_plan')}({name: "X", repo: "<workspaceRoot>"})\` — deps, mocks, suggested tests |
343
- | "what needs tests" | \`${t('test_coverage_gaps')}({repo: "<workspaceRoot>"})\` — untested symbols by risk |
344
- | "which tests to run" | \`${t('test_impact')}({repo: "<workspaceRoot>"})\` — maps changes → test files |
345
- | "remember/note that \`X\`..." | \`${t('annotate')}({symbol: "X", key: "note", value: "...", repo: "<workspaceRoot>"})\` |
346
- | "what do we know about \`X\`" | \`${t('recall')}({symbol: "X", repo: "<workspaceRoot>"})\` |
347
- | "start new session" | \`${t('session_start')}({agent: "...", repo: "<workspaceRoot>"})\` |
348
- | "find code like \`X\`" | \`${t('find_similar')}({name: "X", repo: "<workspaceRoot>"})\` |
349
- | "search for \`concept\`" | \`${t('semantic_search')}({query: "concept", repo: "<workspaceRoot>"})\` |
350
- | "generate tests for \`X\`" | \`${t('test_generate')}({symbol: "X", repo: "<workspaceRoot>"})\` |
351
- | "fix security issue in \`X\`" | \`${t('fix_apply')}({ruleId, file, line, repo: "<workspaceRoot>"})\` |
352
- | "remove dead code" | \`${t('find_dead_code')}()\` then \`dead_code_remove\` prompt |
353
- | "orchestrate/check changes" | \`${t('orchestrate')}({repo: "<workspaceRoot>"})\` |
354
- | "compare impact of \`X\`" | \`${t('compare_impact')}({name: "X", action: "snapshot"|"compare", repo: "<workspaceRoot>"})\` |
355
- | "check pre-commit" | \`${t('pre_commit_check')}({repo: "<workspaceRoot>"})\` |
356
- | "save/restore context" | \`${t('hook_preCompact')}()\` / \`${t('hook_postCompact')}()\` |
357
- | "scan security / audit security" | \`${t('security_scan')}({repo: "<workspaceRoot>"})\` — full audit across all 190 rules |
358
- | "end session" / "finish work" | \`${t('session_end')}({session_id: "..."})\` — record stats, trigger onSessionEnd hook |
359
- | "what did session X do" | \`${t('session_context')}({session_id: "..."})\` — get annotations + tool calls |
360
- | "file changed to X" | \`${t('hook_onFileChange')}({files: ["path/to/file"], repo: "<workspaceRoot>"})\` |
361
-
362
- ### Domain-aware skill triggers:
363
- | User intent | Skill to load |
364
- |---|---|
365
- | "I'm working on authentication/security" | Load \`milens-security\` skill + \`${t('security_scan')}()\` |
366
- | "I need to understand the parser" | Load \`milens-parser\` skill + \`${t('get_file_symbols')}({file: "src/parser/"})\` |
367
- | "I'm debugging a server issue" | Load \`milens-server\` skill + \`${t('trace')}()\` |
368
- | "I'm working with the database" | Load \`milens-store\` skill + \`${t('get_file_symbols')}({file: "src/store/"})\` |
369
- | "I need to write tests for this" | Load \`milens-tdd\` skill + \`${t('test_plan')}()\` |
370
- | "I'm planning a feature" | Load \`milens-plan\` skill + \`${t('codebase_summary')}()\` |
371
- | "I need to refactor this" | Load \`milens-refactor-clean\` skill + \`${t('impact')}()\` |
372
- | "Review my code changes" | Load \`milens-code-review\` skill + \`${t('review_pr')}()\` |
373
-
374
- ## Annotation Guide — Building a Smarter Codebase
375
-
376
- Every time you discover something important about a symbol, annotate it. The system learns across sessions — your note today saves tokens tomorrow.
377
-
378
- ### When to annotate:
379
- - Found a bug pattern? → \`${t('annotate')}({symbol: "X", key: "bug", value: "..."})\`
380
- - Discovered an architecture rule? → \`${t('annotate')}({symbol: "X", key: "architecture", value: "..."})\`
381
- - Learned how to test something? → \`${t('annotate')}({symbol: "X", key: "test", value: "..."})\`
382
- - Found a security issue? → \`${t('annotate')}({symbol: "X", key: "security", value: "..."})\`
383
- - Noted a hidden dependency? → \`${t('annotate')}({symbol: "X", key: "dependency", value: "..."})\`
384
-
385
- ### Annotation keys reference:
386
- | Key | Use when | Example value |
387
- |-----|----------|---------------|
388
- | \`bug\` | Known bug, not yet fixed | "NullPointerException when users is empty array" |
389
- | \`security\` | Security vulnerability | "No CSRF token validation on this endpoint" |
390
- | \`architecture\` | Design pattern, constraint | "Service is a singleton — don't instantiate directly" |
391
- | \`test\` | Testing knowledge | "Must mock Database.getConnection() before testing" |
392
- | \`dependency\` | Hidden coupling | "Imports from deprecated module old-auth.js" |
393
- | \`refactor\` | Future refactoring notes | "Split into validateEmail() + normalizeEmail()" |
394
- | \`workflow\` | Process knowledge | "Must restart dev server after modifying this file" |
395
- | \`note\` | General observation | "This function is called from cron job at 3AM" |
396
-
397
- ### Learning lifecycle:
398
- 1. **Session 1:** \`annotate()\` → confidence 0.5
399
- 2. **Session 2:** \`recall()\` sees it again → confidence 0.7
400
- 3. **Session 5:** confidence hits 0.8 → \`milens evolve\` promotes it to SKILL.md
401
-
402
- ### Annotate triggers:
403
- | User says... | Tool call |
404
- |---|---|
405
- | "found a bug in X" | \`${t('annotate')}({symbol: "X", key: "bug", value: "describe the bug"})\` |
406
- | "X has a security issue" | \`${t('annotate')}({symbol: "X", key: "security", value: "describe the issue"})\` |
407
- | "learned how X works" | \`${t('annotate')}({symbol: "X", key: "note", value: "key insight"})\` |
408
- | "X depends on Y internally" | \`${t('annotate')}({symbol: "X", key: "dependency", value: "depends on Y for Z"})\` |
409
- | "X needs refactoring later" | \`${t('annotate')}({symbol: "X", key: "refactor", value: "plan"})\` |
410
-
411
- ### At session end, ALWAYS:
412
- 1. \`${t('recall')}({})\` — review annotations you found useful
413
- 2. \`${t('annotate')}({symbol: "X", key: "...", value: "..."})\` — save new discoveries from this session
414
-
415
- ## Problem → Solution — When You're Stuck
416
-
417
- | You're trying to... | Do this FIRST |
418
- |---|---|
419
- | Understand the codebase | \`${t('codebase_summary')}()\` then \`${t('domains')}()\` |
420
- | Understand a specific function | \`${t('context')}({name: "functionName"})\` |
421
- | Find where something is defined | \`${t('query')}({query: "ClassName"})\` |
422
- | Find ALL references to something | \`${t('grep')}({pattern: "ClassName"})\` |
423
- | Check if editing is safe | \`${t('impact')}({target: "functionName"})\` |
424
- | Edit with confidence | \`${t('overview')}({name: "functionName"})\` — context+impact+grep in 1 call |
425
- | Know which tests to run | \`${t('test_impact')}()\` — maps changes to test files |
426
- | Find what needs testing most | \`${t('test_coverage_gaps')}()\` — sorted by risk |
427
- | Get a test strategy | \`${t('test_plan')}({name: "functionName"})\` — mocks + scenarios |
428
- | Review your changes | \`${t('review_pr')}()\` — risk scores for changed symbols |
429
- | Check for security issues | \`${t('security_scan')}()\` — 190 rules in one call |
430
- | Remove dead code safely | \`${t('find_dead_code')}()\` then use \`dead_code_remove\` prompt |
431
- | Trace how code executes | \`${t('trace')}({name: "functionName", direction: "to"})\` |
432
- | Find API endpoints | \`${t('routes')}()\` — auto-detect across 7 frameworks |
433
- | See class hierarchy | \`${t('get_type_hierarchy')}({name: "ClassName"})\` |
434
- | Compare impact before/after | \`${t('compare_impact')}({name: "X", action: "snapshot"})\` before, then \`compare\` after |
435
- | Get a full picture fast | \`${t('orchestrate')}()\` — runs detect+review+impact+gaps+dead code |
436
- | Remember something important | \`${t('annotate')}({symbol: "X", key: "...", value: "..."})\` |
437
- | Recall past knowledge | \`${t('recall')}({symbol: "X"})\` |
438
- | Start a new session properly | \`${t('session_start')}({agent: "..."})\` → \`${t('recall')}()\` → \`${t('codebase_summary')}()\` |
439
- | End a session properly | \`${t('detect_changes')}()\` → \`${t('review_pr')}()\` → annotate → \`${t('session_end')}()\` |
440
- | Transfer work to another agent | \`${t('handoff')}({from_session: "...", to_agent: "...", context: "..."})\` |
441
- | Debug a crash / exception | \`${t('trace')}({name: "crashingFunction"})\` + \`${t('context')}()\` + \`${t('impact')}()\` |
442
-
443
- ## Session Lifecycle
444
-
445
- ### Start EVERY session:
446
- 1. \`${t('session_start')}({agent: "your-agent-name"})\` — register session
447
- 2. \`${t('recall')}({})\` — what did we learn last time?
448
- 3. \`${t('codebase_summary')}()\` — refresh project context in 500 tokens
449
-
450
- ### End EVERY session:
451
- 1. \`${t('detect_changes')}()\` — verify changes
452
- 2. \`${t('review_pr')}()\` — risk assessment
453
- 3. \`${t('annotate')}({...})\` — save key discoveries from this session
454
- 4. \`${t('session_end')}({session_id: "..."})\` — record stats
455
-
456
- Milens indexes **Markdown files** (.md, .mdx) — headings become \`section\` symbols with parent-child hierarchy, and local links become cross-file references.
457
-
458
- ### Researching or exploring documentation:
459
- 1. \`${t('get_file_symbols')}({file: "README.md", repo: "<workspaceRoot>"})\` — see the full heading outline (TOC) of any doc
460
- 2. \`${t('query')}({query: "<topic>"})\` — search section headings across all docs and code
461
- 3. \`${t('grep')}({pattern: "<keyword>", include: "**/*.md"})\` — text search within docs only
462
-
463
- ### Before updating documentation:
464
- 1. \`${t('get_file_symbols')}({file: "<doc.md>"})\` — understand document structure first
465
- 2. If documenting a code symbol: \`${t('context')}({name: "<symbolName>"})\` — get full symbol info (signature, callers, deps)
466
- 3. \`${t('grep')}({pattern: "<symbolName>", include: "**/*.md"})\` — check if other docs already reference it
467
-
468
- ### After renaming/deleting a code symbol:
469
- - \`${t('grep')}({pattern: "<oldName>", include: "**/*.md"})\` — find docs that need updating (milens indexes markdown links as cross-file references)
470
-
471
- ## Never Do
472
-
473
- - NEVER edit a symbol without first running \`${t('impact')}\` on it.
474
- - NEVER delete or rename without running both \`${t('grep')}\` and \`${t('impact')}\`.
475
- - NEVER commit without running \`${t('detect_changes')}()\`.
476
- - NEVER call milens MCP tools without the \`repo\` parameter.
477
- - NEVER use \`${t('query')}\` for multi-word display text or UI labels — use \`${t('grep')}\`.
478
-
479
- ---
480
-
481
- ## Reference
482
-
483
- ### ⭐ Core Tools — Use Every Session (8)
484
-
485
- | Tool | Purpose |
486
- |---|---|
487
- | \`${t('overview')}\` | **Use this first.** Combined context + impact + grep. 1 call replaces 3-5 file reads. |
488
- | \`${t('impact')}\` | Blast radius BEFORE editing. Shows what WILL BREAK. |
489
- | \`${t('edit_check')}\` | Pre-edit safety: callers + exports + re-export chains + test coverage |
490
- | \`${t('context')}\` | 360° view: all callers + all callees. Instant dependency graph. |
491
- | \`${t('query')}\` | Find symbol definitions by name (FTS5 instant search) |
492
- | \`${t('grep')}\` | Search ALL files for any text (templates, configs, docs, styles) |
493
- | \`${t('detect_changes')}\` | Pre-commit: which symbols changed + dependents + risk scores |
494
- | \`${t('codebase_summary')}\` | Project overview in ~500 tokens. Use instead of reading README. |
495
-
496
- ### 🔧 Situational Tools — Use When Needed (15)
497
-
498
- | Tool | Purpose | Use when... |
499
- |---|---|---|
500
- | \`${t('review_pr')}\` | PR risk assessment | Before opening PR |
501
- | \`${t('review_symbol')}\` | Single symbol deep-dive | Symbol is flagged CRITICAL/HIGH |
502
- | \`${t('test_plan')}\` | Mock strategy + >=3 test scenarios | Writing new tests |
503
- | \`${t('test_coverage_gaps')}\` | Untested symbols sorted by risk | Finding test priorities |
504
- | \`${t('test_impact')}\` | Maps changes test files | After making edits |
505
- | \`${t('test_generate')}\` | Auto-generate test file | Starting tests from scratch |
506
- | \`${t('security_scan')}\` | 190 security rules | Security audit requested |
507
- | \`${t('trace')}\` | Call chains from entrypoints | Debugging execution flow |
508
- | \`${t('routes')}\` | Framework routes/endpoints | Finding API endpoints |
509
- | \`${t('smart_context')}\` | Intent-aware context | Understand/edit/debug/test modes |
510
- | \`${t('domains')}\` | Domain clusters | Understanding module structure |
511
- | \`${t('explain_relationship')}\` | Shortest dependency path | How A connects to B |
512
- | \`${t('get_type_hierarchy')}\` | Inheritance tree | Class/interface exploration |
513
- | \`${t('find_dead_code')}\` | Unused exported symbols | Before major refactors |
514
- | \`${t('find_similar')}\` | Symbols with shared callers/callees | Finding refactor patterns |
515
-
516
- ### 📚 Advanced Tools — Reference (19)
517
-
518
- | Tool | Purpose |
519
- |---|---|
520
- | \`${t('status')}\` | Index health: symbols, links, files, coverage, staleness |
521
- | \`${t('repos')}\` | List all indexed repositories |
522
- | \`${t('annotate')}\` | Record observations about symbols (persists across sessions) |
523
- | \`${t('recall')}\` | Retrieve annotations from past sessions |
524
- | \`${t('session_start')}\` | Register agent session |
525
- | \`${t('session_end')}\` | End session and record stats |
526
- | \`${t('session_context')}\` | Get session metadata + annotations |
527
- | \`${t('handoff')}\` | Transfer context between agent sessions |
528
- | \`${t('orchestrate')}\` | Full cycle: detect review → impact → gaps → dead code |
529
- | \`${t('pre_commit_check')}\` | Pre-commit risk scan |
530
- | \`${t('compare_impact')}\` | Compare impact graph before/after edit |
531
- | \`${t('semantic_search')}\` | Hybrid FTS5 + vector search |
532
- | \`${t('fix_apply')}\` | Apply security fix to a file |
533
- | \`${t('hook_preCompact')}\` | Save metrics before context compaction |
534
- | \`${t('hook_postCompact')}\` | Restore context after compaction |
535
- | \`${t('hook_onFileChange')}\` | Trigger on file change hook |
536
- | \`${t('ast_explore')}\` | Parse code to AST S-expression |
537
- | \`${t('test_query')}\` | Test tree-sitter query patterns |
538
- | \`${t('get_file_symbols')}\` | All symbols in a file with ref/dep counts |
539
-
540
- ### Keeping the Index Fresh
541
-
542
- After significant code changes: \`npx milens analyze -p . --force\` (replace \`.\` with your project root if running from a different directory)
543
-
544
- ### Skills
545
-
546
- | Task | Read this skill file |
547
- |------|---------------------|
548
- | General milens tools reference | \`${editorSkillPath(editor, 'milens')}\` |
549
- ${skillsRows}
550
-
261
+ return `<!-- milens:start -->
262
+ # Milens — AI-DOS
263
+
264
+ The Operating System for AI-Driven Development. This project is indexed by milens (${stats.symbols} symbols, ${stats.links} links, ${stats.files} files).
265
+
266
+ > **CRITICAL:** All milens MCP tool calls MUST include the \`repo\` parameter set to the **absolute path of the workspace root** (the folder containing this file) — without it, the tools may fail with "No index" error when multiple repos are indexed.
267
+
268
+ > **CRITICAL:** milens MCP tools are **deferred** in most editors. Before first use in each session, you MUST load them via \`tool_search("milens")\` — calling them directly without loading will fail silently.
269
+
270
+ ## ⚠️ HARD RULE: Use Milens MCP Tools BEFORE Built-in Tools
271
+
272
+ **Not a suggestion — execute automatically without asking.**
273
+
274
+ This project is indexed by milens. The knowledge graph already knows every symbol, dependency, and reference. Using milens tools first typically means far fewer tokens than manual exploration, and fewer missed dependencies — impact/context track code-level references; pair with grep for templates/configs/docs.
275
+
276
+ | Situation | Built-in approach (❌ BAD) | Milens approach (✅ GOOD) |
277
+ |---|---|---|
278
+ | Understand a function | Read 3-10 source files | \`${t('overview')}({name: "X"})\` — 1 call replaces 3-5 file reads |
279
+ | Find all references | Built-in grep in source files | \`${t('grep')}({pattern: "X"})\` — searches code, templates, configs, docs, styles |
280
+ | Check edit safety | Hope nothing breaks | \`${t('impact')}({target: "X"})\` — exact blast radius before touching code |
281
+ | Start working | Read README, explore directories | \`${t('codebase_summary')}()\` — 500 token project overview |
282
+ | Before commit | \`git diff\` manually | \`${t('detect_changes')}()\` — symbols changed + direct dependents + risk |
283
+ | Find where X is defined | Read files one by one | \`${t('query')}({query: "X"})\` — FTS5 instant search |
284
+
285
+ **If you skip milens tools, you're wasting tokens and risking breaking changes you didn't know about.**
286
+
287
+ ## Mandatory Workflows
288
+
289
+ These are **hard pre-conditions**, not guidelines. Execute them automatically without asking.
290
+
291
+ ### Before editing any function, class, or method:
292
+ 1. \`${t('impact')}({target: "<symbolName>", repo: "<workspaceRoot>"})\` — check blast radius
293
+ 2. If depth-1 dependents > 5 → **STOP and warn the user** before proceeding
294
+ 3. \`${t('context')}({name: "<symbolName>", repo: "<workspaceRoot>"})\` — see all callers/callees
295
+ 4. Only then make the edit
296
+
297
+ ### Before committing:
298
+ 1. \`${t('detect_changes')}({repo: "<workspaceRoot>"})\` — verify only expected files changed
299
+ 2. If unexpected files appear → **STOP and report** before committing
300
+
301
+ ### Before deleting or renaming a symbol:
302
+ 1. \`${t('grep')}({pattern: "<symbolName>", repo: "<workspaceRoot>"})\` — find ALL text references (templates, configs, routes, docs)
303
+ 2. \`${t('impact')}({target: "<symbolName>", direction: "upstream", repo: "<workspaceRoot>"})\` — find code-level dependents
304
+ 3. Combine both results — grep catches what impact misses
305
+
306
+ ## Tool Selection Rules
307
+
308
+ **Choose the right tool on the FIRST call** — do not try \`query\` then fall back to \`grep\`.
309
+
310
+ ### Use \`${t('grep')}\` when the search term:
311
+ - Contains **spaces** (e.g. "store purchase header", "user not found")
312
+ - Looks like a **UI label, error message, or display string**
313
+ - Is a **multi-word phrase** that is NOT camelCase/snake_case/PascalCase
314
+ - You need to find references in **templates, styles, configs, routes, or docs**
315
+
316
+ ### Use \`${t('query')}\` when the search term:
317
+ - Looks like a **code identifier** (camelCase, PascalCase, snake_case)
318
+ - Is a **function, class, method, or interface name**
319
+ - You want to find **symbol definitions** in indexed code files
320
+
321
+ ### When in doubt → use \`${t('grep')}\` first
322
+ \`grep\` searches everything. \`query\` only searches indexed symbol definitions.
323
+
324
+ > **⚠️ \`${t('grep')}\` default is LITERAL mode (isRegex: false).** Characters \`| . * + ?\` are escaped as plain text. To use regex patterns like \`error|fail|panic\` or \`TODO.*urgent\`, you MUST set \`isRegex: true\`. The tool will warn you if you forget.
325
+
326
+ ## Workflow Triggers
327
+
328
+ When the user says... → do this FIRST:
329
+
330
+ | User intent | First action |
331
+ |---|---|
332
+ | "edit/change/modify/fix \`X\`" | \`${t('impact')}({target: "X", repo: "<workspaceRoot>"})\` |
333
+ | "delete/remove \`X\`" | \`${t('grep')}({pattern: "X", repo: "<workspaceRoot>"})\` then \`${t('impact')}\` |
334
+ | "rename \`X\`" | \`${t('grep')}({pattern: "X", repo: "<workspaceRoot>"})\` then \`${t('impact')}\` |
335
+ | "find/search for \`X\`" | Choose \`query\` or \`grep\` per rules above |
336
+ | "commit" / "push" | \`${t('detect_changes')}({repo: "<workspaceRoot>"})\` |
337
+ | "what calls/uses \`X\`" | \`${t('context')}({name: "X", repo: "<workspaceRoot>"})\` |
338
+ | "what happens if I change \`X\`" | \`${t('impact')}({target: "X", repo: "<workspaceRoot>"})\` |
339
+ | "how are \`A\` and \`B\` connected" | \`${t('explain_relationship')}({from: "A", to: "B", repo: "<workspaceRoot>"})\` |
340
+ | "explore/understand \`X\`" | \`${t('context')}({name: "X", repo: "<workspaceRoot>"})\` |
341
+ | "update/write docs for \`X\`" | \`${t('grep')}({pattern: "X", include: "**/*.md"})\` — find existing docs mentioning X, then \`${t('context')}({name: "X"})\` for full symbol info |
342
+ | "research/explore docs" | \`${t('get_file_symbols')}({file: "<doc.md>"})\` — see document outline (headings as sections) |
343
+ | "what docs mention \`X\`" | \`${t('grep')}({pattern: "X", include: "**/*.md"})\` — find all markdown references |
344
+ | "review this PR" | \`${t('review_pr')}({repo: "<workspaceRoot>"})\` — risk assessment for changed files |
345
+ | "is \`X\` risky to change" | \`${t('review_symbol')}({name: "X", repo: "<workspaceRoot>"})\` |
346
+ | "write tests for \`X\`" | \`${t('test_plan')}({name: "X", repo: "<workspaceRoot>"})\` — deps, mocks, suggested tests |
347
+ | "what needs tests" | \`${t('test_coverage_gaps')}({repo: "<workspaceRoot>"})\` — untested symbols by risk |
348
+ | "which tests to run" | \`${t('test_impact')}({repo: "<workspaceRoot>"})\` — maps changes → test files |
349
+ | "remember/note that \`X\`..." | \`${t('annotate')}({symbol: "X", key: "note", value: "...", repo: "<workspaceRoot>"})\` |
350
+ | "what do we know about \`X\`" | \`${t('recall')}({symbol: "X", repo: "<workspaceRoot>"})\` |
351
+ | "start new session" | \`${t('session_start')}({agent: "...", repo: "<workspaceRoot>"})\` |
352
+ | "find code like \`X\`" | \`${t('find_similar')}({name: "X", repo: "<workspaceRoot>"})\` |
353
+ | "search for \`concept\`" | \`${t('semantic_search')}({query: "concept", repo: "<workspaceRoot>"})\` |
354
+ | "generate tests for \`X\`" | \`${t('test_generate')}({symbol: "X", repo: "<workspaceRoot>"})\` |
355
+ | "fix security issue in \`X\`" | \`${t('fix_apply')}({ruleId, file, line, repo: "<workspaceRoot>"})\` |
356
+ | "remove dead code" | \`${t('find_dead_code')}()\` then \`dead_code_remove\` prompt |
357
+ | "orchestrate/check changes" | \`${t('orchestrate')}({repo: "<workspaceRoot>"})\` |
358
+ | "compare impact of \`X\`" | \`${t('compare_impact')}({name: "X", action: "snapshot"|"compare", repo: "<workspaceRoot>"})\` |
359
+ | "check pre-commit" | \`${t('pre_commit_check')}({repo: "<workspaceRoot>"})\` |
360
+ | "save/restore context" | \`${t('hook_preCompact')}()\` / \`${t('hook_postCompact')}()\` |
361
+ | "scan security / audit security" | \`${t('security_scan')}({repo: "<workspaceRoot>"})\` — full audit across all 190 rules |
362
+ | "end session" / "finish work" | \`${t('session_end')}({session_id: "..."})\` — record stats, trigger onSessionEnd hook |
363
+ | "what did session X do" | \`${t('session_context')}({session_id: "..."})\` — get annotations + tool calls |
364
+ | "file changed to X" | \`${t('hook_onFileChange')}({files: ["path/to/file"], repo: "<workspaceRoot>"})\` |
365
+
366
+ ### Domain-aware skill triggers:
367
+ | User intent | Skill to load |
368
+ |---|---|
369
+ | "I'm working on authentication/security" | Load \`milens-security\` skill + \`${t('security_scan')}()\` |
370
+ | "I need to understand the parser" | Load \`milens-parser\` skill + \`${t('get_file_symbols')}({file: "src/parser/"})\` |
371
+ | "I'm debugging a server issue" | Load \`milens-server\` skill + \`${t('trace')}()\` |
372
+ | "I'm working with the database" | Load \`milens-store\` skill + \`${t('get_file_symbols')}({file: "src/store/"})\` |
373
+ | "I need to write tests for this" | Load \`milens-tdd\` skill + \`${t('test_plan')}()\` |
374
+ | "I'm planning a feature" | Load \`milens-plan\` skill + \`${t('codebase_summary')}()\` |
375
+ | "I need to refactor this" | Load \`milens-refactor-clean\` skill + \`${t('impact')}()\` |
376
+ | "Review my code changes" | Load \`milens-code-review\` skill + \`${t('review_pr')}()\` |
377
+
378
+ ## Annotation Guide — Building a Smarter Codebase
379
+
380
+ Every time you discover something important about a symbol, annotate it. The system learns across sessions — your note today saves tokens tomorrow.
381
+
382
+ ### When to annotate:
383
+ - Found a bug pattern? → \`${t('annotate')}({symbol: "X", key: "bug", value: "..."})\`
384
+ - Discovered an architecture rule? → \`${t('annotate')}({symbol: "X", key: "architecture", value: "..."})\`
385
+ - Learned how to test something? → \`${t('annotate')}({symbol: "X", key: "test", value: "..."})\`
386
+ - Found a security issue? → \`${t('annotate')}({symbol: "X", key: "security", value: "..."})\`
387
+ - Noted a hidden dependency? → \`${t('annotate')}({symbol: "X", key: "dependency", value: "..."})\`
388
+
389
+ ### Annotation keys reference:
390
+ | Key | Use when | Example value |
391
+ |-----|----------|---------------|
392
+ | \`bug\` | Known bug, not yet fixed | "NullPointerException when users is empty array" |
393
+ | \`security\` | Security vulnerability | "No CSRF token validation on this endpoint" |
394
+ | \`architecture\` | Design pattern, constraint | "Service is a singleton — don't instantiate directly" |
395
+ | \`test\` | Testing knowledge | "Must mock Database.getConnection() before testing" |
396
+ | \`dependency\` | Hidden coupling | "Imports from deprecated module old-auth.js" |
397
+ | \`refactor\` | Future refactoring notes | "Split into validateEmail() + normalizeEmail()" |
398
+ | \`workflow\` | Process knowledge | "Must restart dev server after modifying this file" |
399
+ | \`note\` | General observation | "This function is called from cron job at 3AM" |
400
+
401
+ ### Learning lifecycle:
402
+ 1. **Session 1:** \`annotate()\` → confidence 0.5
403
+ 2. **Session 2:** \`recall()\` sees it again → confidence 0.7
404
+ 3. **Session 5:** confidence hits 0.8 → \`milens evolve\` promotes it to SKILL.md
405
+
406
+ ### Annotate triggers:
407
+ | User says... | Tool call |
408
+ |---|---|
409
+ | "found a bug in X" | \`${t('annotate')}({symbol: "X", key: "bug", value: "describe the bug"})\` |
410
+ | "X has a security issue" | \`${t('annotate')}({symbol: "X", key: "security", value: "describe the issue"})\` |
411
+ | "learned how X works" | \`${t('annotate')}({symbol: "X", key: "note", value: "key insight"})\` |
412
+ | "X depends on Y internally" | \`${t('annotate')}({symbol: "X", key: "dependency", value: "depends on Y for Z"})\` |
413
+ | "X needs refactoring later" | \`${t('annotate')}({symbol: "X", key: "refactor", value: "plan"})\` |
414
+
415
+ ### At session end, ALWAYS:
416
+ 1. \`${t('recall')}({})\` — review annotations you found useful
417
+ 2. \`${t('annotate')}({symbol: "X", key: "...", value: "..."})\` — save new discoveries from this session
418
+
419
+ ## Problem → Solution — When You're Stuck
420
+
421
+ | You're trying to... | Do this FIRST |
422
+ |---|---|
423
+ | Understand the codebase | \`${t('codebase_summary')}()\` then \`${t('domains')}()\` |
424
+ | Understand a specific function | \`${t('context')}({name: "functionName"})\` |
425
+ | Find where something is defined | \`${t('query')}({query: "ClassName"})\` |
426
+ | Find ALL references to something | \`${t('grep')}({pattern: "ClassName"})\` |
427
+ | Check if editing is safe | \`${t('impact')}({target: "functionName"})\` |
428
+ | Edit with confidence | \`${t('overview')}({name: "functionName"})\` — context+impact+grep in 1 call |
429
+ | Know which tests to run | \`${t('test_impact')}()\` — maps changes to test files |
430
+ | Find what needs testing most | \`${t('test_coverage_gaps')}()\` — sorted by risk |
431
+ | Get a test strategy | \`${t('test_plan')}({name: "functionName"})\` — mocks + scenarios |
432
+ | Review your changes | \`${t('review_pr')}()\` — risk scores for changed symbols |
433
+ | Check for security issues | \`${t('security_scan')}()\` — 190 rules in one call |
434
+ | Remove dead code safely | \`${t('find_dead_code')}()\` then use \`dead_code_remove\` prompt |
435
+ | Trace how code executes | \`${t('trace')}({name: "functionName", direction: "to"})\` |
436
+ | Find API endpoints | \`${t('routes')}()\` — auto-detect across 7 frameworks |
437
+ | See class hierarchy | \`${t('get_type_hierarchy')}({name: "ClassName"})\` |
438
+ | Compare impact before/after | \`${t('compare_impact')}({name: "X", action: "snapshot"})\` before, then \`compare\` after |
439
+ | Get a full picture fast | \`${t('orchestrate')}()\` — runs detect+review+impact+gaps+dead code |
440
+ | Remember something important | \`${t('annotate')}({symbol: "X", key: "...", value: "..."})\` |
441
+ | Recall past knowledge | \`${t('recall')}({symbol: "X"})\` |
442
+ | Start a new session properly | \`${t('session_start')}({agent: "..."})\` → \`${t('recall')}()\` → \`${t('codebase_summary')}()\` |
443
+ | End a session properly | \`${t('detect_changes')}()\` → \`${t('review_pr')}()\` → annotate → \`${t('session_end')}()\` |
444
+ | Transfer work to another agent | \`${t('handoff')}({from_session: "...", to_agent: "...", context: "..."})\` |
445
+ | Debug a crash / exception | \`${t('trace')}({name: "crashingFunction"})\` + \`${t('context')}()\` + \`${t('impact')}()\` |
446
+
447
+ ## Session Lifecycle
448
+
449
+ ### Start EVERY session:
450
+ 1. \`${t('session_start')}({agent: "your-agent-name"})\` — register session
451
+ 2. \`${t('recall')}({})\` — what did we learn last time?
452
+ 3. \`${t('codebase_summary')}()\` — refresh project context in 500 tokens
453
+
454
+ ### End EVERY session:
455
+ 1. \`${t('detect_changes')}()\` — verify changes
456
+ 2. \`${t('review_pr')}()\` — risk assessment
457
+ 3. \`${t('annotate')}({...})\` — save key discoveries from this session
458
+ 4. \`${t('session_end')}({session_id: "..."})\` — record stats
459
+
460
+ Milens indexes **Markdown files** (.md, .mdx) — headings become \`section\` symbols with parent-child hierarchy, and local links become cross-file references.
461
+
462
+ ### Researching or exploring documentation:
463
+ 1. \`${t('get_file_symbols')}({file: "README.md", repo: "<workspaceRoot>"})\` — see the full heading outline (TOC) of any doc
464
+ 2. \`${t('query')}({query: "<topic>"})\` — search section headings across all docs and code
465
+ 3. \`${t('grep')}({pattern: "<keyword>", include: "**/*.md"})\` — text search within docs only
466
+
467
+ ### Before updating documentation:
468
+ 1. \`${t('get_file_symbols')}({file: "<doc.md>"})\` — understand document structure first
469
+ 2. If documenting a code symbol: \`${t('context')}({name: "<symbolName>"})\` — get full symbol info (signature, callers, deps)
470
+ 3. \`${t('grep')}({pattern: "<symbolName>", include: "**/*.md"})\` — check if other docs already reference it
471
+
472
+ ### After renaming/deleting a code symbol:
473
+ - \`${t('grep')}({pattern: "<oldName>", include: "**/*.md"})\` — find docs that need updating (milens indexes markdown links as cross-file references)
474
+
475
+ ## Never Do
476
+
477
+ - NEVER edit a symbol without first running \`${t('impact')}\` on it.
478
+ - NEVER delete or rename without running both \`${t('grep')}\` and \`${t('impact')}\`.
479
+ - NEVER commit without running \`${t('detect_changes')}()\`.
480
+ - NEVER call milens MCP tools without the \`repo\` parameter.
481
+ - NEVER use \`${t('query')}\` for multi-word display text or UI labels — use \`${t('grep')}\`.
482
+
483
+ ---
484
+
485
+ ## Reference
486
+
487
+ ### ⭐ Core Tools — Use Every Session (9)
488
+
489
+ | Tool | Purpose |
490
+ |---|---|
491
+ | \`${t('overview')}\` | **Use this first.** Combined context + impact + grep. 1 call replaces 3-5 file reads. |
492
+ | \`${t('impact')}\` | Blast radius BEFORE editing. Shows what WILL BREAK. |
493
+ | \`${t('edit_check')}\` | Pre-edit safety: callers + exports + re-export chains + test coverage |
494
+ | \`${t('guard_edit_check')}\` | HARD pre-edit gate: blocks if dependents > 5, tracks checks for session audit |
495
+ | \`${t('context')}\` | 360° view: all callers + all callees. Instant dependency graph. |
496
+ | \`${t('query')}\` | Find symbol definitions by name (FTS5 instant search) |
497
+ | \`${t('grep')}\` | Search ALL files for any text (templates, configs, docs, styles) |
498
+ | \`${t('detect_changes')}\` | Pre-commit: which symbols changed + dependents + risk scores |
499
+ | \`${t('codebase_summary')}\` | Project overview in ~500 tokens. Use instead of reading README. |
500
+
501
+ ### 🔧 Situational Tools — Use When Needed (15)
502
+
503
+ | Tool | Purpose | Use when... |
504
+ |---|---|---|
505
+ | \`${t('review_pr')}\` | PR risk assessment | Before opening PR |
506
+ | \`${t('review_symbol')}\` | Single symbol deep-dive | Symbol is flagged CRITICAL/HIGH |
507
+ | \`${t('test_plan')}\` | Mock strategy + >=3 test scenarios | Writing new tests |
508
+ | \`${t('test_coverage_gaps')}\` | Untested symbols sorted by risk | Finding test priorities |
509
+ | \`${t('test_impact')}\` | Maps changes → test files | After making edits |
510
+ | \`${t('test_generate')}\` | Auto-generate test file | Starting tests from scratch |
511
+ | \`${t('security_scan')}\` | 190 security rules | Security audit requested |
512
+ | \`${t('trace')}\` | Call chains from entrypoints | Debugging execution flow |
513
+ | \`${t('routes')}\` | Framework routes/endpoints | Finding API endpoints |
514
+ | \`${t('smart_context')}\` | Intent-aware context | Understand/edit/debug/test modes |
515
+ | \`${t('domains')}\` | Domain clusters | Understanding module structure |
516
+ | \`${t('explain_relationship')}\` | Shortest dependency path | How A connects to B |
517
+ | \`${t('get_type_hierarchy')}\` | Inheritance tree | Class/interface exploration |
518
+ | \`${t('find_dead_code')}\` | Unused exported symbols | Before major refactors |
519
+ | \`${t('find_similar')}\` | Symbols with shared callers/callees | Finding refactor patterns |
520
+
521
+ ### 📚 Advanced Tools — Reference (20)
522
+
523
+ | Tool | Purpose |
524
+ |---|---|
525
+ | \`${t('generate_findings_report')}\` | Render investigated findings into a Markdown+XML report for a worker/coder agent |
526
+ | \`${t('status')}\` | Index health: symbols, links, files, coverage, staleness |
527
+ | \`${t('repos')}\` | List all indexed repositories |
528
+ | \`${t('annotate')}\` | Record observations about symbols (persists across sessions) |
529
+ | \`${t('recall')}\` | Retrieve annotations from past sessions |
530
+ | \`${t('session_start')}\` | Register agent session |
531
+ | \`${t('session_end')}\` | End session and record stats |
532
+ | \`${t('session_context')}\` | Get session metadata + annotations |
533
+ | \`${t('handoff')}\` | Transfer context between agent sessions |
534
+ | \`${t('orchestrate')}\` | Full cycle: detect → review → impact gaps dead code |
535
+ | \`${t('pre_commit_check')}\` | Pre-commit risk scan |
536
+ | \`${t('compare_impact')}\` | Compare impact graph before/after edit |
537
+ | \`${t('semantic_search')}\` | Hybrid FTS5 + vector search |
538
+ | \`${t('fix_apply')}\` | Apply security fix to a file |
539
+ | \`${t('hook_preCompact')}\` | Save metrics before context compaction |
540
+ | \`${t('hook_postCompact')}\` | Restore context after compaction |
541
+ | \`${t('hook_onFileChange')}\` | Trigger on file change hook |
542
+ | \`${t('ast_explore')}\` | Parse code to AST S-expression |
543
+ | \`${t('test_query')}\` | Test tree-sitter query patterns |
544
+ | \`${t('get_file_symbols')}\` | All symbols in a file with ref/dep counts |
545
+
546
+ ### Keeping the Index Fresh
547
+
548
+ After significant code changes: \`npx milens analyze -p . --force\` (replace \`.\` with your project root if running from a different directory)
549
+
550
+ ### Skills
551
+
552
+ | Task | Read this skill file |
553
+ |------|---------------------|
554
+ | General milens tools reference | \`${editorSkillPath(editor, 'milens')}\` |
555
+ ${skillsRows}
556
+
551
557
  <!-- milens:end -->`;
552
558
  }
553
559
  function generateToolInstructions(rootDir, copilotDir, cursorDir, claudeDir, _claudeRulesDir, agentsDir, stats, areaNames, has) {
554
560
  if (has('copilot')) {
555
561
  const content = renderMilensInstructions(rootDir, stats, areaNames, 'copilot');
556
562
  // Copilot: .github/instructions/milens.instructions.md (applyTo: ** → always loaded)
557
- writeFileSync(join(copilotDir, 'milens.instructions.md'), `---\napplyTo: "**"\n---\n\n${content}`);
563
+ writeFileSync(join(copilotDir, 'milens.instructions.md'), `---\ngenerated-by: milens\napplyTo: "**"\n---\n\n${content}`);
558
564
  // Inject into root config that Copilot always reads
559
565
  const githubDir = join(rootDir, '.github');
560
566
  mkdirSync(githubDir, { recursive: true });
@@ -563,7 +569,7 @@ function generateToolInstructions(rootDir, copilotDir, cursorDir, claudeDir, _cl
563
569
  if (has('cursor')) {
564
570
  const content = renderMilensInstructions(rootDir, stats, areaNames, 'cursor');
565
571
  // Cursor: .cursor/rules/milens.mdc (alwaysApply: true → always loaded)
566
- writeFileSync(join(cursorDir, 'milens.mdc'), `---\ndescription: Milens code intelligence MCP tools\nglobs: "**"\nalwaysApply: true\n---\n\n${content}`);
572
+ writeFileSync(join(cursorDir, 'milens.mdc'), `---\ngenerated-by: milens\ndescription: Milens code intelligence MCP tools\nglobs: "**"\nalwaysApply: true\n---\n\n${content}`);
567
573
  // Cursor project-wide rules: .cursor/index.mdc (alwaysApply: always loaded)
568
574
  const cursorIndex = join(rootDir, '.cursor', 'index.mdc');
569
575
  mkdirSync(dirname(cursorIndex), { recursive: true });
@@ -583,7 +589,7 @@ function generateToolInstructions(rootDir, copilotDir, cursorDir, claudeDir, _cl
583
589
  // Universal agents: .agents/skills/milens/SKILL.md
584
590
  const agentsMilensDir = join(agentsDir, 'milens');
585
591
  mkdirSync(agentsMilensDir, { recursive: true });
586
- writeFileSync(join(agentsMilensDir, 'SKILL.md'), `---\nname: milens\ndescription: Code intelligence MCP tools — symbol search, text grep, impact analysis, dependency graph\n---\n\n${content}`);
592
+ writeFileSync(join(agentsMilensDir, 'SKILL.md'), `---\ngenerated-by: milens\nname: milens\ndescription: Code intelligence MCP tools — symbol search, text grep, impact analysis, dependency graph\n---\n\n${content}`);
587
593
  // Inject into root config for universal agents
588
594
  injectWithMarkers(join(rootDir, 'AGENTS.md'), content);
589
595
  }