@uoyo/mvtt 2.0.0-beta.1 → 2.0.0-beta.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 (84) hide show
  1. package/README.md +184 -193
  2. package/dist/build/section-loader.d.ts.map +1 -1
  3. package/dist/build/section-loader.js +18 -8
  4. package/dist/build/section-loader.js.map +1 -1
  5. package/dist/fs/materialize.d.ts.map +1 -1
  6. package/dist/fs/materialize.js +5 -0
  7. package/dist/fs/materialize.js.map +1 -1
  8. package/dist/scripts/session-update.cjs +7568 -0
  9. package/install-manifest.yaml +2 -0
  10. package/package.json +3 -2
  11. package/registry.yaml +6 -0
  12. package/sources/defaults/config.yaml +7 -7
  13. package/sources/defaults/session.yaml +9 -16
  14. package/sources/scripts/session-update.js +351 -0
  15. package/sources/sections/activation-load-context.md +4 -0
  16. package/sources/sections/footer-next-steps.md +1 -1
  17. package/sources/sections/output-language-constraint.md +11 -11
  18. package/sources/sections/session-update.md +115 -47
  19. package/sources/skills/mvt-analyze/business.md +7 -7
  20. package/sources/skills/mvt-analyze/manifest.yaml +1 -0
  21. package/sources/skills/mvt-analyze-code/manifest.yaml +110 -96
  22. package/sources/skills/mvt-bug-detect/business.md +99 -0
  23. package/sources/skills/mvt-bug-detect/manifest.yaml +84 -0
  24. package/sources/skills/mvt-check-context/business.md +3 -5
  25. package/sources/skills/mvt-check-context/manifest.yaml +70 -63
  26. package/sources/skills/mvt-cleanup/business.md +49 -23
  27. package/sources/skills/mvt-cleanup/manifest.yaml +15 -10
  28. package/sources/skills/mvt-config/business.md +1 -2
  29. package/sources/skills/mvt-config/manifest.yaml +103 -96
  30. package/sources/skills/mvt-create-skill/business.md +84 -76
  31. package/sources/skills/mvt-create-skill/manifest.yaml +107 -95
  32. package/sources/skills/mvt-design/business.md +3 -6
  33. package/sources/skills/mvt-design/manifest.yaml +109 -96
  34. package/sources/skills/mvt-fix/business.md +39 -9
  35. package/sources/skills/mvt-fix/manifest.yaml +88 -72
  36. package/sources/skills/mvt-help/business.md +2 -4
  37. package/sources/skills/mvt-help/manifest.yaml +75 -67
  38. package/sources/skills/mvt-implement/business.md +4 -5
  39. package/sources/skills/mvt-implement/manifest.yaml +93 -80
  40. package/sources/skills/mvt-init/business.md +2 -2
  41. package/sources/skills/mvt-init/manifest.yaml +102 -101
  42. package/sources/skills/mvt-manage-context/business.md +186 -175
  43. package/sources/skills/mvt-manage-context/manifest.yaml +134 -123
  44. package/sources/skills/mvt-plan-dev/business.md +101 -20
  45. package/sources/skills/mvt-plan-dev/manifest.yaml +90 -91
  46. package/sources/skills/mvt-quick-dev/business.md +2 -1
  47. package/sources/skills/mvt-quick-dev/manifest.yaml +84 -69
  48. package/sources/skills/mvt-refactor/business.md +2 -1
  49. package/sources/skills/mvt-refactor/manifest.yaml +104 -86
  50. package/sources/skills/mvt-resume/business.md +28 -68
  51. package/sources/skills/mvt-resume/manifest.yaml +81 -71
  52. package/sources/skills/mvt-review/business.md +3 -3
  53. package/sources/skills/mvt-review/manifest.yaml +108 -87
  54. package/sources/skills/mvt-status/business.md +14 -18
  55. package/sources/skills/mvt-status/manifest.yaml +74 -66
  56. package/sources/skills/mvt-sync-context/business.md +155 -150
  57. package/sources/skills/mvt-sync-context/manifest.yaml +99 -96
  58. package/sources/skills/mvt-template/business.md +0 -2
  59. package/sources/skills/mvt-template/manifest.yaml +68 -63
  60. package/sources/skills/mvt-test/business.md +3 -3
  61. package/sources/skills/mvt-test/manifest.yaml +115 -102
  62. package/sources/skills/mvt-update-plan/business.md +83 -72
  63. package/sources/skills/mvt-update-plan/manifest.yaml +124 -132
  64. package/sources/templates/analyze-output/body.md +15 -15
  65. package/sources/templates/design-output/body.md +17 -17
  66. package/sources/templates/implement-output/body.md +11 -11
  67. package/sources/templates/review-output/body.md +11 -11
  68. package/sources/templates/test-output/body.md +7 -7
  69. package/dist/build/plan-validator.d.ts +0 -26
  70. package/dist/build/plan-validator.d.ts.map +0 -1
  71. package/dist/build/plan-validator.js +0 -225
  72. package/dist/build/plan-validator.js.map +0 -1
  73. package/dist/commands/build.d.ts +0 -5
  74. package/dist/commands/build.d.ts.map +0 -1
  75. package/dist/commands/build.js +0 -46
  76. package/dist/commands/build.js.map +0 -1
  77. package/dist/commands/migrate.d.ts +0 -18
  78. package/dist/commands/migrate.d.ts.map +0 -1
  79. package/dist/commands/migrate.js +0 -163
  80. package/dist/commands/migrate.js.map +0 -1
  81. package/dist/fs/protection.d.ts +0 -15
  82. package/dist/fs/protection.d.ts.map +0 -1
  83. package/dist/fs/protection.js +0 -16
  84. package/dist/fs/protection.js.map +0 -1
