goalbuddy 0.3.6 → 0.3.7

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 (73) hide show
  1. package/README.md +17 -8
  2. package/RELEASE-0.3.5.md +4 -4
  3. package/RELEASE-0.3.7.md +127 -0
  4. package/goalbuddy/SKILL.md +19 -10
  5. package/goalbuddy/scripts/check-goal-state.mjs +53 -0
  6. package/goalbuddy/scripts/render-task-prompt.mjs +22 -1
  7. package/{plugins/goalbuddy/skills/goalbuddy/extend → goalbuddy/surfaces}/local-goal-board/README.md +7 -9
  8. package/{plugins/goalbuddy/skills/goalbuddy/extend → goalbuddy/surfaces}/local-goal-board/examples/sample-goal/state.yaml +5 -5
  9. package/{plugins/goalbuddy/skills/goalbuddy/extend → goalbuddy/surfaces}/local-goal-board/examples/subgoal-parent/state.yaml +3 -3
  10. package/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/subgoals/T004-board-view/state.yaml +3 -3
  11. package/goalbuddy/{extend → surfaces}/local-goal-board/scripts/lib/goal-board.mjs +2 -2
  12. package/goalbuddy/{extend → surfaces}/local-goal-board/scripts/local-goal-board.mjs +4 -4
  13. package/goalbuddy/{extend → surfaces}/local-goal-board/test/local-goal-board.test.mjs +8 -8
  14. package/goalbuddy/templates/goal.md +9 -0
  15. package/goalbuddy/templates/state.yaml +7 -6
  16. package/internal/assets/goalbuddy-v0.3.7-release.png +0 -0
  17. package/internal/cli/goal-maker.mjs +9 -711
  18. package/package.json +4 -4
  19. package/plugins/goalbuddy/.claude-plugin/plugin.json +3 -4
  20. package/plugins/goalbuddy/.codex-plugin/plugin.json +5 -6
  21. package/plugins/goalbuddy/README.md +4 -3
  22. package/plugins/goalbuddy/skills/goalbuddy/SKILL.md +19 -10
  23. package/plugins/goalbuddy/skills/goalbuddy/scripts/check-goal-state.mjs +53 -0
  24. package/plugins/goalbuddy/skills/goalbuddy/scripts/render-task-prompt.mjs +22 -1
  25. package/{goalbuddy/extend → plugins/goalbuddy/skills/goalbuddy/surfaces}/local-goal-board/README.md +7 -9
  26. package/{goalbuddy/extend → plugins/goalbuddy/skills/goalbuddy/surfaces}/local-goal-board/examples/sample-goal/state.yaml +5 -5
  27. package/{goalbuddy/extend → plugins/goalbuddy/skills/goalbuddy/surfaces}/local-goal-board/examples/subgoal-parent/state.yaml +3 -3
  28. package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/subgoals/T004-board-view/state.yaml +3 -3
  29. package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/scripts/lib/goal-board.mjs +2 -2
  30. package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/scripts/local-goal-board.mjs +4 -4
  31. package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/test/local-goal-board.test.mjs +8 -8
  32. package/plugins/goalbuddy/skills/goalbuddy/templates/goal.md +9 -0
  33. package/plugins/goalbuddy/skills/goalbuddy/templates/state.yaml +7 -6
  34. package/examples/extend-catalog-workflow/goal.md +0 -53
  35. package/examples/extend-catalog-workflow/notes/T001-extension-model-map.md +0 -47
  36. package/examples/extend-catalog-workflow/notes/T002-architecture-decision.md +0 -48
  37. package/examples/extend-catalog-workflow/notes/T003-implementation-summary.md +0 -43
  38. package/examples/extend-catalog-workflow/notes/T004-root-extend-folder.md +0 -24
  39. package/examples/extend-catalog-workflow/notes/T005-layout-cleanup.md +0 -46
  40. package/examples/extend-catalog-workflow/notes/T006-catalog-location.md +0 -50
  41. package/examples/extend-catalog-workflow/notes/T999-completion-audit.md +0 -36
  42. package/examples/extend-catalog-workflow/state.yaml +0 -327
  43. package/examples/github-pr-workflow-extension/pr-handoff.md +0 -46
  44. package/goalbuddy/extend/github-projects/README.md +0 -105
  45. package/goalbuddy/extend/github-projects/examples/goal-board-sync/state.yaml +0 -63
  46. package/goalbuddy/extend/github-projects/extension.yaml +0 -43
  47. package/goalbuddy/extend/github-projects/scripts/lib/github-projects.mjs +0 -728
  48. package/goalbuddy/extend/github-projects/scripts/lib/goal-state.mjs +0 -362
  49. package/goalbuddy/extend/github-projects/scripts/sync-github-project.mjs +0 -193
  50. package/goalbuddy/extend/github-projects/test/github-projects.test.mjs +0 -267
  51. package/goalbuddy/extend/local-goal-board/extension.yaml +0 -39
  52. package/internal/assets/extend-release.png +0 -0
  53. package/internal/assets/extend-release.svg +0 -83
  54. package/plugins/goalbuddy/skills/goalbuddy/extend/github-projects/README.md +0 -105
  55. package/plugins/goalbuddy/skills/goalbuddy/extend/github-projects/examples/goal-board-sync/state.yaml +0 -63
  56. package/plugins/goalbuddy/skills/goalbuddy/extend/github-projects/extension.yaml +0 -43
  57. package/plugins/goalbuddy/skills/goalbuddy/extend/github-projects/scripts/lib/github-projects.mjs +0 -728
  58. package/plugins/goalbuddy/skills/goalbuddy/extend/github-projects/scripts/lib/goal-state.mjs +0 -362
  59. package/plugins/goalbuddy/skills/goalbuddy/extend/github-projects/scripts/sync-github-project.mjs +0 -193
  60. package/plugins/goalbuddy/skills/goalbuddy/extend/github-projects/test/github-projects.test.mjs +0 -267
  61. package/plugins/goalbuddy/skills/goalbuddy/extend/local-goal-board/extension.yaml +0 -39
  62. /package/goalbuddy/{extend → surfaces}/local-goal-board/assets/goalbuddy-mark.png +0 -0
  63. /package/goalbuddy/{extend → surfaces}/local-goal-board/examples/sample-goal/notes/T001-scout.md +0 -0
  64. /package/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/goal.md +0 -0
  65. /package/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/notes/.gitkeep +0 -0
  66. /package/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/subgoals/T004-board-view/goal.md +0 -0
  67. /package/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/subgoals/T004-board-view/notes/.gitkeep +0 -0
  68. /package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/assets/goalbuddy-mark.png +0 -0
  69. /package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/examples/sample-goal/notes/T001-scout.md +0 -0
  70. /package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/goal.md +0 -0
  71. /package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/notes/.gitkeep +0 -0
  72. /package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/subgoals/T004-board-view/goal.md +0 -0
  73. /package/plugins/goalbuddy/skills/goalbuddy/{extend → surfaces}/local-goal-board/examples/subgoal-parent/subgoals/T004-board-view/notes/.gitkeep +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "goalbuddy",
