mdkg 0.1.4 → 0.1.5

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,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GOAL_SCOPE_ALLOWED_TYPES = exports.GOAL_SCOPE_ACTIONABLE_TYPES = exports.GOAL_SCOPE_CONTAINER_TYPES = void 0;
4
+ exports.goalScopeRefs = goalScopeRefs;
5
+ exports.collectGoalScope = collectGoalScope;
6
+ const qid_1 = require("../util/qid");
7
+ exports.GOAL_SCOPE_CONTAINER_TYPES = new Set(["epic", "feat"]);
8
+ exports.GOAL_SCOPE_ACTIONABLE_TYPES = new Set(["feat", "task", "bug", "test"]);
9
+ exports.GOAL_SCOPE_ALLOWED_TYPES = new Set([
10
+ ...exports.GOAL_SCOPE_CONTAINER_TYPES,
11
+ ...exports.GOAL_SCOPE_ACTIONABLE_TYPES,
12
+ ]);
13
+ function toStringList(value) {
14
+ if (!Array.isArray(value)) {
15
+ return [];
16
+ }
17
+ return value.filter((item) => typeof item === "string");
18
+ }
19
+ function goalScopeRefs(goal) {
20
+ return toStringList(goal.attributes.scope_refs);
21
+ }
22
+ function resolveGoalScopeRef(index, value, ws) {
23
+ const resolved = (0, qid_1.resolveQid)(index, value, ws);
24
+ return resolved.status === "ok" ? resolved.qid : undefined;
25
+ }
26
+ function addIfPresent(values, value) {
27
+ if (value) {
28
+ values.add(value);
29
+ }
30
+ }
31
+ function collectDirectCompatibilityRefs(index, goal) {
32
+ const qids = new Set();
33
+ const edges = goal.edges;
34
+ addIfPresent(qids, edges.next);
35
+ addIfPresent(qids, edges.prev);
36
+ addIfPresent(qids, edges.parent);
37
+ addIfPresent(qids, edges.epic);
38
+ for (const value of edges.relates) {
39
+ qids.add(value);
40
+ }
41
+ for (const value of edges.blocks) {
42
+ qids.add(value);
43
+ }
44
+ for (const value of edges.blocked_by) {
45
+ qids.add(value);
46
+ }
47
+ for (const node of Object.values(index.nodes)) {
48
+ if (node.edges.parent === goal.qid ||
49
+ node.edges.epic === goal.qid ||
50
+ node.edges.prev === goal.qid ||
51
+ node.edges.next === goal.qid ||
52
+ node.edges.relates.includes(goal.qid) ||
53
+ node.edges.blocked_by.includes(goal.qid) ||
54
+ node.edges.blocks.includes(goal.qid)) {
55
+ qids.add(node.qid);
56
+ }
57
+ }
58
+ return qids;
59
+ }
60
+ function descendantQids(index, qid) {
61
+ const byEpic = index.reverse_edges.epic?.[qid] ?? [];
62
+ const byParent = index.reverse_edges.parent?.[qid] ?? [];
63
+ return [...new Set([...byEpic, ...byParent])].sort();
64
+ }
65
+ function collectGoalScope(index, goal, options = {}) {
66
+ const includeCompatibilityRefs = options.includeCompatibilityRefs ?? true;
67
+ const rootQids = [];
68
+ const qids = new Set();
69
+ const actionableQids = new Set();
70
+ const missingRefs = [];
71
+ const invalidRefs = [];
72
+ const queued = new Set();
73
+ const queue = [];
74
+ function enqueue(qid) {
75
+ if (queued.has(qid)) {
76
+ return;
77
+ }
78
+ queued.add(qid);
79
+ queue.push(qid);
80
+ }
81
+ for (const ref of goalScopeRefs(goal)) {
82
+ const resolved = resolveGoalScopeRef(index, ref, goal.ws);
83
+ if (!resolved) {
84
+ missingRefs.push(ref);
85
+ continue;
86
+ }
87
+ rootQids.push(resolved);
88
+ enqueue(resolved);
89
+ }
90
+ if (includeCompatibilityRefs) {
91
+ for (const qid of collectDirectCompatibilityRefs(index, goal)) {
92
+ rootQids.push(qid);
93
+ enqueue(qid);
94
+ }
95
+ }
96
+ while (queue.length > 0) {
97
+ const qid = queue.shift();
98
+ if (!qid) {
99
+ break;
100
+ }
101
+ const node = index.nodes[qid];
102
+ if (!node) {
103
+ continue;
104
+ }
105
+ if (!exports.GOAL_SCOPE_ALLOWED_TYPES.has(node.type)) {
106
+ invalidRefs.push(qid);
107
+ continue;
108
+ }
109
+ qids.add(qid);
110
+ if (exports.GOAL_SCOPE_ACTIONABLE_TYPES.has(node.type)) {
111
+ actionableQids.add(qid);
112
+ }
113
+ if (exports.GOAL_SCOPE_CONTAINER_TYPES.has(node.type)) {
114
+ for (const childQid of descendantQids(index, qid)) {
115
+ enqueue(childQid);
116
+ }
117
+ }
118
+ }
119
+ rootQids.sort();
120
+ return {
121
+ rootQids: [...new Set(rootQids)],
122
+ qids,
123
+ actionableQids,
124
+ missingRefs,
125
+ invalidRefs: [...new Set(invalidRefs)].sort(),
126
+ };
127
+ }
@@ -10,7 +10,7 @@ const id_1 = require("../util/id");
10
10
  const refs_1 = require("../util/refs");