@@ -11,6 +11,8 @@ generated:
11
11
  source: "copy:sources/knowledge/core/_framework/"
12
12
  - pattern: ".ai-agents/registry.yaml"
13
13
  source: "copy:registry.yaml"
14
+ - pattern: ".ai-agents/scripts/session-update.cjs"
15
+ source: "bundle:sources/scripts/session-update.js"
14
16
 
15
17
  create_once:
16
18
  - path: ".ai-agents/config.yaml"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uoyo/mvtt",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.3",
4
4
  "description": "My Virtual Tech Team - AI-guided prompt orchestration framework",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "access": "public"
36
36
  },
37
37
  "scripts": {
38
- "build": "tsc -p tsconfig.build.json",
38
+ "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && node build-scripts.js",
39
39
  "test": "vitest run",
40
40
  "test:watch": "vitest",
41
41
  "test:coverage": "vitest run --coverage",
@@ -45,6 +45,7 @@
45
45
  "@types/node": "^25.6.0",
46
46
  "@types/prompts": "^2.4.9",
47
47
  "@vitest/coverage-v8": "^2.1.9",
48
+ "esbuild": "^0.28.0",
48
49
  "typescript": "^5.4.0",
49
50
  "vitest": "^2.0.0"
50
51
  },
package/registry.yaml CHANGED
@@ -100,6 +100,12 @@ skills:
100
100
  category: project
101
101
 
102
102
  # --- Developer Skills ---
103
+ mvt-bug-detect:
104
+ agent: analyst
105
+ description: "Analyze and detect bugs by investigating root cause, assessing severity and impact scope. Produces a structured diagnosis in conversation without applying fixes. This skill should be used when user suspects a bug, wants to understand a problem before fixing, or needs impact analysis."
106
+ path: .claude/skills/mvt-bug-detect/SKILL.md
107
+ template: null
108
+ category: shortcut
103
109
  mvt-implement:
104
110
  agent: developer
105
111
  description: "Implement features based on architecture design. This skill should be used when user wants to implement a feature, write production code, or translate design blueprints into working code."