3
- "version": "0.3.6",
4
- "description": "A /goal operating system for Codex and Claude Code: subgoals, parallel-agent-ready boards, dark mode, receipts, and verification.",
3
+ "version": "0.3.7",
4
+ "description": "A /goal operating loop for Codex and Claude Code: goal oracles, local boards, receipts, and verification.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "goalbuddy": "internal/cli/goal-maker.mjs",
@@ -11,6 +11,7 @@
11
11
  ".agents/plugins/marketplace.json",
12
12
  "README.md",
13
13
  "RELEASE-0.3.5.md",
14
+ "RELEASE-0.3.7.md",
14
15
  "CONTRIBUTING.md",
15
16
  "examples",
16
17
  "plugins/goalbuddy",
@@ -19,7 +20,7 @@
19
20
  "goalbuddy/SKILL.md",
20
21
  "goalbuddy/agents",
21
22
  "goalbuddy/scripts",
22
- "goalbuddy/extend",
23
+ "goalbuddy/surfaces",
23
24
  "goalbuddy/templates"
24
25
  ],
25
26
  "scripts": {
@@ -51,7 +52,6 @@
51
52
  "cli",
52
53
  "workflow",
53
54
  "agent",
54
- "extensions",
55
55
  "verification"
56
56
  ],
57
57
  "author": "tolibear",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "goalbuddy",
3
- "version": "0.3.6",
4
- "description": "Turn broad Claude Code work into verified GoalBuddy boards with subgoals, parallel-agent-ready handoffs, dark mode, and receipts.",
3
+ "version": "0.3.7",
4
+ "description": "Turn broad Codex and Claude Code work into pressured /goal runs with oracles, local boards, receipts, and verification.",
5
5
  "author": {
6
6
  "name": "tolibear",
7
7
  "email": "support@tolibear.com",
@@ -18,7 +18,6 @@
18
18
  "goal",
19
19
  "task-board",
20
20
  "receipts",
21
- "workflow",
22
- "extensions"
21
+ "workflow"
23
22
  ]
24
23
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "goalbuddy",
3
- "version": "0.3.6",
4
- "description": "Turn broad Codex and Claude Code work into verified GoalBuddy boards with subgoals, parallel-agent-ready handoffs, dark mode, and receipts.",
3
+ "version": "0.3.7",
4
+ "description": "Turn broad Codex and Claude Code work into pressured /goal runs with oracles, local boards, receipts, and verification.",
5
5
  "author": {
6
6
  "name": "tolibear",
7
7
  "email": "support@tolibear.com",
@@ -18,14 +18,13 @@
18
18
  "goal",
19
19
  "task-board",
20
20
  "receipts",
21
- "workflow",
22
- "extensions"
21
+ "workflow"
23
22
  ],
24
23
  "skills": "./skills/",
