@opellen/opengoal 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +400 -0
  3. package/README.ko.md +409 -0
  4. package/README.md +416 -0
  5. package/README.zh-CN.md +436 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +298 -0
  8. package/dist/extend.d.ts +13 -0
  9. package/dist/extend.js +286 -0
  10. package/dist/hook-parser.d.ts +15 -0
  11. package/dist/hook-parser.js +95 -0
  12. package/dist/i18n/index.d.ts +5 -0
  13. package/dist/i18n/index.js +20 -0
  14. package/dist/i18n/messages.d.ts +28 -0
  15. package/dist/i18n/messages.js +49 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.js +4 -0
  18. package/dist/installer.d.ts +30 -0
  19. package/dist/installer.js +165 -0
  20. package/dist/marker.d.ts +11 -0
  21. package/dist/marker.js +25 -0
  22. package/dist/platforms/amazon-q.d.ts +2 -0
  23. package/dist/platforms/amazon-q.js +12 -0
  24. package/dist/platforms/antigravity.d.ts +2 -0
  25. package/dist/platforms/antigravity.js +12 -0
  26. package/dist/platforms/auggie.d.ts +2 -0
  27. package/dist/platforms/auggie.js +15 -0
  28. package/dist/platforms/claude.d.ts +2 -0
  29. package/dist/platforms/claude.js +7 -0
  30. package/dist/platforms/cline.d.ts +2 -0
  31. package/dist/platforms/cline.js +11 -0
  32. package/dist/platforms/codebuddy.d.ts +2 -0
  33. package/dist/platforms/codebuddy.js +16 -0
  34. package/dist/platforms/codex.d.ts +2 -0
  35. package/dist/platforms/codex.js +7 -0
  36. package/dist/platforms/continue.d.ts +2 -0
  37. package/dist/platforms/continue.js +16 -0
  38. package/dist/platforms/costrict.d.ts +2 -0
  39. package/dist/platforms/costrict.js +15 -0
  40. package/dist/platforms/crush.d.ts +2 -0
  41. package/dist/platforms/crush.js +19 -0
  42. package/dist/platforms/cursor.d.ts +2 -0
  43. package/dist/platforms/cursor.js +18 -0
  44. package/dist/platforms/factory.d.ts +2 -0
  45. package/dist/platforms/factory.js +15 -0
  46. package/dist/platforms/gemini.d.ts +2 -0
  47. package/dist/platforms/gemini.js +14 -0
  48. package/dist/platforms/github-copilot.d.ts +2 -0
  49. package/dist/platforms/github-copilot.js +12 -0
  50. package/dist/platforms/iflow.d.ts +2 -0
  51. package/dist/platforms/iflow.js +18 -0
  52. package/dist/platforms/index.d.ts +10 -0
  53. package/dist/platforms/index.js +68 -0
  54. package/dist/platforms/kilocode.d.ts +2 -0
  55. package/dist/platforms/kilocode.js +8 -0
  56. package/dist/platforms/kiro.d.ts +2 -0
  57. package/dist/platforms/kiro.js +12 -0
  58. package/dist/platforms/opencode.d.ts +2 -0
  59. package/dist/platforms/opencode.js +12 -0
  60. package/dist/platforms/pi.d.ts +2 -0
  61. package/dist/platforms/pi.js +12 -0
  62. package/dist/platforms/qoder.d.ts +2 -0
  63. package/dist/platforms/qoder.js +19 -0
  64. package/dist/platforms/qwen.d.ts +2 -0
  65. package/dist/platforms/qwen.js +14 -0
  66. package/dist/platforms/roocode.d.ts +2 -0
  67. package/dist/platforms/roocode.js +11 -0
  68. package/dist/platforms/toml.d.ts +9 -0
  69. package/dist/platforms/toml.js +18 -0
  70. package/dist/platforms/trae.d.ts +2 -0
  71. package/dist/platforms/trae.js +11 -0
  72. package/dist/platforms/types.d.ts +19 -0
  73. package/dist/platforms/types.js +1 -0
  74. package/dist/platforms/windsurf.d.ts +2 -0
  75. package/dist/platforms/windsurf.js +19 -0
  76. package/dist/platforms/yaml.d.ts +10 -0
  77. package/dist/platforms/yaml.js +30 -0
  78. package/dist/prompts/platform-select.d.ts +1 -0
  79. package/dist/prompts/platform-select.js +174 -0
  80. package/dist/skills/generate.d.ts +13 -0
  81. package/dist/skills/generate.js +16 -0
  82. package/dist/templates.d.ts +20 -0
  83. package/dist/templates.js +98 -0
  84. package/dist/ui/ascii-logo.d.ts +6 -0
  85. package/dist/ui/ascii-logo.js +45 -0
  86. package/dist/ui/colors.d.ts +6 -0
  87. package/dist/ui/colors.js +17 -0
  88. package/dist/ui/welcome.d.ts +1 -0
  89. package/dist/ui/welcome.js +77 -0
  90. package/package.json +51 -0
  91. package/templates/commands/context.md +92 -0
  92. package/templates/commands/design.md +113 -0
  93. package/templates/commands/go.md +84 -0
  94. package/templates/commands/goal.md +360 -0
  95. package/templates/commands/overview.md +78 -0
  96. package/templates/commands/recap.md +77 -0
  97. package/templates/commands/roadmap.md +99 -0
  98. package/templates/commands/scout.md +89 -0
  99. package/templates/commands/verify.md +140 -0
  100. package/templates/skills/opengoal-flow/SKILL.md +169 -0
  101. package/templates/skills/opengoal-subagent/SKILL.md +159 -0