@@ -1,18 +1,13 @@
1
1
  # MVTT Framework - User Configuration
2
- # Unified config center: all skills read and enforce these settings via Activation Protocol
3
- # Modify via: /mvt-config or edit directly
4
2
 
5
3
  version: "2.0"
6
4
 
7
- # ============================================================
8
- # User Preferences (enforced by Activation Protocol Step 2)
9
- # ============================================================
10
5
  preferences:
11
- # Language used for interactive responses (chat replies, prompts, tables shown to the user)
6
+ # Language used for interactive responses
12
7
  # Options: en-US, zh-CN
13
8
  interaction_language: en-US
14
9
 
15
- # Language used for persistent document output (artifacts, project-context.md, generated reports)
10
+ # Language used for persistent document output
16
11
  # If absent, falls back to interaction_language.
17
12
  # Options: en-US, zh-CN
18
13
  document_output_language: en-US
@@ -25,3 +20,8 @@ preferences:
25
20
  # AI routing for /mvt-manage-context add
26
21
  context_routing:
27
22
  relevance_threshold: 70 # Skills scored >= this are pre-checked; below are folded
23
+
24
+ # Session history limits
25
+ history_limits:
26
+ history: 20 # Max history entries (1-100)
27
+ changes: 20 # Max changes entries (1-100)
@@ -1,31 +1,24 @@
1
1
  # Workspace Session State
2
- # Supports flexible workflows -- no longer bound to a fixed pipeline
3
2
 
4
3
  session:
5
4
  initialized_at: ""
6
- last_command: ""
5
+ last_synced_at: ""
7
6
 
8
- # Current active change (id/title/created_at set by /mvt-analyze;
9
- # plan_path/has_plan set by /mvt-plan-dev once a plan is generated)
10
7
  active_change:
11
8
  id: ""
12
9
  title: ""
13
10
  created_at: ""
14
11
  plan_path: ""
15
- has_plan: false
16
12
 
17
- # Recent changes with active plans (max 5, owned by /mvt-plan-dev and /mvt-update-plan)
18
- # Each entry: { id, title, plan_path, last_updated }
19
- # Status is the responsibility of plan.yaml (read on demand by /mvt-resume).
20
- recent_changes: []
13
+ changes: []
14
+ # - id: "chg-001"
15
+ # title: "User authentication"
16
+ # plan_path: ".ai-agents/workspace/artifacts/chg-001/plan.yaml"
17
+ # status: "active" # active | done | abandoned
18
+ # updated_at: "2026-05-23T14:30:00"
21
19
 
22
- # Skill execution history (append-only, max 10)
23
- # Records which skills have been executed, replacing the old progress field
24
- skill_history: []
25
- # - command: "/mvt-analyze"
20
+ history: []
21
+ # - skill: "/mvt-analyze"
26
22
  # completed_at: "2026-05-23T14:30:00"
27
23
  # summary: "Analyzed user authentication requirements"
28
24
  # change_id: "" # set when work belongs to an active change