11
11
  const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
12
12
  const DEC_ID_RE = /^dec-[0-9]+$/;
13
- exports.WORK_TYPES = new Set(["epic", "feat", "task", "bug", "checkpoint", "test"]);
13
+ exports.WORK_TYPES = new Set(["goal", "epic", "feat", "task", "bug", "checkpoint", "test"]);
14
14
  exports.DEC_TYPES = new Set(["dec"]);
15
15
  exports.ALLOWED_TYPES = new Set([
16
16
  "rule",
@@ -18,6 +18,7 @@ exports.ALLOWED_TYPES = new Set([
18
18
  "edd",
19
19
  "dec",
20
20
  "prop",
21
+ "goal",
21
22
  "epic",
22
23
  "feat",
23
24
  "task",
@@ -28,7 +29,18 @@ exports.ALLOWED_TYPES = new Set([
28
29
  ...agent_file_types_1.AGENT_FILE_TYPES,
29
30
  ]);
30
31
  const DEC_STATUS = new Set(["proposed", "accepted", "rejected", "superseded"]);
32
+ const GOAL_STATE = new Set(["active", "paused", "achieved", "blocked", "budget_limited"]);
31
33
  const SKILL_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
34
+ const GOAL_ATTRIBUTE_KEYS = [
35
+ "goal_state",
36
+ "goal_condition",
37
+ "scope_refs",
38
+ "active_node",
39
+ "required_skills",
40
+ "required_checks",
41
+ "max_iterations",
42
+ "blocked_after_attempts",
43
+ ];
32
44
  function formatError(filePath, message) {
33
45
  return new Error(`${filePath}: ${message}`);
34
46
  }
@@ -142,6 +154,71 @@ function normalizeSkillList(values, filePath) {
142
154
  return normalized;
143
155
  });
144
156
  }
157
+ function parsePositiveIntegerString(value, key, filePath) {
158
+ if (!/^[1-9][0-9]*$/.test(value)) {
159
+ throw formatError(filePath, `${key} must be a positive integer`);
160
+ }
161
+ return value;
162
+ }
163
+ function validateGoalFrontmatter(type, frontmatter, filePath) {
164
+ if (type !== "goal") {
165
+ return;
166
+ }
167
+ const goalState = requireLowercase(expectString(frontmatter, "goal_state", filePath), "goal_state", filePath);
168
+ if (!GOAL_STATE.has(goalState)) {
169
+ throw formatError(filePath, `goal_state must be one of ${Array.from(GOAL_STATE).join(", ")}`);
170
+ }
171
+ const goalCondition = expectString(frontmatter, "goal_condition", filePath);
172
+ if (goalCondition.length > 4000) {
173
+ throw formatError(filePath, "goal_condition must be 4000 characters or fewer");
174
+ }
175
+ const activeNode = optionalString(frontmatter, "active_node", filePath);
176
+ if (activeNode !== undefined) {
177
+ const normalized = requireLowercase(activeNode, "active_node", filePath);
178
+ if (!(0, id_1.isPortableIdRef)(normalized)) {
179
+ throw formatError(filePath, "active_node must be a local id or qid");
180
+ }
181
+ }
182
+ const scopeRefs = optionalList(frontmatter, "scope_refs", filePath);
183
+ for (const [index, value] of scopeRefs.entries()) {
184
+ if (typeof value !== "string" || value.trim().length === 0) {
185
+ throw formatError(filePath, `scope_refs[${index}] must not be empty`);
186
+ }
187
+ const normalized = requireLowercase(value, `scope_refs[${index}]`, filePath);
188
+ if (!(0, id_1.isPortableIdRef)(normalized)) {
189
+ throw formatError(filePath, `scope_refs[${index}] must be a local id or qid`);
190
+ }
191
+ }
192
+ const requiredSkills = optionalList(frontmatter, "required_skills", filePath);
193
+ normalizeSkillList(requiredSkills, filePath);
194
+ const requiredChecks = optionalList(frontmatter, "required_checks", filePath);
195
+ for (const [index, value] of requiredChecks.entries()) {
196
+ if (typeof value !== "string" || value.trim().length === 0) {
197
+ throw formatError(filePath, `required_checks[${index}] must not be empty`);
198
+ }
199
+ }
200
+ const maxIterations = optionalString(frontmatter, "max_iterations", filePath);
201
+ if (maxIterations !== undefined) {
202
+ parsePositiveIntegerString(maxIterations, "max_iterations", filePath);
203
+ }
204
+ const blockedAfterAttempts = optionalString(frontmatter, "blocked_after_attempts", filePath);
205
+ if (blockedAfterAttempts !== undefined) {
206
+ parsePositiveIntegerString(blockedAfterAttempts, "blocked_after_attempts", filePath);
207
+ }
208
+ }
209
+ function extractGoalAttributes(type, frontmatter) {
210
+ if (type !== "goal") {
211
+ return {};
212
+ }
213
+ const attributes = {};
214
+ for (const key of GOAL_ATTRIBUTE_KEYS) {
215
+ const value = frontmatter[key];
216
+ if (value !== undefined) {
217
+ attributes[key] = value;
218
+ }
219
+ }
220
+ return attributes;
221
+ }
145
222
  function requireTemplateSchema(type, templateSchemas, filePath) {
146
223
  const schema = templateSchemas[type];
147
224
  if (!schema) {
@@ -185,6 +262,7 @@ function parseNode(content, filePath, options) {
185
262
  validateTemplateKeys(frontmatter, schema, filePath);
186
263
  (0, agent_file_types_1.validateAgentFrontmatter)(type, frontmatter, filePath);
187
264
  (0, archive_file_1.validateArchiveFrontmatter)(type, frontmatter, filePath);
265
+ validateGoalFrontmatter(type, frontmatter, filePath);
188
266
  const idValue = requireLowercase(expectString(frontmatter, "id", filePath), "id", filePath);
189
267
  const id = isPortableType
190
268
  ? requirePortableIdFormat(idValue, "id", filePath)
@@ -250,6 +328,7 @@ function parseNode(content, filePath, options) {
250
328
  }
251
329
  const edges = (0, edges_1.extractEdges)(frontmatter, filePath, { allowPortableRefs: isPortableType });
252
330
  const attributes = {
331
+ ...extractGoalAttributes(type, frontmatter),
253
332
  ...(0, agent_file_types_1.extractAgentAttributes)(type, frontmatter),
254
333
  ...(0, archive_file_1.extractArchiveAttributes)(type, frontmatter),
255
334
  };
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.collectGraphErrors = collectGraphErrors;
4
4
  exports.validateGraph = validateGraph;
5
5
  const refs_1 = require("../util/refs");
6
+ const goal_scope_1 = require("./goal_scope");
6
7
  function pushError(errors, message) {
7
8
  if (errors) {
8
9
  errors.push(message);
@@ -433,6 +434,45 @@ function validateArchiveUriRefs(index, allowMissing, errors) {
433
434
  }
434
435
  }
435
436
  }
437
+ function validateGoalRefs(index, allowMissing, errors) {
438
+ for (const [qid, node] of Object.entries(index.nodes)) {
439
+ if (node.type !== "goal") {
440
+ continue;
441
+ }
442
+ const scope = (0, goal_scope_1.collectGoalScope)(index, node, { includeCompatibilityRefs: false });
443
+ for (const ref of scope.missingRefs) {
444
+ if (allowMissing) {
445
+ continue;
446
+ }
447
+ pushError(errors, `${qid}: scope_refs references missing node ${ref}`);
448
+ }
449
+ for (const ref of scope.invalidRefs) {
450
+ const target = index.nodes[ref];
451
+ const typeLabel = target ? target.type : "missing";
452
+ pushError(errors, `${qid}: scope_refs references ${ref} with type ${typeLabel}, expected ${Array.from(goal_scope_1.GOAL_SCOPE_ALLOWED_TYPES).join(", ")}`);
453
+ }
454
+ const activeNode = node.attributes.active_node;
455
+ if (typeof activeNode !== "string") {
456
+ continue;
457
+ }
458
+ const activeQid = activeNode.includes(":") ? activeNode : `${node.ws}:${activeNode}`;
459
+ const target = index.nodes[activeQid];
460
+ if (!target) {
461
+ if (allowMissing) {
462
+ continue;
463
+ }
464
+ pushError(errors, `${qid}: active_node references missing node ${activeNode}`);
465
+ continue;
466
+ }
467
+ if (!goal_scope_1.GOAL_SCOPE_ACTIONABLE_TYPES.has(target.type)) {
468
+ pushError(errors, `${qid}: active_node references ${activeQid} with type ${target.type}, expected ${Array.from(goal_scope_1.GOAL_SCOPE_ACTIONABLE_TYPES).join(", ")}`);
469
+ continue;
470
+ }
471
+ if (scope.qids.size > 0 && !scope.actionableQids.has(activeQid)) {
472
+ pushError(errors, `${qid}: active_node ${activeQid} is not inside goal scope_refs`);
473
+ }
474
+ }
475
+ }
436
476
  function detectPrevNextCycles(index, errors) {
437
477
  const nodes = index.nodes;
438
478
  const seen = new Set();
@@ -480,6 +520,7 @@ function collectGraphErrors(index, options = {}) {
480
520
  validateAgentWorkflowDisputeRefs(index, allowMissing, errors);
481
521
  validateAgentWorkflowFeedbackProposalRefs(index, allowMissing, knownSkillSlugs, externalWorkspaces, errors);
482
522
  validateArchiveUriRefs(index, allowMissing, errors);
523
+ validateGoalRefs(index, allowMissing, errors);
483
524
  detectPrevNextCycles(index, errors);
484
525
  return errors;
485
526
  }
@@ -23,6 +23,11 @@ Agent operating prompt:
23
23
  - Treat mdkg rules, EDDs, DECs, PRDs, and work nodes as more authoritative than chat memory.
24
24
  - Use `mdkg show <id>` for direct inspection and `mdkg show <id> --meta` for card-only inspection.
25
25
  - Use `mdkg search "..."` and `mdkg next` to discover current work.
26
+ - Use `mdkg new goal "..."` for long-running recursive objectives that need an explicit end condition, active node, required skills, required checks, and completion evidence.
27
+ - Use `mdkg goal select <goal-id>` when a goal is active, then `mdkg goal next` to surface one scoped feature, task, bug, or test at a time; normal `mdkg next` remains for non-goal concrete work.
28
+ - Use `mdkg goal claim [goal-id] <work-id>` only after accepting the surfaced work item; `mdkg goal next` is read-only.
29
+ - Treat goal `required_checks` as report-only guidance from mdkg. Run commands yourself, then record evidence in the goal or active work item.
30
+ - Record skill improvement candidates during normal goal execution; edit `SKILL.md` only when the active node is explicit skill-maintenance work.
26
31
  - Use `mdkg skill list`, `mdkg skill search`, and `mdkg skill show <slug>` for skill discovery.
27
32
  - Use `mdkg capability list/search/show` for deterministic skills, `SPEC.md`, `WORK.md`, core-doc, and design-doc capability discovery.
28
33
  - Use `mdkg index` to refresh JSON compatibility caches and `.mdkg/index/mdkg.sqlite` when SQLite mode is enabled.
@@ -51,6 +56,16 @@ If the active task is known:
51
56
  - `mdkg task done <id>` when work is complete
52
57
  - `mdkg validate`
53
58
 
59
+ If an active goal is known:
60
+ - `mdkg goal select <goal-id>`
61
+ - `mdkg goal current`
62
+ - `mdkg goal next`
63
+ - `mdkg goal claim <work-id>`
64
+ - work the selected concrete node to completion
65
+ - run required checks and record evidence
66
+ - `mdkg goal evaluate <goal-id>`
67
+ - repeat until the goal condition is achieved, blocked, paused, or budget-limited
68
+
54
69
  If no task is known:
55
70
  - `mdkg search "..."`
56
71
  - `mdkg show <id>`
@@ -19,6 +19,7 @@ Primary commands:
19
19
  - `mdkg archive`
20
20
  - `mdkg bundle`
21
21
  - `mdkg work`
22
+ - `mdkg goal`
22
23
  - `mdkg task`
23
24
  - `mdkg validate`
24
25
 
@@ -32,6 +33,7 @@ Validation commands:
32
33
 
33
34
  Node creation commands:
34
35
  - `mdkg new <type> "<title>" [options] [--json]`
36
+ - `mdkg new goal "<title>" [options] [--json]`
35
37
 
36
38
  Agent workflow file type creation:
37
39
  - `mdkg new spec "<title>" [options] [--json]`
@@ -48,6 +50,7 @@ Agent workflow notes:
48
50
  - `--id <portable-id>` is only for agent workflow file types.
49
51
  - `spec` and `work` scaffold as validation-clean standalone docs.
50
52
  - `work_order`, `receipt`, `feedback`, `dispute`, and `proposal` need real refs before strict `mdkg validate` passes.
53
+ - `goal` nodes capture recursive objective state and required checks, but normal `mdkg next` does not select them.
51
54
 
52
55
  Workspace registry commands:
53
56
  - `mdkg workspace ls [--json]`
@@ -146,6 +149,30 @@ Work semantic mirrors:
146
149
  - `artifact://...` refs identify external/runtime-managed artifacts; `archive://...` refs identify committed mdkg archive sidecars
147
150
  - work update and artifact commands accept local ids or local qids; subgraph qids are read-only and must be changed in their source workspace
148
151
 
152
+ Goal nodes:
153
+ - `mdkg goal show <goal-id-or-qid> [--json]`
154
+ - `mdkg goal select <goal-id-or-qid> [--json]`
155
+ - `mdkg goal current [--json]`
156
+ - `mdkg goal clear [--json]`
157
+ - `mdkg goal next [goal-id-or-qid] [--json]`
158
+ - `mdkg goal claim [goal-id-or-qid] <work-id-or-qid> [--json]`
159
+ - `mdkg goal evaluate <goal-id-or-qid> [--json]`
160
+ - `mdkg goal pause|resume|done <goal-id-or-qid> [--json]`
161
+ - `mdkg goal show <goal-id-or-qid> [--ws <alias>] [--json]`
162
+ - `mdkg goal select <goal-id-or-qid> [--ws <alias>] [--json]`
163
+ - `mdkg goal current [--ws <alias>] [--json]`
164
+ - `mdkg goal next [goal-id-or-qid] [--ws <alias>] [--json]`
165
+ - `mdkg goal claim <work-id-or-qid> [--ws <alias>] [--json]`
166
+ - `mdkg goal claim <goal-id-or-qid> <work-id-or-qid> [--ws <alias>] [--json]`
167
+ - `mdkg goal evaluate <goal-id-or-qid> [--ws <alias>] [--json]`
168
+ - `mdkg goal pause <goal-id-or-qid> [--ws <alias>] [--json]`
169
+ - `mdkg goal resume <goal-id-or-qid> [--ws <alias>] [--json]`
170
+ - `mdkg goal done <goal-id-or-qid> [--ws <alias>] [--json]`
171
+ - goals orchestrate recursive progress through explicit `scope_refs`; tasks, bugs, tests, and features remain concrete executable units
172
+ - `goal next` is read-only; use `goal claim` to set `active_node`
173
+ - `mdkg goal evaluate` is report-only and never runs commands from `required_checks`
174
+ - skill improvements discovered during normal goal execution should be recorded as candidates or proposals unless the active node is skill-maintenance
175
+
149
176
  Discovery/show export flags:
150
177
  - `--json`
151
178
  - `--xml`
@@ -30,7 +30,7 @@ mdkg subgraph list --json
30
30
  mdkg validate
31
31
  ```
32
32
 
33
- This repo is already initialized. Use `mdkg upgrade` to preview safe scaffold updates, `mdkg new` to create work, `mdkg search`/`mdkg show` to inspect graph state, `mdkg capability ...` to inspect cached skill/spec/work/core/design capabilities, `mdkg capability resolve ...` to rank local and subgraph capabilities, `mdkg archive ...` to register source/artifact sidecars, `mdkg work ...` to create work contract/order/receipt semantic mirrors, `mdkg bundle ...` to create full graph snapshot bundles, `mdkg subgraph ...` to register read-only child graph planning views, `mdkg pack <id>` to build deterministic context, and `mdkg validate` before closeout.
33
+ This repo is already initialized. Use `mdkg upgrade` to preview safe scaffold updates, `mdkg new` to create work, `mdkg new goal "..."` plus `mdkg goal select/current/next/claim/evaluate` for recursive long-running objectives, `mdkg search`/`mdkg show` to inspect graph state, `mdkg capability ...` to inspect cached skill/spec/work/core/design capabilities, `mdkg capability resolve ...` to rank local and subgraph capabilities, `mdkg archive ...` to register source/artifact sidecars, `mdkg work ...` to create work contract/order/receipt semantic mirrors, `mdkg bundle ...` to create full graph snapshot bundles, `mdkg subgraph ...` to register read-only child graph planning views, `mdkg pack <id>` to build deterministic context, and `mdkg validate` before closeout.
34
34
 
35
35
  Agent workflow docs can use semantic ids:
36
36
 
@@ -157,6 +157,7 @@ If a user provides an unqualified ID and it is ambiguous globally:
157
157
  - uses global templates (root-only) via token substitution
158
158
  - writes into the appropriate workspace-local `.mdkg/<area>/` folder
159
159
  - updates index if necessary
160
+ - supports `goal` nodes for recursive objective contracts
160
161
 
161
162
  Common flags:
162
163
  - `--ws <alias>` (default `root`)
@@ -176,6 +177,27 @@ Common flags:
176
177
  - `--skills <slug,slug,...>` (work items)
177
178
  - `--template <set>` (default from config)
178
179
 
180
+ ### Goal commands
181
+ - `mdkg goal show <goal-id-or-qid> [--ws <alias>] [--json]`
182
+ - reports condition, goal state, scope refs, active node, required skills, required checks, and source path
183
+ - `mdkg goal select <goal-id-or-qid> [--ws <alias>] [--json]`
184
+ - stores local ignored selected-goal state at `.mdkg/state/selected-goal.json`
185
+ - `mdkg goal current [--ws <alias>] [--json]`
186
+ - reports selected goal or a unique active goal fallback without requiring committed state
187
+ - `mdkg goal clear [--json]`
188
+ - clears local selected-goal state
189
+ - `mdkg goal next [goal-id-or-qid] [--ws <alias>] [--json]`
190
+ - read-only; resolves explicit id, then selected goal, then one unique active goal
191
+ - recursively expands `scope_refs` through `epic` and `parent` edges
192
+ - selects local `feat`, `task`, `bug`, or `test` work and never returns the goal or container-only epic itself
193
+ - `mdkg goal claim [goal-id-or-qid] <work-id-or-qid> [--ws <alias>] [--json]`
194
+ - explicit mutating path that writes goal `active_node` after the work is confirmed inside scope
195
+ - `mdkg goal evaluate <goal-id-or-qid> [--ws <alias>] [--json]`
196
+ - report-only; lists required checks and completion evidence state without executing scripts
197
+ - `mdkg goal pause|resume|done <goal-id-or-qid> [--ws <alias>] [--json]`
198
+ - updates `goal_state`, compatible work status, and `updated`
199
+ - subgraph goal qids are read-only and must be changed in their source workspace
200
+
179
201
  ### Read/search
180
202
  - `mdkg show <id-or-qid> [--meta] [--json|--xml|--toon|--md]`
181
203
  - default behavior shows the full node body
@@ -290,6 +312,7 @@ Common flags:
290
312
  - `mdkg next [<id-or-qid>] [--ws <alias>]`
291
313
  - If `<id>` provided: follow `next` if present; otherwise fall back to priority-based selection.
292
314
  - If no `<id>` provided: use priority-based selection (and optionally an epic filter in future).
315
+ - Does not select `goal` nodes; use `mdkg goal select <goal-id>` plus `mdkg goal next`, or explicit `mdkg goal next <goal-id>`, for goal-scoped selection.
293
316
 
294
317
  ### Checkpoints
295
318
  - `mdkg checkpoint new "<title>" [--ws <alias>] [--relates <id,...>] [--scope <id,...>]`
@@ -310,6 +333,9 @@ Common flags:
310
333
  - `TASK_STARTED`
311
334
  - `TASK_UPDATED`
312
335
  - `TASK_DONE`
336
+ - `GOAL_PAUSE`
337
+ - `GOAL_RESUME`
338
+ - `GOAL_DONE`
313
339
 
314
340
  ### Validation and formatting
315
341
  - `mdkg validate`
@@ -23,6 +23,7 @@ mdkg content may contain sensitive notes and internal project planning. This rul
23
23
  - `.mdkg/` must not be published to npm.
24
24
  - Generated JSON index, temp, lock, WAL, SHM, and journal files under `.mdkg/index/` must not be committed.
25
25
  - `.mdkg/index/mdkg.sqlite` is a rebuildable access cache and may be committed when the repo intentionally tracks it and it stays reasonably small.
26
+ - `.mdkg/state/` stores local workflow convenience state and must not be committed.
26
27
  - `.mdkg/bundles/` may be committed only when the repo intentionally tracks private or public snapshot bundles.
27
28
 
28
29
  ## Git ignore requirements
@@ -37,6 +38,7 @@ The repo MUST ignore at minimum:
37
38
  - `.mdkg/index/*.sqlite-wal`
38
39
  - `.mdkg/index/*.sqlite-shm`
39
40
  - `.mdkg/index/*.sqlite-journal`
41
+ - `.mdkg/state/`
40
42
  - `.mdkg/pack/`
41
43
  - `.mdkg/archive/**/source/`
42
44
 
@@ -47,6 +49,7 @@ Recommended `.gitignore` entries:
47
49
  - `.mdkg/index/*.sqlite-wal`
48
50
  - `.mdkg/index/*.sqlite-shm`
49
51
  - `.mdkg/index/*.sqlite-journal`
52
+ - `.mdkg/state/`
50
53
  - `.mdkg/pack/`
51
54
  - `.mdkg/archive/**/source/`
52
55
 
@@ -87,7 +90,7 @@ For application builds:
87
90
 
88
91
  `mdkg init` updates ignore files by default for safety:
89
92
 
90
- - `.gitignore` appends generated index cache/temp/lock patterns, `.mdkg/pack/`, and raw archive source ignores.
93
+ - `.gitignore` appends generated index cache/temp/lock patterns, `.mdkg/state/`, `.mdkg/pack/`, and raw archive source ignores.
91
94
  - `.npmignore` appends `.mdkg/`, generated index cache/temp/lock patterns, and `.mdkg/pack/`.
92
95
  - `--no-update-ignores` disables these default writes
93
96
 
@@ -102,6 +105,7 @@ Explicit flags remain available and take precedence:
102
105
  - `.mdkg/index/` contains generated caches.
103
106
  - JSON index files may contain extracted metadata and could expose sensitive strings; they MUST be ignored from git.
104
107
  - `.mdkg/index/mdkg.sqlite` contains the same rebuildable access data and may be committed only by explicit repo policy; `mdkg doctor` warns when it exceeds `index.sqlite_commit_warning_bytes`.
108
+ - `.mdkg/state/` contains local workflow convenience state such as selected goals and MUST stay ignored.
105
109
  - Index rebuild should be deterministic and safe to regenerate at any time.
106
110
 
107
111
  ## Bundle safety
@@ -131,6 +135,7 @@ Workspace-local `.mdkg/` directories (near code) should follow the same rules:
131
135
  ## Summary checklist
132
136
 
133
137
  - ✅ generated JSON index/temp/lock files ignored
138
+ - ✅ local `.mdkg/state/` ignored
134
139
  - ✅ `.mdkg/index/mdkg.sqlite` committed only by explicit repo policy
135
140
  - ✅ event logs are committed by default unless a repo chooses to ignore them manually
136
141
  - ✅ npm publishes only `dist/`, `README.md`, `LICENSE`
@@ -91,12 +91,21 @@ All nodes MAY include the following searchable frontmatter lists:
91
91
  List fields SHOULD be written as `[]` when empty.
92
92
  Optional scalar graph fields (like `epic`, `parent`, `prev`, `next`) should be omitted when empty.
93
93
 
94
- Work items (`epic/feat/task/bug/checkpoint/test`):
94
+ Work items (`goal/epic/feat/task/bug/checkpoint/test`):
95
95
  - `status` (enum)
96
96
  - optional `priority` (0..9)
97
97
  - optional `skills: [slug, ...]` (kebab-case skill slugs)
98
98
  - optional graph edges: `epic`, `parent`, `relates`, `blocked_by`, `blocks`, `prev`, `next`
99
99
 
100
+ Goal nodes (`goal-*`):
101
+ - required `goal_state`: `active`, `paused`, `achieved`, `blocked`, or `budget_limited`
102
+ - required `goal_condition` up to 4000 characters for external slash-command compatibility
103
+ - optional `scope_refs: [id-or-qid, ...]` naming explicit goal ownership roots; allowed targets are `epic`, `feat`, `task`, `bug`, and `test`
104
+ - optional `active_node`
105
+ - optional `required_skills: [slug, ...]`
106
+ - optional `required_checks: [command, ...]` as report-only guidance; mdkg does not execute these scripts
107
+ - optional positive integer strings `max_iterations` and `blocked_after_attempts`
108
+
100
109
  Decision records (`dec-*`):
101
110
  - `status` (enum: `proposed`, `accepted`, `rejected`, `superseded`)
102
111
  - optional `supersedes: dec-#`
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "tool": "mdkg",
4
- "mdkg_version": "0.1.4",
4
+ "mdkg_version": "0.1.5",
5
5
  "files": [
6
6
  {
7
7
  "path": ".mdkg/config.json",
@@ -36,12 +36,12 @@
36
36
  {
37
37
  "path": ".mdkg/core/rule-3-cli-contract.md",
38
38
  "category": "core",
39
- "sha256": "4ec25c6936eefe0857a2946b47f0b65c9481bd65f1159fd5456bec6cce9de7ea"
39
+ "sha256": "0b72a2448cc91779278fed6e011c3936c31c5b11a7365a4145941dcc90f805a3"
40
40
  },
41
41
  {
42
42
  "path": ".mdkg/core/rule-4-repo-safety-and-ignores.md",
43
43
  "category": "core",
44
- "sha256": "2374e8684dfb32d24d560c83c99c33ff655cfdfe6811372dc3959ec93318a6db"
44
+ "sha256": "d8aff39af7a00e63db51831d4324856bbf49d3e3434141416903bad42c7d5380"
45
45
  },
46
46
  {
47
47
  "path": ".mdkg/core/rule-5-release-and-versioning.md",
@@ -51,7 +51,7 @@
51
51
  {
52
52
  "path": ".mdkg/core/rule-6-templates-and-schemas.md",
53
53
  "category": "core",
54
- "sha256": "5181e2e8a025cb6b9d160c1232c425bfc426fd8fd1ae3f75ce5052981807fc5f"
54
+ "sha256": "3ae20e1a925154ddc69bfc79495b169500aa5158db2134336890b00e64750c2f"
55
55
  },
56
56
  {
57
57
  "path": ".mdkg/core/SOUL.md",
@@ -61,22 +61,27 @@
61
61
  {
62
62
  "path": ".mdkg/README.md",
63
63
  "category": "mdkg_doc",
64
- "sha256": "5ee6c141c0052e78671762e69c111f7f0a5d7f79b35c8f78c5b3b41901bd6959"
64
+ "sha256": "f733792daa2b0f3318fd7b39fa2f812c61b8a3f5f630dba2f271cdcb10af9927"
65
65
  },
66
66
  {
67
67
  "path": ".mdkg/skills/build-pack-and-execute-task/SKILL.md",
68
68
  "category": "default_skill",
69
69
  "sha256": "3e240cb844b22e5e4c0046a4f839ac3c0d771a62d00a72719fc449477564b1ae"
70
70
  },
71
+ {
72
+ "path": ".mdkg/skills/pursue-mdkg-goal/SKILL.md",
73
+ "category": "default_skill",
74
+ "sha256": "fd64f666fb1329c392ff0979ed9999b71ad948cbca6a191502eb2cdfd76ec825"
75
+ },
71
76
  {
72
77
  "path": ".mdkg/skills/select-work-and-ground-context/SKILL.md",
73
78
  "category": "default_skill",
74
- "sha256": "c8c04134532deda079f9ee290a66b2423892f9789fa946e44db4c89c05b8e1bf"
79
+ "sha256": "e50fc3b1a2c79a9a3544ca9df1bf4ca9c312e7c3a51d5e4c6f3314341eca268b"
75
80
  },
76
81
  {
77
82
  "path": ".mdkg/skills/verify-close-and-checkpoint/SKILL.md",
78
83
  "category": "default_skill",
79
- "sha256": "67fc3d7e3c59b53add62306624391c1a416d0c66077729d79e1be0a303538f42"
84
+ "sha256": "f85ffa4a139db10c3bc3203cde0e4f41603fbc7f3925e6fdaba821346ffa28b8"
80
85
  },
81
86
  {
82
87
  "path": ".mdkg/templates/default/archive.md",
@@ -123,6 +128,11 @@
123
128
  "category": "template",
124
129
  "sha256": "61ad7b8b717d17736ba505f814fa6e4f9ec61f7fe4ae6622359304620a99d649"
125
130
  },
131
+ {
132
+ "path": ".mdkg/templates/default/goal.md",
133
+ "category": "template",
134
+ "sha256": "710252d8a2dc35be71661d6988007af127052fa8ad24b1fb00374c975ae117a2"
135
+ },
126
136
  {
127
137
  "path": ".mdkg/templates/default/prd.md",
128
138
  "category": "template",
@@ -176,7 +186,7 @@
176
186
  {
177
187
  "path": "AGENT_START.md",
178
188
  "category": "startup_doc",
179
- "sha256": "abde8671d34fcc7abd8570cf8c10b940cbe8f339edb369bd046045aa5626c0fc"
189
+ "sha256": "bb8654d11adb2ed6cb45f3514bbf7fad8fe6cda8a2e0e1676462542563df0df9"
180
190
  },
181
191
  {
182
192
  "path": "AGENTS.md",
@@ -191,7 +201,7 @@
191
201
  {
192
202
  "path": "CLI_COMMAND_MATRIX.md",
193
203
  "category": "startup_doc",
194
- "sha256": "14deecded057a99284d2dc147855d12dedffec049da51fed3b1ebdae3105d537"
204
+ "sha256": "a2f59afae403fff7335b0cf0109ee550c7a864b9ef6744b39a645096432e5206"
195
205
  },
196
206
  {
197
207
  "path": "llms.txt",