25
24
  "interface": {
26
25
  "displayName": "GoalBuddy",
27
- "shortDescription": "Verified goal boards with subgoals, parallel-agent-ready handoffs, and dark mode",
28
- "longDescription": "GoalBuddy packages a structured goal workflow for broad, long-running, or ambiguous engineering work in Codex or Claude Code. It creates durable goal charters, task boards, optional depth-1 subgoals, visual board surfaces, parallel-agent-ready handoffs, receipts, verification gates, extension handoffs, and compatibility guidance for teams moving from goal-maker.",
26
+ "shortDescription": "Goal oracles, local boards, receipts, and proof loops for /goal",
27
+ "longDescription": "GoalBuddy packages a structured goal workflow for broad, long-running, or ambiguous engineering work in Codex or Claude Code. It creates durable goal charters, goal oracles, task boards, optional depth-1 subgoals, local board surfaces, parallel-agent-ready handoffs, receipts, verification gates, and compatibility guidance for teams moving from goal-maker.",
29
28
  "developerName": "tolibear",
30
29
  "category": "Coding",
31
30
  "capabilities": [
@@ -1,8 +1,8 @@
1
1
  # GoalBuddy Plugin (Codex + Claude Code)
2
2
 
3
- GoalBuddy packages the canonical `goal-prep` skill as a plugin so teams can install the reusable workflow in **Codex** and **Claude Code**, while keeping the npm CLI for local setup, doctor checks, and extension management.
3
+ GoalBuddy packages the canonical `goal-prep` skill as a plugin so teams can install the reusable workflow in **Codex** and **Claude Code**, while keeping the npm CLI for local setup, doctor checks, and the built-in local board surface.
4
4
 
5
- Version 0.3.5 is the Subgoals, Parallel Agents, and Dark Mode release: depth-1 child boards, a shared multi-board local hub, readable dark-mode boards, stricter agent contracts, deterministic prompt rendering, and conservative parallel planning for long-running work.
5
+ Version 0.3.7 is the Goalmaxxed release: goal oracles, largest safe useful slices, built-in local boards, receipt pressure, final-proof gates, and a smaller core without the extension catalog.
6
6
 
7
7
  ## What It Contains
8
8
 
@@ -56,8 +56,9 @@ goalbuddy --target claude # installs for Claude Code only
56
56
  For local CLI testing before npm publish:
57
57
 
58
58
  ```bash
59
- node internal/cli/goal-maker.mjs --catalog-url extend/catalog.json
59
+ node internal/cli/goal-maker.mjs
60
60
  node internal/cli/goal-maker.mjs doctor
61
+ node internal/cli/goal-maker.mjs board docs/goals/<slug> --once --json
61
62
  ```
62
63
 
63
64
  ## Release Notes
@@ -12,9 +12,17 @@ GoalBuddy is for autonomous, long-running Codex or Claude Code work where the PM
12
12
  The loop is:
13
13
 
14
14
  ```text
15
- raw user intent -> intake compiler -> discovery/plan validation/execution board -> one active task -> receipt -> board update -> repeat
15
+ raw user intent -> intake compiler -> goal oracle -> local work surface -> one active task -> receipt -> proof loop -> repeat
16
16
  ```
17
17
 
18
+ GoalBuddy's core invariant is:
19
+
20
+ ```text
21
+ Intent -> Oracle -> Surface -> Loop -> Proof
22
+ ```
23
+
24
+ No oracle, no serious goal. A goal oracle is the observable signal that tells the PM whether the original owner outcome is actually true yet. It may be a test suite, browser walkthrough, demo transcript, generated artifact, benchmark, source-backed answer, release check, or final human decision. Weak proof creates weak goals, so record the oracle before shaping tasks and keep testing against it until final completion.
25
+
18
26
  ## Invocation Boundary
19
27
 
20
28
  There are two different modes:
@@ -31,7 +39,7 @@ Allowed `$goal-prep` actions:
31
39
  - run the bundled GoalBuddy update checker and mention a newer version if one is available;
32
40
  - ask diagnostic intake questions and wait when required;
33
41
  - create or repair only `docs/goals/<slug>/goal.md`, `docs/goals/<slug>/state.yaml`, `docs/goals/<slug>/notes/`, and the generated `.goalbuddy-board/` visual board artifact;
34
- - create and open the selected visual board surface for the goal;
42
+ - create and open the built-in local GoalBuddy board surface for the goal unless the user opts out;
35
43
  - optionally run the GoalBuddy board checker against that `state.yaml`;
36
44
  - verify GoalBuddy agent availability, if this can be done without touching implementation work, and record `installed`, `bundled_not_installed`, `missing`, or `unknown` truthfully;
37
45
  - print exactly `/goal Follow docs/goals/<slug>/goal.md.`;
@@ -69,25 +77,25 @@ Extract:
69
77
  - authority: `requested | approved | inferred | needs_approval | blocked`;
70
78
  - proof type: `test | demo | artifact | metric | review | source_backed_answer | decision`;
71
79
  - completion proof: the observable signal for full outcome completion;
80
+ - goal oracle: the live check, walkthrough, artifact, metric, or decision that will keep pressure on the goal and prevent early completion;
72
81
  - likely misfire: how `/goal` could succeed at the wrong thing;
73
82
  - blind spots: important risks, choices, or success dimensions the user may not have named yet;
74
83
  - existing plan facts: user-provided steps, files, constraints, or sequencing that must be preserved but still validated.
75
84
 
76
- Ask the visual-board question early, before detailed task shaping:
85
+ Use the local GoalBuddy board as the default work surface for broad GoalBuddy runs. Ask only when the user has not already implied they want the default local surface, the goal is unusually quick/private, or board setup would materially distract from the requested prep:
77
86
 
78
87
  ```text
79
- Do you want to set up a visual board for this?
88
+ Do you want the local GoalBuddy board for this goal?
80
89
  ```
81
90
 
82
91
  Recommended options:
83
92
 
84
93
  1. Local live board (Recommended) - starts immediately, requires no credentials, and lets the user watch tasks populate inside Codex or Claude Code.
85
- 2. GitHub Projects - best when stakeholders need a shared external board and the user can approve GitHub credentials/project details.
86
- 3. No visual board - best for quick or private goals where the file board is enough.
94
+ 2. No visual board - best for quick or private goals where the file board is enough.
87
95
 
88
96
  If the user chooses the local live board, create the goal directory, `notes/`, and an initial minimal `state.yaml` as soon as the slug is known, then run `npx goalbuddy board docs/goals/<slug>` and open the printed local URL in the AI coding agent's in-app browser (the Codex in-app Browser, the Claude Code preview, or the user's regular browser). The default local hub is `http://goalbuddy.localhost:41737/`, and board URLs normally look like `http://goalbuddy.localhost:41737/<slug>/`. In short: start the local board before filling the task list so the board pops up right away and cards populate live as `state.yaml` changes. Include the printed board URL in the final prep response as an actual clickable Markdown link, for example `[Open GoalBuddy board](http://goalbuddy.localhost:41737/<slug>/)`. Do not put the board URL only in a code block, quote, HTML comment, or prose that the UI cannot click.
89
97
 
90
- If the user chooses GitHub Projects, ask for approval and the required project target before any live write. Create or sync the GitHub Project at the same early point as the local board: after the goal root and skeleton `state.yaml` exist, before the detailed task list is finished, then sync again as tasks populate. Run a dry-run sync first when possible. Missing GitHub credentials or project details should not block local board creation or goal prep; record the missing requirement in `visual_board.github_projects` and seed a PM setup task.
98
+ If the user wants an external board, GitHub sync, Slack digest, Linear handoff, or any other custom integration, do not install a GoalBuddy catalog item. Treat it as normal implementation work: create a concrete task that designs and verifies that integration inside the target repo or asks the operator for the required credentials and scope.
91
99
 
92
100
  Ask before board creation when the request is vague, strategic, improvement-oriented, or open-ended and the user has not explicitly said to use defaults. Ask one guided question at a time with 2-3 options and a recommended default, then wait. Continue the diagnostic intake until the user's answers are sufficient to choose the board shape. Do not create or repair `docs/goals/<slug>/` until the diagnostic intake is complete or the user explicitly accepts defaults.
93
101
 
@@ -134,7 +142,7 @@ Stop after each question. Do not create files, repair an existing board, run che
134
142
 
135
143
  Minimum diagnostic ladder for vague, strategic, or improvement-oriented goals:
136
144
 
137
- 1. Visual board: ask "Do you want to set up a visual board for this?"
145
+ 1. Goal surface: use the local live board by default, or ask "Do you want the local GoalBuddy board for this goal?" when board handling is unresolved.
138
146
  2. Intent target: what kind of improvement or outcome matters most?
139
147
  3. Success proof: what evidence would convince the user this worked?
140
148
  4. Scope and non-goals: what should remain untouched or explicitly out of scope?
@@ -173,7 +181,7 @@ Do:
173
181
  - classify the goal as `specific`, `open_ended`, `existing_plan`, `recovery`, or `audit`;
174
182
  - create or repair `docs/goals/<slug>/`;
175
183
  - create `goal.md`, `state.yaml`, and `notes/`;
176
- - if requested, start the local visual board immediately and open it in the AI coding agent's in-app browser (Codex in-app Browser, Claude Code preview, or the user's regular browser) before filling the task list;
184
+ - start the local board immediately and open it in the AI coding agent's in-app browser (Codex in-app Browser, Claude Code preview, or the user's regular browser) before filling the task list, unless the user opts out;
177
185
  - seed a role-tagged task board that matches the input shape;