29
-
30
- # Recent actions (append-only, max 5)
31
- recent_actions: []
@@ -0,0 +1,351 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * session-update.js — Mechanical session state mutation script
5
+ *
6
+ * Replaces AI-driven YAML mutation with a deterministic Node.js script.
7
+ * All skills call this script instead of manually editing session.yaml.
8
+ *
9
+ * NOTE: This source file uses `import from "yaml"`. During the build
10
+ * pipeline, esbuild bundles it into a zero-dependency single file that
11
+ * gets deployed to .ai-agents/scripts/session-update.cjs.
12
+ *
13
+ * Usage:
14
+ * node .ai-agents/scripts/session-update.cjs \
15
+ * --skill <name> \
16
+ * --summary <text> \
17
+ * [--change-id <id>] \
18
+ * [--new-change <title>] \
19
+ * [--set-initialized] \
20
+ * [--update-change] \
21
+ * [--set-plan-path <path>] \
22
+ * [--close-change] \
23
+ * [--set-change-status <status>] \
24
+ * [--no-change] \
25
+ * [--set-synced] \
26
+ * [--truncate-history <n>]
27
+ *
28
+ * Output:
29
+ * Success (exit 0): {"ok":true}
30
+ * Failure (exit 1): plain text error message on stderr
31
+ */
32
+
33
+ import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync } from "node:fs";
34
+ import path from "node:path";
35
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
36
+
37
+ // ── Error Messages ──────────────────────────────────────────────────────────
38
+ // All error messages centralized here for visibility and easy maintenance.
39
+ // Each key maps to a function that returns the stderr message string.
40
+
41
+ const ERRORS = {
42
+ MISSING_SKILL: () => "Missing required argument: --skill",
43
+ MISSING_SUMMARY: () => "Missing required argument: --summary",
44
+ CHANGE_ID_REQUIRED: () => "--new-change requires --change-id",
45
+ NO_PROJECT_ROOT: () => "Could not find project root (.ai-agents/ directory not found). Make sure you are inside an MVTT project.",
46
+ NO_SESSION_YAML: () => "session.yaml not found. Run /mvt-init first to initialize the project.",
47
+ SESSION_PARSE_FAILED: (detail) => `Failed to parse session.yaml: ${detail}. Check the file for syntax errors.`,
48
+ SESSION_WRITE_FAILED: (detail) => `Failed to write session.yaml: ${detail}`,
49
+ CONFIG_LIMIT_INVALID: (key, val, min, max, fallback) =>
50
+ `Warning: config history_limits.${key} value "${val}" is invalid (must be integer ${min}-${max}). Using default ${fallback}.`,
51
+ };
52
+
53
+ // ── Defaults ────────────────────────────────────────────────────────────────
54
+ const DEFAULT_LIMITS = {
55
+ history: 20,
56
+ changes: 20,
57
+ };
58
+
59
+ const LIMIT_RANGES = {
60
+ history: { min: 1, max: 100 },
61
+ changes: { min: 1, max: 100 },
62
+ };
63
+
64
+ // ── Project Root Resolution ─────────────────────────────────────────────────
65
+ function findProjectRoot(cwd) {
66
+ let dir = cwd;
67
+ while (true) {
68
+ if (existsSync(path.join(dir, ".ai-agents"))) return dir;
69
+ const parent = path.dirname(dir);
70
+ if (parent === dir) return null;
71
+ dir = parent;
72
+ }
73
+ }
74
+
75
+ // ── CLI Parsing ─────────────────────────────────────────────────────────────
76
+ function parseArgs(argv) {
77
+ const args = {};
78
+ for (let i = 2; i < argv.length; i++) {
79
+ if (argv[i].startsWith("--")) {
80
+ const key = argv[i].slice(2);
81
+ const next = argv[i + 1];
82
+ if (next && !next.startsWith("--")) {
83
+ args[key] = next;
84
+ i++;
85
+ } else {
86
+ args[key] = true;
87
+ }
88
+ }
89
+ }
90
+ return args;
91
+ }
92
+
93
+ // ── Config Loading ──────────────────────────────────────────────────────────
94
+ function loadHistoryLimits(configPath) {
95
+ const limits = { ...DEFAULT_LIMITS };
96
+ if (!existsSync(configPath)) return limits;
97
+
98
+ try {
99
+ const raw = readFileSync(configPath, "utf-8");
100
+ const config = parseYaml(raw);
101
+ const configured = config?.preferences?.history_limits;
102
+ if (!configured || typeof configured !== "object") return limits;
103
+
104
+ for (const key of Object.keys(DEFAULT_LIMITS)) {
105
+ const val = configured[key];
106
+ if (val == null) continue;
107
+
108
+ const num = Number(val);
109
+ const range = LIMIT_RANGES[key];
110
+ if (!Number.isInteger(num) || num < range.min || num > range.max) {
111
+ console.warn(ERRORS.CONFIG_LIMIT_INVALID(key, val, range.min, range.max, DEFAULT_LIMITS[key]));
112
+ continue;
113
+ }
114
+ limits[key] = num;
115
+ }
116
+ } catch {
117
+ // If config can't be parsed, use defaults silently
118
+ }
119
+ return limits;
120
+ }
121
+
122
+ // ── Validation ──────────────────────────────────────────────────────────────
123
+ function validate(args) {
124
+ if (!args.skill) return ERRORS.MISSING_SKILL();
125
+ if (!args.summary) return ERRORS.MISSING_SUMMARY();
126
+ if (args["new-change"] && !args["change-id"]) return ERRORS.CHANGE_ID_REQUIRED();
127
+ return null;
128
+ }
129
+
130
+ // ── Main ────────────────────────────────────────────────────────────────────
131
+ function main() {
132
+ const args = parseArgs(process.argv);
133
+
134
+ const validationError = validate(args);
135
+ if (validationError) {
136
+ process.stderr.write(validationError + "\n");
137
+ process.exit(1);
138
+ }
139
+
140
+ const projectRoot = findProjectRoot(process.cwd());
141
+ if (!projectRoot) {
142
+ process.stderr.write(ERRORS.NO_PROJECT_ROOT() + "\n");
143
+ process.exit(1);
144
+ }
145
+
146
+ const sessionPath = path.join(projectRoot, ".ai-agents/workspace/session.yaml");
147
+ if (!existsSync(sessionPath)) {
148
+ process.stderr.write(ERRORS.NO_SESSION_YAML() + "\n");
149
+ process.exit(1);
150
+ }
151
+
152
+ const configPath = path.join(projectRoot, ".ai-agents/config.yaml");
153
+ const limits = loadHistoryLimits(configPath);
154
+
155
+ // Read session
156
+ let session;
157
+ try {
158
+ session = parseYaml(readFileSync(sessionPath, "utf-8"));
159
+ } catch (e) {
160
+ process.stderr.write(ERRORS.SESSION_PARSE_FAILED(e.message) + "\n");
161
+ process.exit(1);
162
+ }
163
+
164
+ const now = new Date().toISOString();
165
+
166
+ // ── Mandatory updates ──────────────────────────────────────────────────
167
+
168
+ // history append + truncate
169
+ session.history = session.history || [];
170
+ // Use --no-change to force empty change_id, otherwise fall back to active_change.id
171
+ const activeChangeId = args["no-change"] ? "" : (args["change-id"] || session.active_change?.id || "");
172
+ session.history.push({
173
+ skill: `/${args.skill}`,
174
+ completed_at: now,
175
+ summary: args.summary,
176
+ change_id: activeChangeId,
177
+ });
178
+ if (session.history.length > limits.history) {
179
+ session.history = session.history.slice(-limits.history);
180
+ }
181
+
182
+ // ── Conditional updates ────────────────────────────────────────────────
183
+
184
+ // --new-change: auto-snapshot old active_change, then set new one
185
+ if (args["new-change"]) {
186
+ session.active_change = session.active_change || {};
187
+
188
+ // Auto-snapshot: if there's an existing active_change with an id, upsert into changes[]
189
+ if (session.active_change.id) {
190
+ session.changes = session.changes || [];
191
+ const existingIdx = session.changes.findIndex(
192
+ (e) => e.id === session.active_change.id
193
+ );
194
+ const snapshotEntry = {
195
+ id: session.active_change.id,
196
+ title: session.active_change.title || "",
197
+ plan_path: session.active_change.plan_path || "",
198
+ status: "active",
199
+ updated_at: now,
200
+ };
201
+ if (existingIdx >= 0) {
202
+ session.changes[existingIdx] = snapshotEntry;
203
+ } else {
204
+ session.changes.push(snapshotEntry);
205
+ }
206
+ // Sort + truncate changes
207
+ session.changes.sort((a, b) => a.updated_at.localeCompare(b.updated_at));
208
+ if (session.changes.length > limits.changes) {
209
+ session.changes = session.changes.slice(-limits.changes);
210
+ }
211
+ }
212
+
213
+ // Now set new active_change
214
+ session.active_change.id = args["change-id"];
215
+ session.active_change.title = args["new-change"];
216
+ session.active_change.created_at = now;
217
+ session.active_change.plan_path = "";
218
+ }
219
+
220
+ // --set-initialized
221
+ if (args["set-initialized"]) {
222
+ session.session = session.session || {};
223
+ if (!session.session.initialized_at) {
224
+ session.session.initialized_at = now;
225
+ }
226
+ }
227
+
228
+ // --set-synced: set session.last_synced_at to current time
229
+ if (args["set-synced"]) {
230
+ session.session = session.session || {};
231
+ session.session.last_synced_at = now;
232
+ }
233
+
234
+ // --set-plan-path: set active_change.plan_path
235
+ // NOTE: Must execute BEFORE --update-change so that
236
+ // the upserted changes entry contains the correct plan_path.
237
+ if (args["set-plan-path"]) {
238
+ session.active_change = session.active_change || {};
239
+ session.active_change.plan_path = args["set-plan-path"];
240
+ }
241
+
242
+ // --update-change: upsert active_change into changes[] + truncate
243
+ if (args["update-change"]) {
244
+ session.changes = session.changes || [];
245
+ const ac = session.active_change || {};
246
+ const existingIdx = session.changes.findIndex(
247
+ (e) => e.id === ac.id
248
+ );
249
+ const entry = {
250
+ id: ac.id || "",
251
+ title: ac.title || "",
252
+ plan_path: ac.plan_path || "",
253
+ status: "active",
254
+ updated_at: now,
255
+ };
256
+ if (existingIdx >= 0) {
257
+ session.changes[existingIdx] = entry;
258
+ } else {
259
+ session.changes.push(entry);
260
+ }
261
+ // Sort by updated_at ascending, then truncate to limit
262
+ session.changes.sort(
263
+ (a, b) => a.updated_at.localeCompare(b.updated_at)
264
+ );
265
+ if (session.changes.length > limits.changes) {
266
+ session.changes = session.changes.slice(-limits.changes);
267
+ }
268
+ }
269
+
270
+ // --close-change: snapshot active_change to changes[] with status:done, clear active_change
271
+ if (args["close-change"]) {
272
+ session.changes = session.changes || [];
273
+ const ac = session.active_change || {};
274
+ if (ac.id) {
275
+ const existingIdx = session.changes.findIndex(
276
+ (e) => e.id === ac.id
277
+ );
278
+ const entry = {
279
+ id: ac.id,
280
+ title: ac.title || "",
281
+ plan_path: ac.plan_path || "",
282
+ status: "done",
283
+ updated_at: now,
284
+ };
285
+ if (existingIdx >= 0) {
286
+ session.changes[existingIdx] = entry;
287
+ } else {
288
+ session.changes.push(entry);
289
+ }
290
+ session.changes.sort(
291
+ (a, b) => a.updated_at.localeCompare(b.updated_at)
292
+ );
293
+ if (session.changes.length > limits.changes) {
294
+ session.changes = session.changes.slice(-limits.changes);
295
+ }
296
+ }
297
+ // Clear active_change
298
+ session.active_change = {
299
+ id: "",
300
+ title: "",
301
+ created_at: "",
302
+ plan_path: "",
303
+ };
304
+ }
305
+
306
+ // --set-change-status: set status on changes[] entry matching active_change.id
307
+ if (args["set-change-status"]) {
308
+ session.changes = session.changes || [];
309
+ const ac = session.active_change || {};
310
+ if (ac.id) {
311
+ const existingIdx = session.changes.findIndex(
312
+ (e) => e.id === ac.id
313
+ );
314
+ if (existingIdx >= 0) {
315
+ session.changes[existingIdx].status = args["set-change-status"];
316
+ session.changes[existingIdx].updated_at = now;
317
+ }
318
+ }
319
+ }
320
+
321
+ // --truncate-history: keep last N history entries, discard older
322
+ if (args["truncate-history"]) {
323
+ const n = Number(args["truncate-history"]);
324
+ if (Number.isInteger(n) && n > 0) {
325
+ session.history = session.history || [];
326
+ if (session.history.length > n) {
327
+ session.history = session.history.slice(-n);
328
+ }
329
+ }
330
+ }
331
+
332
+ // ── Write back atomically ─────────────────────────────────────────────
333
+ const tmpPath = sessionPath + ".tmp";
334
+
335
+ try {
336
+ writeFileSync(tmpPath, stringifyYaml(session), "utf-8");
337
+ renameSync(tmpPath, sessionPath);
338
+ } catch (e) {
339
+ try {
340
+ if (existsSync(tmpPath)) unlinkSync(tmpPath);
341
+ } catch {
342
+ // Best effort cleanup
343
+ }
344
+ process.stderr.write(ERRORS.SESSION_WRITE_FAILED(e.message) + "\n");
345
+ process.exit(1);
346
+ }
347
+
348
+ process.stdout.write('{"ok":true}\n');
349
+ }
350
+
351
+ main();
@@ -24,3 +24,7 @@ For each entry, resolve files relative to `.ai-agents/{source}`:
24
24
  - If the entry lists `files_from_manifest: true`, read `{source}/manifest.yaml` and load every `files[]` entry where `auto_load: true`.