@@ -0,0 +1,20 @@
1
+ import { type PlatformAdapter, type CommandMeta } from "./platforms/index.js";
2
+ export declare const DEFAULT_PREFIX = "opgl";
3
+ export interface OpenGoalConfig {
4
+ tools: string[];
5
+ subagent: boolean;
6
+ root: string;
7
+ docsDir: string;
8
+ codebaseDir: string;
9
+ prefix: string;
10
+ force?: boolean;
11
+ }
12
+ export interface TemplateEntry {
13
+ src: string;
14
+ dst: string;
15
+ adapter: PlatformAdapter;
16
+ meta: CommandMeta;
17
+ rawContent: string;
18
+ }
19
+ export declare function resolveTemplates(config: OpenGoalConfig): TemplateEntry[];
20
+ export declare function renderFile(entry: TemplateEntry, config: OpenGoalConfig): string;
@@ -0,0 +1,98 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { renderTemplate } from "./marker.js";
5
+ import { getAdapters } from "./platforms/index.js";
6
+ import { skillInstallPath, formatSkill } from "./skills/generate.js";
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const TEMPLATE_DIR = join(__dirname, "..", "templates");
9
+ // Installed CLI version — injected into skill metadata.generatedBy.
10
+ // Read once at module load from the shipped package.json.
11
+ const OPENGOAL_VERSION = (() => {
12
+ try {
13
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
14
+ return String(pkg.version ?? "0.0.0");
15
+ }
16
+ catch {
17
+ return "0.0.0";
18
+ }
19
+ })();
20
+ export const DEFAULT_PREFIX = "opgl";
21
+ const COMMAND_TEMPLATES = [
22
+ "scout", "goal", "context", "design",
23
+ "roadmap", "verify", "recap", "overview", "go",
24
+ ];
25
+ const SKILL_TEMPLATES = [
26
+ { src: "skills/opengoal-subagent/SKILL.md", skillName: "opengoal-subagent" },
27
+ { src: "skills/opengoal-flow/SKILL.md", skillName: "opengoal-flow" },
28
+ ];
29
+ function parseMeta(content) {
30
+ const normalized = content.replace(/\r\n/g, "\n");
31
+ const fmMatch = normalized.match(/^---\n([\s\S]*?)\n---/);
32
+ if (!fmMatch)
33
+ return { name: "", description: "" };
34
+ const fm = fmMatch[1];
35
+ const nameMatch = fm.match(/name:\s*"?(?:[\w-]+:)?([\w-]+)"?/);
36
+ const descMatch = fm.match(/description:\s*"([^"]+)"/);
37
+ const categoryMatch = fm.match(/category:\s*(\S+)/);
38
+ const tagsMatch = fm.match(/tags:\s*\[([^\]]*)\]/);
39
+ const tags = tagsMatch
40
+ ? tagsMatch[1]
41
+ .split(",")
42
+ .map((s) => s.trim().replace(/^["']|["']$/g, ""))
43
+ .filter(Boolean)
44
+ : undefined;
45
+ return {
46
+ name: nameMatch?.[1] ?? "",
47
+ description: descMatch?.[1] ?? "",
48
+ category: categoryMatch?.[1],
49
+ tags,
50
+ };
51
+ }
52
+ export function resolveTemplates(config) {
53
+ const adapters = getAdapters(config.tools);
54
+ const entries = [];
55
+ const commandMetas = COMMAND_TEMPLATES.map((cmd) => {
56
+ const src = `commands/${cmd}.md`;
57
+ const rawContent = readFileSync(join(TEMPLATE_DIR, src), "utf-8");
58
+ return { cmd, src, rawContent, meta: parseMeta(rawContent) };
59
+ });
60
+ const skillContents = SKILL_TEMPLATES.map((skill) => ({
61
+ ...skill,
62
+ rawContent: readFileSync(join(TEMPLATE_DIR, skill.src), "utf-8"),
63
+ }));
64
+ for (const adapter of adapters) {
65
+ if (adapter.supportsCommands !== false) {
66
+ for (const { cmd, src, rawContent, meta } of commandMetas) {
67
+ entries.push({ src, dst: adapter.commandPath(cmd, config.prefix), adapter, meta, rawContent });
68
+ }
69
+ }
70
+ for (const skill of skillContents) {
71
+ entries.push({
72
+ src: skill.src,
73
+ dst: skillInstallPath(adapter, skill.skillName),
74
+ adapter,
75
+ meta: { name: skill.skillName, description: "" },
76
+ rawContent: skill.rawContent,
77
+ });
78
+ }
79
+ }
80
+ return entries;
81
+ }
82
+ export function renderFile(entry, config) {
83
+ const content = entry.rawContent.replace(/\r\n/g, "\n");
84
+ const rendered = renderTemplate(content, {
85
+ conditions: {
86
+ subagent: config.subagent,
87
+ },
88
+ });
89
+ const substituted = rendered
90
+ .replace(/\$DocsDir/g, config.docsDir)
91
+ .replace(/\$CodebaseDir/g, config.codebaseDir)
92
+ .replace(/\$OpenGoalVersion/g, OPENGOAL_VERSION)
93
+ .replace(/\$CommandPrefix/g, config.prefix);
94
+ if (entry.src.startsWith("skills/")) {
95
+ return formatSkill(substituted);
96
+ }
97
+ return entry.adapter.formatCommand(substituted, entry.meta, config.prefix);
98
+ }
@@ -0,0 +1,6 @@
1
+ export declare const OPENGOAL_LOGO: {
2
+ readonly frame: readonly [" ▄▄▄▄▄▄▄▄▄▄▄▄ ", " ██ ██ ", " ██ ██ ", " ██ ", " ██ ", " ██ ", " ██ ██ ", " ██ ██ ", " ▀▀▀▀▀▀▀▀▀▀▀▀ "];
3
+ readonly inner: readonly [" ", " ", " ", " ░▒▒▒▒░ ", " ▒▒██▒▒ ", " ░▒▒▒▒░ ", " ", " ", " "];
4
+ };
5
+ export declare const OPENGOAL_LOGO_WIDTH: number;
6
+ export declare const OPENGOAL_LOGO_HEIGHT: 9;
@@ -0,0 +1,45 @@
1
+ // The OpenGoal mark in text: an open frame with the current goal inside it.
2
+ //
3
+ // Two-layer logo. Layers are overlaid at render time: any non-space char in
4
+ // `inner` wins over `frame`. This lets the same block char carry a different
5
+ // color depending on which layer it belongs to, without a parallel mask array
6
+ // to keep in sync — `frame` renders in the muted structural tone, `inner` in
7
+ // goal orange (§50: structure stays quiet, the present gets the color).
8
+ //
9
+ // Palette: █ (full), ▓ (dark), ▒ (medium), ░ (light) — shade blocks give a
10
+ // pseudo-anti-aliased gradient that renders uniformly across monospace fonts.
11
+ // The focus point is a blob shaded radially in four rings — █ core, ▓, ▒,
12
+ // then ░ at the corners. All three rows share one width: the cross-arm
13
+ // illusion comes from rows of different lengths, not from dark centres, so
14
+ // equal widths allow a real ring gradient. Density under a single orange.
15
+ //
16
+ // Geometry: 16x9 cells (a terminal cell is roughly twice as tall as it is
17
+ // wide, so the frame reads near-square). The right side stays open across
18
+ // 3 of 9 rows; the top and bottom bars are half-blocks (▄/▀) inset by one
19
+ // column, which both thickens the stroke and stair-steps the corners.
20
+ export const OPENGOAL_LOGO = {
21
+ frame: [
22
+ " ▄▄▄▄▄▄▄▄▄▄▄▄ ",
23
+ " ██ ██ ",
24
+ " ██ ██ ",
25
+ " ██ ",
26
+ " ██ ",
27
+ " ██ ",
28
+ " ██ ██ ",
29
+ " ██ ██ ",
30
+ " ▀▀▀▀▀▀▀▀▀▀▀▀ ",
31
+ ],
32
+ inner: [
33
+ " ",
34
+ " ",
35
+ " ",
36
+ " ░▒▒▒▒░ ",
37
+ " ▒▒██▒▒ ",
38
+ " ░▒▒▒▒░ ",
39
+ " ",
40
+ " ",
41
+ " ",
42
+ ],
43
+ };
44
+ export const OPENGOAL_LOGO_WIDTH = OPENGOAL_LOGO.frame[0].length;
45
+ export const OPENGOAL_LOGO_HEIGHT = OPENGOAL_LOGO.frame.length;
@@ -0,0 +1,6 @@
1
+ /** --og-ink-muted — the open frame, and anything structural. */
2
+ export declare const structure: import("chalk").ChalkInstance;
3
+ /** --og-goal — the current goal, and the one action worth taking now (§13). */
4
+ export declare const goal: import("chalk").ChalkInstance;
5
+ /** Terminal foreground, so the wordmark is legible on any background. */
6
+ export declare const title: import("chalk").ChalkInstance;
@@ -0,0 +1,17 @@
1
+ import chalk from "chalk";
2
+ // Palette tokens from docs/design/visual-design-guide.md §11.
3
+ //
4
+ // A terminal's background is unknown at runtime, so the guide's --og-ink
5
+ // (#20211F) and --og-canvas (#F7F6F2) cannot be used directly — either one
6
+ // disappears against half the terminals in use. The frame therefore takes
7
+ // --og-ink-muted, the one neutral that holds contrast on light and dark
8
+ // surfaces alike, and the title falls back to the terminal's own foreground.
9
+ //
10
+ // This preserves the rule that matters (§50): structure stays quiet, the
11
+ // present gets the color.
12
+ /** --og-ink-muted — the open frame, and anything structural. */
13
+ export const structure = chalk.hex("#6B6B66");
14
+ /** --og-goal — the current goal, and the one action worth taking now (§13). */
15
+ export const goal = chalk.hex("#F45A3A");
16
+ /** Terminal foreground, so the wordmark is legible on any background. */
17
+ export const title = chalk.bold;
@@ -0,0 +1 @@
1
+ export declare function showWelcome(): Promise<void>;
@@ -0,0 +1,77 @@
1
+ import chalk from "chalk";
2
+ import { OPENGOAL_LOGO, OPENGOAL_LOGO_HEIGHT, OPENGOAL_LOGO_WIDTH } from "./ascii-logo.js";
3
+ import { t } from "../i18n/index.js";
4
+ import { structure, goal, title } from "./colors.js";
5
+ export async function showWelcome() {
6
+ if (!process.stdin.isTTY)
7
+ return;
8
+ const cols = process.stdout.columns ?? 80;
9
+ const compact = cols < 60;
10
+ const lines = buildScreen(compact);
11
+ process.stdout.write("\n" + lines.join("\n") + "\n\n");
12
+ await waitForEnter();
13
+ }
14
+ function buildScreen(compact) {
15
+ const rightLines = [
16
+ title("OpenGoal"),
17
+ chalk.dim(t("welcome.tagline")),
18
+ "",
19
+ chalk.dim(t("welcome.setsUp")),
20
+ " " + chalk.dim("•") + " " + t("welcome.skills"),
21
+ " " + chalk.dim("•") + " " + t("welcome.commands"),
22
+ "",
23
+ goal(t("welcome.pressEnter")),
24
+ ];
25
+ if (compact) {
26
+ return rightLines;
27
+ }
28
+ const gap = " ";
29
+ const totalRows = Math.max(OPENGOAL_LOGO_HEIGHT, rightLines.length);
30
+ const result = [];
31
+ for (let i = 0; i < totalRows; i++) {
32
+ const logo = i < OPENGOAL_LOGO_HEIGHT ? colorLogoRow(i) : " ".repeat(OPENGOAL_LOGO_WIDTH);
33
+ const text = i < rightLines.length ? rightLines[i] : "";
34
+ result.push(logo + gap + text);
35
+ }
36
+ return result;
37
+ }
38
+ function colorLogoRow(row) {
39
+ const frame = OPENGOAL_LOGO.frame[row];
40
+ const inner = OPENGOAL_LOGO.inner[row];
41
+ let result = "";
42
+ for (let j = 0; j < OPENGOAL_LOGO_WIDTH; j++) {
43
+ const innerCh = inner[j];
44
+ if (innerCh !== " ") {
45
+ result += goal(innerCh);
46
+ continue;
47
+ }
48
+ const frameCh = frame[j];
49
+ result += frameCh === " " ? " " : structure(frameCh);
50
+ }
51
+ return result;
52
+ }
53
+ function waitForEnter() {
54
+ return new Promise((resolve) => {
55
+ const { stdin } = process;
56
+ const wasRaw = stdin.isRaw ?? false;
57
+ stdin.setRawMode(true);
58
+ stdin.resume();
59
+ const onData = (buf) => {
60
+ const key = buf[0];
61
+ if (key === 0x0d || key === 0x0a) {
62
+ cleanup();
63
+ resolve();
64
+ }
65
+ else if (key === 0x03) {
66
+ cleanup();
67
+ process.exit(0);
68
+ }
69
+ };
70
+ const cleanup = () => {
71
+ stdin.removeListener("data", onData);
72
+ stdin.setRawMode(wasRaw);
73
+ stdin.pause();
74
+ };
75
+ stdin.on("data", onData);
76
+ });
77
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@opellen/opengoal",
3
+ "version": "1.0.0",
4
+ "description": "Goal-centric AI harness. Open structure, clear present.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "San",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/opellen/opengoal.git"
11
+ },
12
+ "homepage": "https://github.com/opellen/opengoal#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/opellen/opengoal/issues"
15
+ },
16
+ "keywords": [
17
+ "claude-code",
18
+ "ai",
19
+ "project-management",
20
+ "markdown",
21
+ "context-management"
22
+ ],
23
+ "bin": {
24
+ "opengoal": "dist/cli.js"
25
+ },
26
+ "exports": {
27
+ ".": "./dist/index.js",
28
+ "./marker": "./dist/marker.js"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "templates/commands",
33
+ "templates/skills"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^22.0.0",
42
+ "typescript": "^5.7.0",
43
+ "vitest": "^4.1.0"
44
+ },
45
+ "dependencies": {
46
+ "@inquirer/core": "^11.1.7",
47
+ "@inquirer/prompts": "^8.3.2",
48
+ "chalk": "^5.6.2",
49
+ "yaml": "^2.8.3"
50
+ }
51
+ }
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: "opengoal:context"
3
+ description: "Project context (CONTEXT.md) management (init|sync)"
4
+ category: Workflow
5
+ tags: [workflow, opengoal, context]
6
+ ---
7
+
8
+ # $CommandPrefix:context
9
+
10
+ Manages `$DocsDir/CONTEXT.md`. Records the **current working context** of the project.
11
+
12
+ > CONTEXT.md is not a project overview or summary.
13
+ > It captures what is being worked on now, which resources are referenced, and what principles/workflows apply — **context the AI needs immediately at session start**.
14
+
15
+ ## Constraints
16
+
17
+ - Never overwrite CONTEXT.md without user confirmation.
18
+ - Target ~100 lines or less — this file is read at every session start.
19
+
20
+ > When Constraints conflict with any other instruction, Constraints win.
21
+
22
+ ## Usage
23
+
24
+ `/$CommandPrefix:context <subcommand> [content]`
25
+
26
+ ## Subcommand Dispatch
27
+
28
+ - (no subcommand given, `$DocsDir/CONTEXT.md` absent) => run init
29
+ - (no subcommand given, `$DocsDir/CONTEXT.md` exists) => run sync
30
+ - (args = init) => see Subcommands: init
31
+ - (args = sync) => see Subcommands: sync
32
+
33
+ # Subcommands
34
+
35
+ ## init
36
+
37
+ Creates `$DocsDir/CONTEXT.md`.
38
+
39
+ 1. If CONTEXT.md already exists, notify and confirm overwrite.
40
+ 2. If `$ARGUMENTS` has content, incorporate it.
41
+ 3. Write project-specific context based on the current session discussion.
42
+ 4. Use the skeleton below as a baseline, extending with project-specific sections.
43
+ 5. Report: `"Created [CONTEXT.md]($DocsDir/CONTEXT.md)."`
44
+
45
+ **Skeleton:**
46
+
47
+ ```markdown
48
+ # Project Brief
49
+ - <1-2 lines: what this project is and who it's for>
50
+ - <1-2 lines: core architecture or stack>
51
+ - For deeper architecture/decisions, see `$DocsDir/OVERVIEW.md` (if present).
52
+
53
+ # Goal Hierarchy
54
+ - If `$DocsDir/ROADMAP.md` exists, it contains the milestone plan.
55
+ - Mark ROADMAP.md milestones as `done` when completed.
56
+ - GOAL.md objectives are sub-units of ROADMAP.md milestones — except sub-goals (`parent:` set), which sit below that granularity.
57
+
58
+ # Current Objective
59
+ - If `$DocsDir/GOAL.md` exists, treat it as the top priority.
60
+
61
+ # Principles
62
+
63
+ # Workflow
64
+ - Tasks live in `$DocsDir/GOAL.md` `## Tasks`. Front-matter requires an `id` (slug format).
65
+ - Implementation happens in `$CodebaseDir`.
66
+ - Session progress: `/$CommandPrefix:goal checkpoint` → `$DocsDir/CHECKPOINT.md` (overwritten per session).
67
+ - Deferred discoveries: out-of-scope findings go to `$DocsDir/BACKLOG.md` (persistent parking lot).
68
+ - Work larger than a task, subordinate to the current goal, needed now, and not blocking it: `/$CommandPrefix:goal subgoal init` (the parent resumes automatically on completion; a *blocking* discovery is a blocker, not a sub-goal).
69
+ ```
70
+
71
+ **Project-specific sections** — extend the skeleton with sections appropriate to the project:
72
+
73
+ - **Resources**: Key file/directory paths and their descriptions
74
+ - **Process**: Project-specific procedures (e.g., porting rules, analysis doc management)
75
+ - **Index/Tables**: Frequently referenced item lists (e.g., analysis topics, API endpoints)
76
+ - **Extended Principles**: Project-specific principles (e.g., 1:1 logic preservation, no magic numbers)
77
+
78
+ ## sync
79
+
80
+ Reviews current CONTEXT.md and **proposes updates**.
81
+
82
+ 1. Read `$DocsDir/CONTEXT.md`. If absent, suggest init.
83
+ 2. If `$ARGUMENTS` has content, use it as update direction.
84
+ 3. Identify changes from the current session discussion that should be reflected.
85
+ 4. Present changes in **diff format**:
86
+ - Content to add
87
+ - Content to modify
88
+ - Outdated content to remove/update
89
+ 5. Apply the changes.
90
+ 6. Report: `"Updated [CONTEXT.md]($DocsDir/CONTEXT.md)."`
91
+
92
+ > When Constraints conflict with any other instruction, Constraints win.
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: "opengoal:design"
3
+ description: "Implementation design (DESIGN.md) management (init|sync|archive)"
4
+ category: Workflow
5
+ tags: [workflow, opengoal, design]
6
+ ---
7
+
8
+ # $CommandPrefix:design
9
+
10
+ Manages `$DocsDir/DESIGN.md`. Records the **implementation design** for the current GOAL.
11
+
12
+ > If GOAL.md is "what/why", DESIGN.md is "how".
13
+ > Documents implementation plans, file change lists, key design decisions — implementation details that would be lost if only in chat.
14
+ > DESIGN.md is an *implementation* design doc — architecture decisions, module boundaries, file map. It is never a visual/UI design document; UI-related goals still get an implementation design here.
15
+
16
+ ## Constraints
17
+
18
+ - Never overwrite DESIGN.md without user confirmation.
19
+ - DESIGN.md requires a corresponding GOAL.md — do not create without one.
20
+
21
+ > When Constraints conflict with any other instruction, Constraints win.
22
+
23
+ ## Lifecycle
24
+
25
+ DESIGN.md is paired 1:1 with GOAL.md:
26
+ - Created after GOAL.md when an implementation plan emerges
27
+ - Archived together with GOAL.md
28
+
29
+ ## Usage
30
+
31
+ `/$CommandPrefix:design <subcommand> [content]`
32
+
33
+ ## Subcommand Dispatch
34
+
35
+ - (no subcommand given, `$DocsDir/DESIGN.md` absent) => run init
36
+ - (no subcommand given, `$DocsDir/DESIGN.md` exists) => run sync
37
+ - (args = init) => see Subcommands: init
38
+ - (args = sync) => see Subcommands: sync
39
+ - (args = archive) => see Subcommands: archive
40
+
41
+ # Subcommands
42
+
43
+ ## init
44
+
45
+ Creates `$DocsDir/DESIGN.md`.
46
+
47
+ 1. Read `$DocsDir/GOAL.md`. A file read error means the file does not exist — **do NOT retry failed reads.** If absent, suggest setting a goal first.
48
+ 2. Parse GOAL.md `id` and `goal` for context.
49
+ - If GOAL.md has sub-tasks (from breakdown), note them as context for structuring the Execution Order.
50
+ 3. If DESIGN.md already exists, notify the user and confirm overwrite — before anything is written.
51
+ 4. If `$ARGUMENTS` has content, incorporate it.
52
+ 5. Write based on the implementation plan discussed in the current session.
53
+ 6. Report: `"Created [DESIGN.md]($DocsDir/DESIGN.md)."`
54
+ - (GOAL.md has breakdown sub-tasks AND Execution Order structure differs significantly) => also notify: `"Execution Order differs from GOAL.md sub-task structure. Run /$CommandPrefix:goal breakdown to adjust if needed."`
55
+
56
+ **Structure:**
57
+
58
+ ```markdown
59
+ ---
60
+ goal-id: <GOAL.md id>
61
+ created: YYYY-MM-DD
62
+ ---
63
+
64
+ # Implementation Plan
65
+
66
+ ## Files to Change
67
+
68
+ | File | Change | Description |
69
+ |------|--------|-------------|
70
+ | ... | new/modify | ... |
71
+
72
+ ## Key Design Decisions
73
+
74
+ ### 1. <Component/Module>
75
+ - Design decision and rationale
76
+
77
+ ## Execution Order
78
+ 1. ...
79
+ 2. ...
80
+ ```
81
+
82
+ Extend with project-appropriate sections.
83
+
84
+ ## sync
85
+
86
+ Reviews current DESIGN.md and **proposes updates**.
87
+
88
+ 1. Read `$DocsDir/DESIGN.md`. If absent, suggest init.
89
+ 2. If `$ARGUMENTS` has content, use it as update direction.
90
+ 3. Identify changes from the current session:
91
+ - New design decisions
92
+ - Updated file change list
93
+ - Modified execution order
94
+ - Design changes from trial-and-error
95
+ 4. Present changes in **diff format**.
96
+ 5. Apply the changes.
97
+ 6. Report: `"Updated [DESIGN.md]($DocsDir/DESIGN.md)."`
98
+
99
+ ## archive
100
+
101
+ Archives DESIGN.md.
102
+
103
+ 1. Parse `goal-id` from `$DocsDir/DESIGN.md` front-matter.
104
+ 2. Move to `$DocsDir/archive/goals/YYYY-MM-DD-<goal-id>/DESIGN.md`.
105
+ - (directory exists, holds no GOAL.md, no DESIGN.md, and no resident file carries a `goal-id` differing from this DESIGN's `goal-id`) => write into it — this goal's own partial archive, not a collision (same key `goal archive` uses)
106
+ - (directory exists, holds no GOAL.md, its DESIGN.md carries **this** `goal-id`) => this design is already archived here — report it, and replace only on explicit user confirmation, never silently. This branch wins over the foreign-resident branch below; mention any foreign resident in the report.
107
+ - (directory exists, holds no GOAL.md, but a resident file carries a `goal-id` differing from this DESIGN's `goal-id`) => another goal's partial archive — append `-<N>`, re-applying this same test to the suffixed candidate; never overwrite
108
+ - (directory exists with a GOAL.md — a completed archive of an earlier same-slug goal) => append `-<N>` (e.g., `YYYY-MM-DD-<goal-id>-2/`), re-applying this same test to the suffixed candidate
109
+ 3. Report: `"Archived to [$DocsDir/archive/goals/YYYY-MM-DD-<goal-id>/DESIGN.md]($DocsDir/archive/goals/YYYY-MM-DD-<goal-id>/DESIGN.md)."`
110
+
111
+ > **Note**: `/$CommandPrefix:goal archive` automatically archives DESIGN.md together with GOAL.md.
112
+
113
+ > When Constraints conflict with any other instruction, Constraints win.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: "opengoal:go"
3
+ description: "Execute the next task in GOAL.md"
4
+ category: Workflow
5
+ tags: [workflow, opengoal, go]
6
+ ---
7
+
8
+ # $CommandPrefix:go
9
+
10
+ ## Constraints
11
+
12
+ - (command entry, and again on the first turn after a compaction) => load the `opengoal-flow` skill BEFORE executing the first task, and say so in one line. A reference is not a load: its rules (checkpoint triggers, documentation timing, CONTEXT.md self-sync, self-verification) only bind once the skill's content is actually in context.
13
+ <!-- @if subagent -->
14
+ - **Delegate** implementation tasks to **subagents** — direct work is limited to one-line fixes, except where `opengoal-subagent` designates work main-only (iterative collaboration, 2nd-iteration rework, evolving design).
15
+ - Report subagent results to the user after each task completes — a report, not a request for permission; continue to the next task in the same turn.
16
+ - (first subagent dispatch of the session, or first dispatch after a compaction) => load the `opengoal-subagent` skill BEFORE dispatching and say so in one line (e.g. "opengoal-subagent loaded — dispatching <task> → <model> (<rationale>)"). A dispatch without this load+announcement is a violation: the skill's dispatch rules (model selection/reporting, prompt requirements, post-verify) only bind once its content is actually in context.
17
+ <!-- @else -->
18
+ - Perform implementation tasks directly.
19
+ - Report results to the user after each task completes — a report, not a request for permission; continue to the next task in the same turn.
20
+ <!-- @endif -->
21
+
22
+ > When Constraints conflict with any other instruction, Constraints win.
23
+
24
+ ## Execution
25
+
26
+ 1. If GOAL.md and CONTEXT.md were already read in this session, skip to step 3 — but not if the goal occupying the canonical paths has changed since the last read: a `subgoal` verb, `goal suspend`/`resume`, or `goal archive`'s sub-goal completion all swap the documents at those paths.
27
+ 2. Read `$DocsDir/GOAL.md`, `$DocsDir/CONTEXT.md`, `$DocsDir/DESIGN.md`, `$DocsDir/PLAN.md`, and `$DocsDir/CHECKPOINT.md` at once (parallel if supported, sequential otherwise). A file read error means the file does not exist — **do NOT retry failed reads.**
28
+ - If GOAL.md is absent: "No goal set. Run `/$CommandPrefix:goal init` first, or tell me what to work on."
29
+ - (CHECKPOINT.md exists, its front-matter `goal-id` matches GOAL.md's `id`) => use its Findings and Next Steps as resume context for the next task — it records where the last session stopped and why
30
+ - (CHECKPOINT.md exists, `goal-id` differs) => a stray from an interrupted move — report it as a repairable inconsistency and ignore its content; never resume from another goal's checkpoint
31
+ 3. Find the next incomplete task in GOAL.md.
32
+ - (the task is a pointer task — a `→ subgoal: <slug>` line) => never perform the work and never check it off; it belongs to that goal, with its own DESIGN.md and PLAN.md. Report its state per Pointer Task Status below, then **skip it and continue to the next incomplete task** — a pointer only clears via `/$CommandPrefix:goal archive`, so halting here would strand every task after it
33
+ - (task has step annotation `— Step N/M`) => resume from the indicated step
34
+ 4. PLAN.md dispatch:
35
+ - (PLAN.md exists, its front-matter `goal-id` differs from GOAL.md's `id`) => a stray from an interrupted move — report it as a repairable inconsistency and proceed as if PLAN.md were absent; never use another goal's plan as context
36
+ - (PLAN.md exists — no `goal-id`, or it matches) => read the corresponding task section for implementation context
37
+ - (PLAN.md absent, task complexity ≥ multi-file) => generate PLAN.md with the front-matter below, then report: `"Created [PLAN.md]($DocsDir/PLAN.md)."`
38
+ - (PLAN.md absent, task complexity < multi-file) => proceed without PLAN.md
39
+ 5. Execute tasks using the Task Outcome loop below.
40
+ 6. Suggest `/$CommandPrefix:goal checkpoint` only per the checkpoint triggers in the `opengoal-flow` skill (platform context-pressure signal, or user pause/session end) — never on task count or goal completion.
41
+
42
+ PLAN.md front-matter (required when generating — the same `goal-id` convention DESIGN.md and CHECKPOINT.md carry, and what lets `scout`/`goal archive` tell a stray PLAN.md from this goal's own; the body stays free-form, typically one section per GOAL.md task):
43
+ ```yaml
44
+ ---
45
+ goal-id: <GOAL.md id>
46
+ created: YYYY-MM-DD
47
+ ---
48
+ ```
49
+
50
+ ### Pointer Task Status
51
+
52
+ `go` reads only the canonical paths, so it does not know a pointer's state until it resolves the slug. Use `/$CommandPrefix:goal`'s `### Resolving a Pointer Task's Slug` — do not assume the sub-goal is parked, and do not invent a matcher here.
53
+
54
+ - (parked) => name it and note `/$CommandPrefix:goal subgoal switch <slug>` works it
55
+ - (archived) => report that it completed with the pointer left unchecked; nothing is blocked — bare `/$CommandPrefix:goal subgoal` offers the check-off
56
+ - (dangling) => report it as a repairable interrupted `subgoal init`, and point at `/$CommandPrefix:goal subgoal`
57
+
58
+ ## Task Outcome
59
+
60
+ loop until (every task is complete or a pointer task OR user pause):
61
+ - (task complete, task has no Steps annotation) => mark task done in GOAL.md, update PLAN.md if implementation approach changed, then continue to the next incomplete task in the same turn
62
+ - (task complete, task had Steps) => mark task done AND remove its step progress annotation; update PLAN.md if implementation approach changed; continue to the next incomplete task in the same turn
63
+ - (a step completed, more steps remain — the task itself is not complete) => update GOAL.md task with step progress: `— Step N/M (status)`; do not mark the task done
64
+ - (blocked) => report issue and ask user how to proceed
65
+ - (all tasks complete) => suggest `/$CommandPrefix:goal archive` once; do not repeat if user does not act on it
66
+ - (every remaining incomplete task is a pointer task, at least one parked) => stop; report each per Pointer Task Status and suggest `/$CommandPrefix:goal subgoal switch <slug>` for the first parked one — only `/$CommandPrefix:goal archive` on that sub-goal clears its pointer
67
+ - (every remaining incomplete task is a pointer task, none parked) => stop; report each per Pointer Task Status and suggest `/$CommandPrefix:goal archive` — it succeeds in this state; nothing is blocked, and bare `/$CommandPrefix:goal subgoal` offers an archived pointer's check-off and a dangling pointer's repair
68
+
69
+ "user pause" means an explicit user request to stop, or a branch above that says stop. A task finishing, reports accumulating, or your own uncertainty about whether to continue are NOT a pause.
70
+
71
+ - (a task completed and incomplete tasks remain) => do NOT ask "shall I continue?" — continue; asking here is a violation
72
+ - Asking is correct only when: blocked, a genuine decision fork the user owns, or an action that is outward-facing or hard to reverse (publishing, renaming a remote repository, deleting user files)
73
+
74
+ ## Diverge Check
75
+
76
+ - (DESIGN.md and PLAN.md both exist, Files lists differ) => warn: `"[DESIGN.md]($DocsDir/DESIGN.md) and [PLAN.md]($DocsDir/PLAN.md) file lists differ. Run /$CommandPrefix:design sync to review."`
77
+
78
+ ## Work Principles
79
+ - Load the `opengoal-flow` skill, then follow its main-agent flow principles (documentation timing, CONTEXT.md self-sync, OVERVIEW.md reactive read, checkpoints, self-verification).
80
+ <!-- @if subagent -->
81
+ - Load the `opengoal-subagent` skill, then follow its delegation principles and workflow.
82
+ <!-- @endif -->
83
+
84
+ > When Constraints conflict with any other instruction, Constraints win.