178
186
  - make the first active task safe;
179
187
  - verify Scout, Worker, and Judge agent availability or record an explicit truthful state;
@@ -234,7 +242,7 @@ Use this skill for goals that are broad, multi-hour, ambiguous, high-risk, alrea
234
242
 
235
243
  For a one-change task, do not create a GoalBuddy board.
236
244
 
237
- Scout and Judge tasks may identify optional extension, plugin, publishing, reporting, or channel opportunities as improvement candidates. Treat those as normal board tasks. Extensions are supporting surfaces; `state.yaml` remains board truth.
245
+ Scout and Judge tasks may identify optional publishing, reporting, integration, plugin, or channel opportunities as improvement candidates. Treat those as normal board tasks with concrete implementation plans. `state.yaml` remains board truth.
238
246
 
239
247
  ## The Four Primitives
240
248
 
@@ -274,6 +282,7 @@ The charter answers:
274
282
  What did the user originally ask for?
275
283
  What are we trying to improve?
276
284
  What input shape did the intake identify?
285
+ What is the goal oracle?
277
286
  What constraints are non-negotiable?
278
287
  Is this goal specific, open-ended, existing-plan, recovery, or audit?
279
288
  What likely misfire must the PM avoid?
@@ -53,6 +53,38 @@ function nestedScalar(section, key) {
53
53
  return null;
54
54
  }
55
55
 