25
25
 
26
26
  Skip any path that does not exist.
27
+
28
+ ### Archived Artifacts Convention
29
+
30
+ The directory `.ai-agents/workspace/artifacts/_archived/` contains change-id directories that have been archived by `/mvt-cleanup`. All skills that scan `artifacts/` MUST exclude `_archived/` from their scan scope unless explicitly inspecting archived content.
@@ -22,7 +22,7 @@ Match the current state to one of the conditions below. If none match, use `defa
22
22
  ### Resolution order
23
23
 
24
24
  Infer 2-3 suggestions from:
25
- - `skill_history` in `session.yaml`
25
+ - `history` in `session.yaml`
26
26
  - `category` and `description` of each skill in `registry.yaml`
27
27
  - The current `active_change` state (if in progress)
28
28
  - The `depends_on` relationships between skills
@@ -1,11 +1,11 @@
1
- ## Output Language Constraint (Mandatory)
2
-
3
- All persisted document output (files written to disk) MUST be written in the language specified by `preferences.document_output_language` from config.yaml.
4
-
5
- **Scope**: artifact files, generated reports, plans, and any markdown written to disk.
6
-
7
- **Rules**:
8
- - Section headings defined in templates may remain in their original language, but all generated **content** MUST use the configured language
9
- - If `document_output_language` is not set, fall back to `interaction_language`
10
- - Do NOT infer output language from template headings, user prompt language, or source code comments
11
- - This constraint is NON-NEGOTIABLE and overrides any other language signals
1
+ ## Output Language Constraint (Mandatory)
2
+
3
+ All persisted document output (files written to disk) MUST be written in the language specified by `preferences.document_output_language` from config.yaml.
4
+
5
+ **Scope**: artifact files, generated reports, plans, and any markdown written to disk.
6
+
7
+ **Rules**:
8
+ - Section headings defined in templates may remain in their original language, but all generated **content** MUST use the configured language
9
+ - If `document_output_language` is not set, fall back to `interaction_language`
10
+ - Do NOT infer output language from template headings, user prompt language, or source code comments
11
+ - This constraint is NON-NEGOTIABLE and overrides any other language signals