56
+ function pathScalar(path, key) {
57
+ const lines = text.split(/\r?\n/);
58
+ let depth = 0;
59
+ for (const line of lines) {
60
+ if (!line.trim()) continue;
61
+ const indent = line.match(/^ */)[0].length;
62
+ if (indent < depth * 2) depth = Math.floor(indent / 2);
63
+
64
+ if (depth < path.length && indent === depth * 2 && new RegExp(`^\\s{${indent}}${path[depth]}:\\s*$`).test(line)) {
65
+ depth += 1;
66
+ continue;
67
+ }
68
+
69
+ if (depth === path.length && indent === depth * 2) {
70
+ const match = line.match(new RegExp(`^\\s{${indent}}${key}:\\s*(.*?)\\s*$`));
71
+ if (match) return clean(match[1]);
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+
77
+ function isWeakProof(value) {
78
+ if (value === null || value === undefined) return true;
79
+ const normalized = String(value).trim().toLowerCase();
80
+ return normalized === ""
81
+ || normalized === "unknown"
82
+ || normalized === "tbd"
83
+ || normalized === "todo"
84
+ || normalized === "none"
85
+ || /^<.*>$/.test(normalized);
86
+ }
87
+
56
88
  function sectionText(section) {
57
89
  const lines = text.split(/\r?\n/);
58
90
  const start = lines.findIndex((line) => new RegExp(`^${section}:\\s*$`).test(line));
@@ -225,6 +257,11 @@ const allowedAgentStatuses = new Set(["installed", "bundled_not_installed", "mis
225
257
  const continuousUntilFullOutcome = nestedScalar("rules", "continuous_until_full_outcome") === true;
226
258
  const missingInputOrCredentialsDoNotStopGoal =
227
259
  nestedScalar("rules", "missing_input_or_credentials_do_not_stop_goal") === true;
260
+ const goalPressureRequiresOracle = nestedScalar("rules", "goal_pressure_requires_oracle") !== false;
261
+ const noCompletionOnWeakProof = nestedScalar("rules", "no_completion_on_weak_proof") !== false;
262
+ const completionProof = pathScalar(["goal", "intake"], "completion_proof");
263
+ const oracleSignal = pathScalar(["goal", "oracle"], "signal");
264
+ const oracleFinalProof = pathScalar(["goal", "oracle"], "final_proof");
228
265
  const legacySignals = [
229
266
  /^gate:\s*$/m,
230
267
  /^artifact_policy:\s*$/m,
@@ -244,6 +281,19 @@ if (!["active", "blocked", "done"].includes(goalStatus)) {
244
281
  errors.push(`goal.status must be active, blocked, or done; got ${goalStatus || "<missing>"}`);
245
282
  }
246
283
 
284
+ if (goalPressureRequiresOracle) {
285
+ if (isWeakProof(oracleSignal)) {
286
+ warnings.push("goal.oracle.signal is missing or placeholder-like; weak oracles make /goal finish too early.");
287
+ }
288
+ if (isWeakProof(oracleFinalProof)) {
289
+ warnings.push("goal.oracle.final_proof is missing or placeholder-like; final completion needs receipt-backed proof.");
290
+ }
291
+ }
292
+
293
+ if (isWeakProof(completionProof)) {
294
+ warnings.push("goal.intake.completion_proof is missing or placeholder-like; record the observable signal that proves the full original outcome.");
295
+ }
296
+
247
297
  function agentStatusWarning(agent, status) {
248
298
  const agentLabel = agent[0].toUpperCase() + agent.slice(1);
249
299
  if (status === "bundled_not_installed") {
@@ -532,6 +582,9 @@ function escapeRegExp(value) {
532
582
  }
533
583
 
534
584
  if (goalStatus === "done") {
585
+ if (noCompletionOnWeakProof && (isWeakProof(completionProof) || isWeakProof(oracleSignal) || isWeakProof(oracleFinalProof))) {
586
+ errors.push("done goals require concrete completion proof, goal.oracle.signal, and goal.oracle.final_proof; weak proof cannot close a goal");
587
+ }
535
588
  const finalAudit = tasks.some((task) => {
536
589
  if (!["judge", "pm"].includes(task.type) || task.status !== "done") return false;
537
590
  if (!task.receipt.present || task.receipt.value === null) return false;
@@ -2,7 +2,7 @@
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { basename, dirname, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { parseGoalStateText } from "../extend/local-goal-board/scripts/lib/goal-board.mjs";
5
+ import { parseGoalStateText } from "../surfaces/local-goal-board/scripts/lib/goal-board.mjs";
6
6
 
7
7
  const ROLE_DEFAULTS = {
8
8
  scout: { agent: "goal_scout", reasoning: "low", sandbox: "read-only" },
@@ -45,6 +45,7 @@ export function renderTaskPrompt(options) {
45
45
  fork_context_allowed: role !== "worker",
46
46
  board_path: board.path,
47
47
  child_board_paths: childBoardPaths(board),
48
+ goal_oracle: board.goal.oracle || null,
48
49
  slice_policy: board.document.rules?.slice_policy || null,
49
50
  warnings,
50
51
  },
@@ -141,6 +142,12 @@ function promptWarnings(board, task) {
141
142
  const warnings = [];
142
143
  const role = normalizeRole(task.type);
143
144
  if (task.id !== board.activeTask) warnings.push(`Task ${task.id} is not the active task on this board.`);
145
+ if (isWeakProof(board.goal.oracle?.signal)) {
146
+ warnings.push("goal.oracle.signal is missing or placeholder-like; keep the goal pressured by a concrete completion oracle.");
147
+ }
148
+ if (isWeakProof(board.goal.oracle?.final_proof)) {
149
+ warnings.push("goal.oracle.final_proof is missing or placeholder-like; do not mark the goal complete without receipt-backed proof.");
150
+ }
144
151
  if (role === "worker") {
145
152
  if (stringList(task.allowed_files).length === 0) warnings.push(`Worker task ${task.id} has no allowed_files.`);
146
153
  if (stringList(task.verify).length === 0) warnings.push(`Worker task ${task.id} has no verify commands.`);
@@ -211,6 +218,17 @@ function isTrue(value) {
211
218
  return value === true || String(value).toLowerCase() === "true";
212
219
  }
213
220
 
221
+ function isWeakProof(value) {
222
+ if (value === null || value === undefined) return true;
223
+ const normalized = String(value).trim().toLowerCase();
224
+ return normalized === ""
225
+ || normalized === "unknown"
226
+ || normalized === "tbd"
227
+ || normalized === "todo"
228
+ || normalized === "none"
229
+ || /^<.*>$/.test(normalized);
230
+ }
231
+
214
232
  function stringList(value) {
215
233
  return Array.isArray(value) ? value.filter((item) => item !== null && item !== undefined).map(String) : [];
216
234
  }
@@ -261,6 +279,9 @@ function formatPrompt(payload) {
261
279
  lines.push("- child_board_paths:");
262
280
  for (const path of payload.metadata.child_board_paths) lines.push(` - ${path}`);
263
281
  }
282
+ if (payload.metadata.goal_oracle) {
283
+ lines.push(`- goal_oracle: ${JSON.stringify(payload.metadata.goal_oracle)}`);
284
+ }
264
285
  if (payload.metadata.slice_policy) {
265
286
  lines.push(`- slice_policy: ${JSON.stringify(payload.metadata.slice_policy)}`);
266
287
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  Generate a small local GoalBuddy board for a goal directory and watch it update live while agents work.
4
4
 
5
- The extension keeps `state.yaml` authoritative. It writes static web app files into the goal directory and serves them from a local-only Node server. The browser subscribes to Server-Sent Events, so cards update as `state.yaml`, `notes/`, or linked depth-1 sub-goal state changes without a manual reload.
5
+ The surface keeps `state.yaml` authoritative. It writes static web app files into the goal directory and serves them from a local-only Node server. The browser subscribes to Server-Sent Events, so cards update as `state.yaml`, `notes/`, or linked depth-1 sub-goal state changes without a manual reload.
6
6
 
7
7
  ## Use When
8
8
 
@@ -14,11 +14,10 @@ The extension keeps `state.yaml` authoritative. It writes static web app files i
14
14
  ## Generate And Serve
15
15
 
16
16
  ```bash
17
- node extend/local-goal-board/scripts/local-goal-board.mjs \
18
- --goal docs/goals/<slug>
17
+ npx goalbuddy board docs/goals/<slug>
19
18
  ```
20
19
 
21
- The generated app includes the bundled `assets/goalbuddy-mark.png`, so the board keeps the GoalBuddy mark after the extension is installed or copied elsewhere.
20
+ The generated app includes the bundled `assets/goalbuddy-mark.png`, so the board keeps the GoalBuddy mark anywhere the package is installed.
22
21
 
23
22
  The command writes:
24
23
 
@@ -34,8 +33,7 @@ Then it starts or reuses the shared local board hub at `http://goalbuddy.localho
34
33
  ## Check Without A Long-Running Server
35
34
 
36
35
  ```bash
37
- node extend/local-goal-board/scripts/local-goal-board.mjs \
38
- --goal docs/goals/<slug> \
36
+ npx goalbuddy board docs/goals/<slug> \
39
37
  --once \
40
38
  --json
41
39
  ```
@@ -63,9 +61,9 @@ Clicking a card opens a detail modal with the task objective, status, assignee,
63
61
  ## Verification
64
62
 
65
63
  ```bash
66
- node --test extend/local-goal-board/test/*.test.mjs
67
- node extend/local-goal-board/scripts/local-goal-board.mjs \
68
- --goal extend/local-goal-board/examples/sample-goal \
64
+ node --test goalbuddy/surfaces/local-goal-board/test/*.test.mjs
65
+ node goalbuddy/surfaces/local-goal-board/scripts/local-goal-board.mjs \
66
+ --goal goalbuddy/surfaces/local-goal-board/examples/sample-goal \
69
67
  --once \
70
68
  --json
71
69
  ```
@@ -1,8 +1,8 @@
1
1
  version: 2
2
2
 
3
3
  goal:
4
- title: "Local Kanban Board Extension"
5
- slug: "local-kanban-board-extension"
4
+ title: "Local Goal Board Surface"
5
+ slug: "local-goal-board-surface"
6
6
  kind: specific
7
7
  tranche: "Demonstrate local GoalBuddy board rendering."
8
8
  status: active
@@ -30,7 +30,7 @@ tasks:
30
30
  type: worker
31
31
  assignee: Worker
32
32
  status: blocked
33
- objective: "Catalog and document the local board extension."
33
+ objective: "Catalog and document the local board surface."
34
34
  receipt:
35
35
  result: blocked
36
36
  summary: "T003 is blocked during the progressive board motion demo."
@@ -78,7 +78,7 @@ tasks:
78
78
  type: scout
79
79
  assignee: Scout
80
80
  status: done
81
- objective: "List the extension launch paths."
81
+ objective: "List the board launch paths."
82
82
  receipt:
83
83
  result: done
84
84
  summary: "T009 completed during the progressive board motion demo."
@@ -118,7 +118,7 @@ tasks:
118
118
  type: worker
119
119
  assignee: Worker
120
120
  status: done
121
- objective: "Prepare final extension packaging check."
121
+ objective: "Prepare final board packaging check."
122
122
  receipt:
123
123
  result: done
124
124
  summary: "T014 completed during the progressive board motion demo."
@@ -31,10 +31,10 @@ tasks:
31
31
  status: active
32
32
  objective: "Build the sub-goal board view."
33
33
  allowed_files:
34
- - goalbuddy/extend/local-goal-board/scripts/lib/goal-board.mjs
35
- - goalbuddy/extend/local-goal-board/test/local-goal-board.test.mjs
34
+ - goalbuddy/surfaces/local-goal-board/scripts/lib/goal-board.mjs
35
+ - goalbuddy/surfaces/local-goal-board/test/local-goal-board.test.mjs
36
36
  verify:
37
- - node --test goalbuddy/extend/local-goal-board/test/local-goal-board.test.mjs
37
+ - node --test goalbuddy/surfaces/local-goal-board/test/local-goal-board.test.mjs
38
38
  stop_if:
39
39
  - "Need files outside allowed_files."
40
40
  subgoal:
@@ -24,16 +24,16 @@ tasks:
24
24
  result: done
25
25
  summary: "Child board payload needs normal columns and task details."
26
26
  evidence:
27
- - goalbuddy/extend/local-goal-board/scripts/lib/goal-board.mjs
27
+ - goalbuddy/surfaces/local-goal-board/scripts/lib/goal-board.mjs
28
28
  - id: T002
29
29
  type: worker
30
30
  assignee: Worker
31
31
  status: active
32
32
  objective: "Render the read-only embedded child board."
33
33
  allowed_files:
34
- - goalbuddy/extend/local-goal-board/scripts/lib/goal-board.mjs
34
+ - goalbuddy/surfaces/local-goal-board/scripts/lib/goal-board.mjs
35
35
  verify:
36
- - node --test goalbuddy/extend/local-goal-board/test/local-goal-board.test.mjs
36
+ - node --test goalbuddy/surfaces/local-goal-board/test/local-goal-board.test.mjs
37
37
  stop_if:
38
38
  - "Need files outside allowed_files."
39
39
  receipt: null
@@ -6,8 +6,8 @@ import { fileURLToPath } from "node:url";
6
6
  const VALID_STATUSES = new Set(["queued", "active", "blocked", "done"]);
7
7
  const COLUMN_ORDER = ["todo", "in-progress", "blocked", "completed"];
8
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
- const extensionRoot = resolve(__dirname, "../..");
10
- const logoAssetPath = join(extensionRoot, "assets", "goalbuddy-mark.png");
9
+ const surfaceRoot = resolve(__dirname, "../..");
10
+ const logoAssetPath = join(surfaceRoot, "assets", "goalbuddy-mark.png");
11
11
 
12
12
  export class GoalBoardError extends Error {
13
13
  constructor(message) {
@@ -527,9 +527,9 @@ function serveStatic(appDir, pathname, response) {
527
527
  return;
528
528
  }
529
529
 
530
- const extension = cleanPath.match(/\.[^.]+$/)?.[0] || "";
530
+ const fileExtension = cleanPath.match(/\.[^.]+$/)?.[0] || "";
531
531
  response.writeHead(200, {
532
- "Content-Type": textTypes[extension] || "application/octet-stream",
532
+ "Content-Type": textTypes[fileExtension] || "application/octet-stream",
533
533
  "Cache-Control": "no-store",
534
534
  });
535
535
  response.end(readFileSync(file));
@@ -580,8 +580,8 @@ function usage() {
580
580
  console.log(`GoalBuddy Local Goal Board
581
581
 
582
582
  Usage:
583
- node extend/local-goal-board/scripts/local-goal-board.mjs --goal docs/goals/<slug>
584
- node extend/local-goal-board/scripts/local-goal-board.mjs --goal docs/goals/<slug> --once --json
583
+ npx goalbuddy board docs/goals/<slug>
584
+ npx goalbuddy board docs/goals/<slug> --once --json
585
585
 
586
586
  Options:
587
587
  --goal <path> Goal directory containing state.yaml.
@@ -8,9 +8,9 @@ import { createBoardPayload, writeBoardApp } from "../scripts/lib/goal-board.mjs
8
8
  import { parseArgs, startBoardServer } from "../scripts/local-goal-board.mjs";
9
9
 
10
10
  test("normalizes a dense goal into local board columns", () => {
11
- const payload = createBoardPayload(resolve("extend/local-goal-board/examples/sample-goal"));
11
+ const payload = createBoardPayload(resolve("goalbuddy/surfaces/local-goal-board/examples/sample-goal"));
12
12
 
13
- assert.equal(payload.goal.title, "Local Kanban Board Extension");
13
+ assert.equal(payload.goal.title, "Local Goal Board Surface");
14
14
  assert.equal(payload.goal.activeTask, "");
15
15
  assert.equal(payload.counts.total, 14);
16
16
  assert.equal(payload.counts.todo, 0);
@@ -24,7 +24,7 @@ test("normalizes a dense goal into local board columns", () => {
24
24
  });
25
25
 
26
26
  test("loads depth-1 subgoal boards into parent task payloads", () => {
27
- const payload = createBoardPayload(resolve("goalbuddy/extend/local-goal-board/examples/subgoal-parent"));
27
+ const payload = createBoardPayload(resolve("goalbuddy/surfaces/local-goal-board/examples/subgoal-parent"));
28
28
  const parentTask = payload.tasks.find((task) => task.id === "T004");
29
29
 
30
30
  assert.equal(parentTask.subgoal.status, "active");
@@ -229,7 +229,7 @@ tasks:
229
229
  });
230
230
 
231
231
  test("writes a minimal GoalBuddy web app into the goal directory", () => {
232
- const appDir = writeBoardApp(resolve("extend/local-goal-board/examples/sample-goal"));
232
+ const appDir = writeBoardApp(resolve("goalbuddy/surfaces/local-goal-board/examples/sample-goal"));
233
233
  const html = readFileSync(join(appDir, "index.html"), "utf8");
234
234
  const css = readFileSync(join(appDir, "styles.css"), "utf8");
235
235
  const js = readFileSync(join(appDir, "app.js"), "utf8");
@@ -393,20 +393,20 @@ test("advertises goalbuddy.localhost while binding to loopback", async () => {
393
393
  test("runs when installed under a symlinked temp path", () => {
394
394
  const root = mkdtempSync(join(tmpdir(), "goalbuddy-local-board-direct-"));
395
395
  try {
396
- cpSync("extend/local-goal-board/scripts", join(root, "scripts"), { recursive: true });
397
- cpSync("extend/local-goal-board/assets", join(root, "assets"), { recursive: true });
396
+ cpSync("goalbuddy/surfaces/local-goal-board/scripts", join(root, "scripts"), { recursive: true });
397
+ cpSync("goalbuddy/surfaces/local-goal-board/assets", join(root, "assets"), { recursive: true });
398
398
 
399
399
  const result = spawnSync(process.execPath, [
400
400
  join(root, "scripts", "local-goal-board.mjs"),
401
401
  "--goal",
402
- resolve("extend/local-goal-board/examples/sample-goal"),
402
+ resolve("goalbuddy/surfaces/local-goal-board/examples/sample-goal"),
403
403
  "--once",
404
404
  "--json",
405
405
  ], { encoding: "utf8" });
406
406
 
407
407
  assert.equal(result.status, 0, result.stderr || result.stdout);
408
408
  const report = JSON.parse(result.stdout);
409
- assert.equal(report.board.goal.title, "Local Kanban Board Extension");
409
+ assert.equal(report.board.goal.title, "Local Goal Board Surface");
410
410
  } finally {
411
411
  rmSync(root, { recursive: true, force: true });
412
412
  }
@@ -15,10 +15,19 @@
15
15
  - Authority: `requested | approved | inferred | needs_approval | blocked`
16
16
  - Proof type: `test | demo | artifact | metric | review | source_backed_answer | decision`
17
17
  - Completion proof: <observable signal that closes the full original outcome>
18
+ - Goal oracle: <live check, walkthrough, artifact, metric, source-backed answer, or decision that keeps pressure on the goal>
18
19
  - Likely misfire: <how GoalBuddy could succeed at the wrong thing>
19
20
  - Blind spots considered: <risks, unstated choices, or success dimensions surfaced during diagnostic intake>
20
21
  - Existing plan facts: <user-provided steps/files/constraints/sequencing to preserve and validate, or none>
21
22
 
23
+ ## Goal Oracle
24
+
25
+ The oracle for this goal is:
26
+
27
+ `<specific observable signal>`
28
+
29
+ The PM must keep comparing task receipts to this oracle. Planning, discovery, a passing tiny slice, or a clean-looking board is not enough. The goal finishes only when a final Judge/PM audit maps receipts and verification back to this oracle and records `full_outcome_complete: true`.
30
+
22
31
  ## Goal Kind
23
32
 
24
33
  `specific | open_ended | existing_plan | recovery | audit`
@@ -9,6 +9,10 @@ goal:
9
9
  kind: open_ended # specific | open_ended | existing_plan | recovery | audit
10
10
  tranche: "<continuous execution: complete successive safe verified slices until the full original outcome is complete>"
11
11
  status: active # active | blocked | done
12
+ oracle:
13
+ signal: "<live check, walkthrough, artifact, metric, source-backed answer, or decision that proves the owner outcome>"
14
+ cadence: "after each Worker package and at final audit"
15
+ final_proof: "<receipt-backed evidence required before full_outcome_complete: true>"
12
16
  intake:
13
17
  original_request: "<shortest faithful user request>"
14
18
  interpreted_outcome: "<one sentence>"
@@ -33,6 +37,8 @@ rules:
33
37
  missing_input_or_credentials_do_not_stop_goal: true
34
38
  preserve_and_validate_existing_plan: true
35
39
  intake_misfire_must_be_audited: true
40
+ goal_pressure_requires_oracle: true
41
+ no_completion_on_weak_proof: true
36
42
  slice_policy:
37
43
  max_consecutive_tiny_tasks: 2
38
44
  prefer_vertical_slices: true
@@ -47,17 +53,12 @@ agents:
47
53
  judge: unknown
48
54
 
49
55
  visual_board:
50
- # none | local | github_projects | both | unknown
56
+ # none | local | unknown
51
57
  selected: unknown
52
58
  local:
53
59
  status: not_requested # not_requested | starting | live | generated | blocked
54
60
  url: null
55
61
  command: "npx goalbuddy board docs/goals/<goal-slug>"
56
- github_projects:
57
- status: not_requested # not_requested | needs_approval | dry_run_ready | synced | blocked
58
- url: null
59
- command: "npx goalbuddy extend github-projects"
60
- missing: []
61
62
 
62
63
  active_task: T001
63
64