@opellen/opengoal 1.0.5 → 1.1.0-rc.1
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.
- package/README.ja.md +2 -2
- package/README.ko.md +5 -5
- package/README.md +5 -5
- package/README.zh-CN.md +5 -5
- package/dist/cli.js +17 -4
- package/dist/installer.d.ts +6 -0
- package/dist/installer.js +45 -1
- package/dist/platforms/antigravity.js +16 -7
- package/dist/platforms/index.d.ts +1 -1
- package/dist/platforms/index.js +6 -3
- package/dist/platforms/kimi.d.ts +2 -0
- package/dist/platforms/kimi.js +10 -0
- package/dist/platforms/types.d.ts +17 -0
- package/package.json +1 -1
- package/templates/commands/context.md +7 -3
- package/templates/commands/go.md +87 -84
- package/templates/commands/goal.md +114 -7
- package/templates/commands/recap.md +7 -2
- package/templates/commands/scout.md +24 -6
- package/templates/commands/verify.md +5 -2
- package/templates/skills/opengoal-flow/SKILL.md +3 -1
package/README.ja.md
CHANGED
|
@@ -330,9 +330,9 @@ AI: ✓ サブゴールをアーカイブしました。Goal Aに戻ります
|
|
|
330
330
|
|
|
331
331
|
**長期にわたるビルド**
|
|
332
332
|
|
|
333
|
-
- [
|
|
334
|
-
- [Ordo](https://github.com/opellen/Ordo) — Planura から切り出された C++20 の型付きイベント・アプリケーションフレームワークです。イベントはただの構造体で、型がアイデンティティ、フィールドがペイロードです。
|
|
333
|
+
- [Ordo](https://github.com/opellen/Ordo) — C++20 の型付きイベント・アプリケーションフレームワークです。イベントはただの構造体で、型がアイデンティティ、フィールドがペイロードです。OrdoStateDesigner と Planura はこの上に構築されています。
|
|
335
334
|
- [OrdoStateDesigner](https://github.com/opellen/OrdoStateDesigner) — Ordo の上に構築したステートチャート・デザイナー(C++20 / Qt 6)です。キャンバスに状態機械を描き、その場でシミュレートし、それを動かす C++ を生成します。
|
|
335
|
+
- [Planura](https://github.com/opellen/Planura) — ネイティブなダイレクトモデリング3Dアプリケーション(C++20 / Qt 6 / OpenGL): half-edgeジオメトリカーネル、CSGソリッドモデリング、推論駆動の描画を Ordo の上に実装。Ordo はこのプロジェクトから切り出されたものです。
|
|
336
336
|
- リバースエンジニアリングのキャンペーン — OpenGoalが設計された本来の領域であり、ゴールは大きく、道筋は不明で、進捗が細かく分割できるかどうかにかかっています。
|
|
337
337
|
|
|
338
338
|
**アプリケーションとツール**
|
package/README.ko.md
CHANGED
|
@@ -328,13 +328,13 @@ AI: ✓ 서브골 아카이브 완료. Goal A로 복귀 — 포인터 태스크
|
|
|
328
328
|
|
|
329
329
|
**긴 호흡의 개발**
|
|
330
330
|
|
|
331
|
-
- [
|
|
332
|
-
|
|
333
|
-
자체 프레임워크인 [Ordo](https://github.com/opellen/Ordo) 기반으로 구현했습니다.
|
|
334
|
-
- [Ordo](https://github.com/opellen/Ordo) — Planura에서 추출된 C++20용 타입 이벤트 애플리케이션 프레임워크입니다.
|
|
335
|
-
이벤트는 평범한 구조체이며, 타입이 곧 정체성이고 필드가 곧 페이로드입니다.
|
|
331
|
+
- [Ordo](https://github.com/opellen/Ordo) — C++20용 타입 이벤트 애플리케이션 프레임워크입니다.
|
|
332
|
+
이벤트는 평범한 구조체이며, 타입이 곧 정체성이고 필드가 곧 페이로드입니다. OrdoStateDesigner와 Planura가 이 위에서 만들어졌습니다.
|
|
336
333
|
- [OrdoStateDesigner](https://github.com/opellen/OrdoStateDesigner) — Ordo 기반의 상태차트 디자이너입니다
|
|
337
334
|
(C++20 / Qt 6). 캔버스에 상태 머신을 그리고, 실시간으로 시뮬레이션하고, 그것을 실행하는 C++ 코드를 생성합니다.
|
|
335
|
+
- [Planura](https://github.com/opellen/Planura) — 네이티브 다이렉트 모델링 3D 애플리케이션
|
|
336
|
+
(C++20 / Qt 6 / OpenGL). half-edge 지오메트리 커널, CSG 솔리드 모델링, 추론 기반 드로잉을
|
|
337
|
+
Ordo 기반으로 구현했고, Ordo는 이 프로젝트에서 추출됐습니다.
|
|
338
338
|
- 리버스엔지니어링 캠페인 — OpenGoal이 처음 고안된 도메인입니다. 목표는 거대하고 길은
|
|
339
339
|
보이지 않아서, 목표를 잘게 쪼갤 수 있을 때에만 전진할 수 있는 영역입니다.
|
|
340
340
|
|
package/README.md
CHANGED
|
@@ -336,13 +336,13 @@ That range is the point.
|
|
|
336
336
|
|
|
337
337
|
**Long-horizon builds**
|
|
338
338
|
|
|
339
|
-
- [
|
|
340
|
-
|
|
341
|
-
drawing, on [Ordo](https://github.com/opellen/Ordo), its purpose-built application framework.
|
|
342
|
-
- [Ordo](https://github.com/opellen/Ordo) — a typed-event application framework for C++20, extracted from
|
|
343
|
-
Planura. An event is a plain struct: the type is the identity, the fields are the payload.
|
|
339
|
+
- [Ordo](https://github.com/opellen/Ordo) — a typed-event application framework for C++20. An event is a
|
|
340
|
+
plain struct: the type is the identity, the fields are the payload. OrdoStateDesigner and Planura are built on it.
|
|
344
341
|
- [OrdoStateDesigner](https://github.com/opellen/OrdoStateDesigner) — a statechart designer built on Ordo
|
|
345
342
|
(C++20 / Qt 6): draw a state machine on a canvas, simulate it live, and generate the C++ that runs it.
|
|
343
|
+
- [Planura](https://github.com/opellen/Planura) — a native direct-modeling 3D application
|
|
344
|
+
(C++20 / Qt 6 / OpenGL): half-edge geometry kernel, CSG solid modeling, inference-driven
|
|
345
|
+
drawing, on Ordo, which was extracted from it.
|
|
346
346
|
- Reverse-engineering campaigns — the domain OpenGoal was designed in, where the goal is
|
|
347
347
|
large, the path is unknown, and progress depends on splitting it finely.
|
|
348
348
|
|
package/README.zh-CN.md
CHANGED
|
@@ -351,13 +351,13 @@ AI: ✓ sub-goal 已归档。回到目标 A —— 对应的指针任务已勾
|
|
|
351
351
|
|
|
352
352
|
**长周期开发**
|
|
353
353
|
|
|
354
|
-
- [
|
|
355
|
-
|
|
356
|
-
绘图,构建在自研框架 [Ordo](https://github.com/opellen/Ordo) 之上。
|
|
357
|
-
- [Ordo](https://github.com/opellen/Ordo) — 从 Planura 中提取出来的 C++20 类型化事件应用框架。
|
|
358
|
-
事件就是一个普通的结构体:类型即身份,字段即载荷。
|
|
354
|
+
- [Ordo](https://github.com/opellen/Ordo) — C++20 类型化事件应用框架。
|
|
355
|
+
事件就是一个普通的结构体:类型即身份,字段即载荷。OrdoStateDesigner 和 Planura 都构建在它之上。
|
|
359
356
|
- [OrdoStateDesigner](https://github.com/opellen/OrdoStateDesigner) — 构建在 Ordo 之上的状态图设计器
|
|
360
357
|
(C++20 / Qt 6):在画布上绘制状态机,实时模拟,并生成运行它的 C++ 代码。
|
|
358
|
+
- [Planura](https://github.com/opellen/Planura) — 一款原生的直接建模 3D 应用
|
|
359
|
+
(C++20 / Qt 6 / OpenGL):半边(half-edge)几何内核、CSG 实体建模、推理驱动的
|
|
360
|
+
绘图,构建在 Ordo 之上;Ordo 正是从这个项目中提取出来的。
|
|
361
361
|
- 逆向工程项目 — OpenGoal 最初就是为这类场景设计的:目标庞大、路径未知,
|
|
362
362
|
进展全靠把任务拆得足够细。
|
|
363
363
|
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { resolve } from "node:path";
|
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { install, dryRun, detectStale, removeStale } from "./installer.js";
|
|
5
5
|
import { DEFAULT_PREFIX } from "./templates.js";
|
|
6
|
-
import { PLATFORM_IDS, DEFAULT_PLATFORM, isValidPlatform, detectInstalledPlatforms } from "./platforms/index.js";
|
|
6
|
+
import { PLATFORM_IDS, DEFAULT_PLATFORM, isValidPlatform, detectInstalledPlatforms, getAdapters } from "./platforms/index.js";
|
|
7
7
|
import { showWelcome } from "./ui/welcome.js";
|
|
8
8
|
import { selectPlatforms } from "./prompts/platform-select.js";
|
|
9
9
|
import { t } from "./i18n/index.js";
|
|
@@ -250,7 +250,7 @@ async function main() {
|
|
|
250
250
|
console.log(` ${chalk.green("+")} ${file}`);
|
|
251
251
|
}
|
|
252
252
|
if (stale.length > 0) {
|
|
253
|
-
console.log("\nStale files from a previous prefix (would be removed):");
|
|
253
|
+
console.log("\nStale files from a previous prefix or install layout (would be removed):");
|
|
254
254
|
for (const entry of stale) {
|
|
255
255
|
console.log(` ${chalk.red("-")} ${entry.dst}`);
|
|
256
256
|
}
|
|
@@ -272,7 +272,7 @@ async function main() {
|
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
if (stale.length > 0) {
|
|
275
|
-
console.log("\nStale files from a previous prefix:");
|
|
275
|
+
console.log("\nStale files from a previous prefix or install layout:");
|
|
276
276
|
for (const entry of stale) {
|
|
277
277
|
console.log(` ${chalk.yellow("!")} ${entry.dst}`);
|
|
278
278
|
}
|
|
@@ -292,7 +292,20 @@ async function main() {
|
|
|
292
292
|
}
|
|
293
293
|
console.log("\n" + title(t("cli.nextSteps")));
|
|
294
294
|
console.log(" " + chalk.dim("1.") + " " + t("cli.step1"));
|
|
295
|
-
|
|
295
|
+
const hints = new Map();
|
|
296
|
+
for (const adapter of getAdapters(tools)) {
|
|
297
|
+
if (adapter.supportsCommands === false)
|
|
298
|
+
continue;
|
|
299
|
+
const ref = adapter.commandRef?.("scout", args.prefix) ?? `/${args.prefix}:scout`;
|
|
300
|
+
const labels = hints.get(ref) ?? [];
|
|
301
|
+
if (!labels.includes(adapter.displayName))
|
|
302
|
+
labels.push(adapter.displayName);
|
|
303
|
+
hints.set(ref, labels);
|
|
304
|
+
}
|
|
305
|
+
for (const [ref, labels] of hints) {
|
|
306
|
+
const label = tools.length > 1 ? `${labels.join(", ")}: ` : "";
|
|
307
|
+
console.log(" " + chalk.dim("2.") + " " + label + t("cli.step2").replace("{cmd}", goal(ref)));
|
|
308
|
+
}
|
|
296
309
|
process.exit(0);
|
|
297
310
|
}
|
|
298
311
|
main();
|
package/dist/installer.d.ts
CHANGED
|
@@ -16,6 +16,12 @@ export declare function dryRun(config: OpenGoalConfig): {
|
|
|
16
16
|
* eligible. Skill entries are excluded (rule: skills don't carry the
|
|
17
17
|
* prefix, so they can never go stale), and the current prefix is never
|
|
18
18
|
* considered stale even if passed in explicitly.
|
|
19
|
+
*
|
|
20
|
+
* Adapters that declare legacyLayouts (an earlier config dir / command
|
|
21
|
+
* layout) additionally contribute the exact files opengoal wrote there, for
|
|
22
|
+
* the current prefix and every old prefix, plus the shared skills (once).
|
|
23
|
+
* Such entries carry an adapter view whose configDir is the legacy root, so
|
|
24
|
+
* removeStale() prunes emptied directories up to that root.
|
|
19
25
|
*/
|
|
20
26
|
export declare function detectStale(config: OpenGoalConfig, oldPrefixes: string[]): TemplateEntry[];
|
|
21
27
|
/**
|
package/dist/installer.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync, unlinkSync, readdirSync, rmdirSync } from "node:fs";
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
3
|
import { join, dirname, resolve, sep } from "node:path";
|
|
4
|
+
import { getAdapters } from "./platforms/index.js";
|
|
4
5
|
import { resolveTemplates, renderFile } from "./templates.js";
|
|
5
6
|
function createDefaultPrompt() {
|
|
6
7
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -80,6 +81,12 @@ export function dryRun(config) {
|
|
|
80
81
|
* eligible. Skill entries are excluded (rule: skills don't carry the
|
|
81
82
|
* prefix, so they can never go stale), and the current prefix is never
|
|
82
83
|
* considered stale even if passed in explicitly.
|
|
84
|
+
*
|
|
85
|
+
* Adapters that declare legacyLayouts (an earlier config dir / command
|
|
86
|
+
* layout) additionally contribute the exact files opengoal wrote there, for
|
|
87
|
+
* the current prefix and every old prefix, plus the shared skills (once).
|
|
88
|
+
* Such entries carry an adapter view whose configDir is the legacy root, so
|
|
89
|
+
* removeStale() prunes emptied directories up to that root.
|
|
83
90
|
*/
|
|
84
91
|
export function detectStale(config, oldPrefixes) {
|
|
85
92
|
const seen = new Set();
|
|
@@ -99,8 +106,45 @@ export function detectStale(config, oldPrefixes) {
|
|
|
99
106
|
}
|
|
100
107
|
}
|
|
101
108
|
}
|
|
109
|
+
stale.push(...detectLegacyLayoutFiles(config, oldPrefixes, seen));
|
|
102
110
|
return stale;
|
|
103
111
|
}
|
|
112
|
+
function detectLegacyLayoutFiles(config, oldPrefixes, seen) {
|
|
113
|
+
const found = [];
|
|
114
|
+
const current = new Set(resolveTemplates(config).map((e) => e.dst));
|
|
115
|
+
const prefixes = Array.from(new Set([config.prefix, ...oldPrefixes]));
|
|
116
|
+
for (const adapter of getAdapters(config.tools)) {
|
|
117
|
+
if (!adapter.legacyLayouts)
|
|
118
|
+
continue;
|
|
119
|
+
for (const layout of adapter.legacyLayouts) {
|
|
120
|
+
const view = { ...adapter, configDir: layout.configDir };
|
|
121
|
+
const consider = (entry, dst) => {
|
|
122
|
+
if (current.has(dst) || seen.has(dst))
|
|
123
|
+
return;
|
|
124
|
+
seen.add(dst);
|
|
125
|
+
if (existsSync(join(config.root, dst)))
|
|
126
|
+
found.push({ ...entry, dst, adapter: view });
|
|
127
|
+
};
|
|
128
|
+
prefixes.forEach((prefix, i) => {
|
|
129
|
+
const entries = resolveTemplates({ ...config, tools: [adapter.id], prefix });
|
|
130
|
+
for (const entry of entries) {
|
|
131
|
+
if (entry.generated)
|
|
132
|
+
continue;
|
|
133
|
+
if (entry.src.startsWith("commands/")) {
|
|
134
|
+
if (adapter.supportsCommands === false)
|
|
135
|
+
continue;
|
|
136
|
+
const cmd = entry.src.slice("commands/".length).replace(/\.md$/, "");
|
|
137
|
+
consider(entry, layout.commandPath(cmd, prefix));
|
|
138
|
+
}
|
|
139
|
+
else if (i === 0 && entry.src.startsWith("skills/")) {
|
|
140
|
+
consider(entry, `${layout.configDir}/skills/${entry.meta.name}/SKILL.md`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return found;
|
|
147
|
+
}
|
|
104
148
|
/**
|
|
105
149
|
* Walks upward from startDir, removing directories that are now empty,
|
|
106
150
|
* stopping at (and never removing) boundaryDir itself, and stopping as
|
|
@@ -140,7 +184,7 @@ export async function removeStale(config, stale, prompt) {
|
|
|
140
184
|
try {
|
|
141
185
|
let proceed = config.force === true;
|
|
142
186
|
if (!proceed) {
|
|
143
|
-
const answer = await askUser(` Found ${stale.length} stale command file(s) from a previous prefix. Remove? [y/N] `);
|
|
187
|
+
const answer = await askUser(` Found ${stale.length} stale command file(s) from a previous prefix or install layout. Remove? [y/N] `);
|
|
144
188
|
proceed = answer === "y" || answer === "yes";
|
|
145
189
|
}
|
|
146
190
|
if (!proceed) {
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
// Antigravity merged slash-command workflows into skills and moved its
|
|
3
|
+
// workspace dir from `.agent/` to `.agents/`. A skill is invoked as `/<name>`.
|
|
2
4
|
export const antigravity = {
|
|
3
5
|
id: "antigravity",
|
|
4
6
|
displayName: "Antigravity",
|
|
5
|
-
configDir: ".
|
|
6
|
-
commandPath: (name, prefix) => `.
|
|
7
|
-
formatCommand: (body, meta) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
configDir: ".agents",
|
|
8
|
+
commandPath: (name, prefix) => `.agents/skills/${prefix}-${name}/SKILL.md`,
|
|
9
|
+
formatCommand: (body, meta, prefix) => yamlFrontmatter({ name: `${prefix}-${meta.name}`, description: meta.description }) +
|
|
10
|
+
stripFrontmatter(body),
|
|
11
|
+
commandRef: (name, prefix) => `/${prefix}-${name}`,
|
|
12
|
+
legacyLayouts: [
|
|
13
|
+
{
|
|
14
|
+
configDir: ".agent",
|
|
15
|
+
commandPath: (name, prefix) => `.agent/workflows/${prefix}-${name}.md`,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
// `.agents/skills/` is the cross-tool Agent Skills root (Codex and others
|
|
19
|
+
// read it too), so only Antigravity-specific dirs count as detection.
|
|
20
|
+
detectDirs: [".agent", ".agents/workflows", ".agents/rules"],
|
|
12
21
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PlatformAdapter } from "./types.js";
|
|
2
2
|
export type { PlatformAdapter, CommandMeta } from "./types.js";
|
|
3
3
|
export { DEFAULT_PLATFORM } from "./types.js";
|
|
4
|
-
export declare const PLATFORM_IDS: readonly ["claude", "cursor", "windsurf", "cline", "codex", "github-copilot", "continue", "amazon-q", "antigravity", "auggie", "codebuddy", "costrict", "crush", "factory", "gemini", "iflow", "kilocode", "kiro", "opencode", "pi", "qoder", "qwen", "roocode", "trae"];
|
|
4
|
+
export declare const PLATFORM_IDS: readonly ["claude", "cursor", "windsurf", "cline", "codex", "github-copilot", "continue", "amazon-q", "antigravity", "auggie", "codebuddy", "costrict", "crush", "factory", "gemini", "iflow", "kilocode", "kiro", "kimi", "opencode", "pi", "qoder", "qwen", "roocode", "trae"];
|
|
5
5
|
export type PlatformId = typeof PLATFORM_IDS[number];
|
|
6
6
|
export declare function isValidPlatform(id: string): id is PlatformId;
|
|
7
7
|
export declare function getAdapter(id: string): PlatformAdapter | undefined;
|
package/dist/platforms/index.js
CHANGED
|
@@ -24,11 +24,12 @@ import { qoder } from "./qoder.js";
|
|
|
24
24
|
import { qwen } from "./qwen.js";
|
|
25
25
|
import { roocode } from "./roocode.js";
|
|
26
26
|
import { trae } from "./trae.js";
|
|
27
|
+
import { kimi } from "./kimi.js";
|
|
27
28
|
export { DEFAULT_PLATFORM } from "./types.js";
|
|
28
29
|
const ALL_ADAPTERS = [
|
|
29
30
|
claude, cursor, windsurf, cline, codex, githubCopilot, continueAdapter,
|
|
30
31
|
amazonQ, antigravity, auggie, codebuddy, costrict, crush, factory,
|
|
31
|
-
gemini, iflow, kilocode, kiro, opencode, pi, qoder, qwen, roocode, trae,
|
|
32
|
+
gemini, iflow, kilocode, kiro, kimi, opencode, pi, qoder, qwen, roocode, trae,
|
|
32
33
|
];
|
|
33
34
|
const ADAPTER_MAP = new Map(ALL_ADAPTERS.map((a) => [a.id, a]));
|
|
34
35
|
if (ADAPTER_MAP.size !== ALL_ADAPTERS.length)
|
|
@@ -36,7 +37,7 @@ if (ADAPTER_MAP.size !== ALL_ADAPTERS.length)
|
|
|
36
37
|
export const PLATFORM_IDS = [
|
|
37
38
|
"claude", "cursor", "windsurf", "cline", "codex", "github-copilot", "continue",
|
|
38
39
|
"amazon-q", "antigravity", "auggie", "codebuddy", "costrict", "crush", "factory",
|
|
39
|
-
"gemini", "iflow", "kilocode", "kiro", "opencode", "pi", "qoder", "qwen", "roocode", "trae",
|
|
40
|
+
"gemini", "iflow", "kilocode", "kiro", "kimi", "opencode", "pi", "qoder", "qwen", "roocode", "trae",
|
|
40
41
|
];
|
|
41
42
|
if (PLATFORM_IDS.length !== ALL_ADAPTERS.length)
|
|
42
43
|
throw new Error("PLATFORM_IDS out of sync");
|
|
@@ -60,7 +61,9 @@ export function getAllAdapters() {
|
|
|
60
61
|
export function detectInstalledPlatforms(projectRoot) {
|
|
61
62
|
const detected = [];
|
|
62
63
|
for (const adapter of ALL_ADAPTERS) {
|
|
63
|
-
|
|
64
|
+
const dirs = adapter.detectDirs ??
|
|
65
|
+
[adapter.configDir, ...(adapter.legacyLayouts?.map((l) => l.configDir) ?? [])];
|
|
66
|
+
if (dirs.some((dir) => existsSync(resolve(projectRoot, dir)))) {
|
|
64
67
|
detected.push(adapter.id);
|
|
65
68
|
}
|
|
66
69
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { stripFrontmatter, yamlFrontmatter } from "./yaml.js";
|
|
2
|
+
export const kimi = {
|
|
3
|
+
id: "kimi",
|
|
4
|
+
displayName: "Kimi Code",
|
|
5
|
+
configDir: ".kimi-code",
|
|
6
|
+
commandPath: (name, prefix) => `.kimi-code/skills/${prefix}-${name}/SKILL.md`,
|
|
7
|
+
formatCommand: (body, meta, prefix) => yamlFrontmatter({ name: `${prefix}-${meta.name}`, description: meta.description }) +
|
|
8
|
+
stripFrontmatter(body),
|
|
9
|
+
commandRef: (name, prefix) => `/skill:${prefix}-${name}`,
|
|
10
|
+
};
|
|
@@ -43,5 +43,22 @@ export interface PlatformAdapter {
|
|
|
43
43
|
* uninstalled together with the file they accompany.
|
|
44
44
|
*/
|
|
45
45
|
companionFiles?(target: CompanionTarget): CompanionFile[];
|
|
46
|
+
/**
|
|
47
|
+
* Earlier install layouts of this platform (e.g. a renamed config dir).
|
|
48
|
+
* Re-installing offers to remove the files opengoal itself wrote there,
|
|
49
|
+
* found by exact path (never a glob). `configDir` is the root that emptied
|
|
50
|
+
* directories are pruned up to; the root itself is never removed.
|
|
51
|
+
*/
|
|
52
|
+
legacyLayouts?: Array<{
|
|
53
|
+
configDir: string;
|
|
54
|
+
commandPath(name: string, prefix: string): string;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Directories whose presence means this platform is in use, for
|
|
58
|
+
* auto-detection. Defaults to `configDir` plus every legacy `configDir`.
|
|
59
|
+
* Set it when `configDir` is a root other tools share (e.g. `.agents/`),
|
|
60
|
+
* so that root alone does not count as detection.
|
|
61
|
+
*/
|
|
62
|
+
detectDirs?: string[];
|
|
46
63
|
}
|
|
47
64
|
export declare const DEFAULT_PLATFORM = "claude";
|
package/package.json
CHANGED
|
@@ -15,7 +15,9 @@ Manages `$DocsDir/CONTEXT.md`. Records the **current working context** of the pr
|
|
|
15
15
|
## Constraints
|
|
16
16
|
|
|
17
17
|
- Never overwrite CONTEXT.md without user confirmation.
|
|
18
|
-
-
|
|
18
|
+
- Writes `$DocsDir/CONTEXT.md` only — content that belongs in another resource is reported to the user, never written there.
|
|
19
|
+
- Pointers only — this file is read whole at every session start, so an entry records when to read a resource and where it is, never what is learned after opening it.
|
|
20
|
+
- (an entry restates what its referenced resource already holds) => reduce it to the pointer.
|
|
19
21
|
|
|
20
22
|
> When Constraints conflict with any other instruction, Constraints win.
|
|
21
23
|
|
|
@@ -70,9 +72,9 @@ Creates `$DocsDir/CONTEXT.md`.
|
|
|
70
72
|
|
|
71
73
|
**Project-specific sections** — extend the skeleton with sections appropriate to the project:
|
|
72
74
|
|
|
73
|
-
- **Resources**: Key file/directory paths and their
|
|
75
|
+
- **Resources**: Key file/directory paths and when to reference them, not their contents
|
|
74
76
|
- **Process**: Project-specific procedures (e.g., porting rules, analysis doc management)
|
|
75
|
-
- **Index/Tables**: Frequently referenced item lists (e.g., analysis topics, API endpoints)
|
|
77
|
+
- **Index/Tables**: Frequently referenced item lists (e.g., analysis topics, API endpoints). When the list lives in its own file, this section holds the pointer to that file, not a copy of the list.
|
|
76
78
|
- **Extended Principles**: Project-specific principles (e.g., 1:1 logic preservation, no magic numbers)
|
|
77
79
|
|
|
78
80
|
## sync
|
|
@@ -86,6 +88,8 @@ Reviews current CONTEXT.md and **proposes updates**.
|
|
|
86
88
|
- Content to add
|
|
87
89
|
- Content to modify
|
|
88
90
|
- Outdated content to remove/update
|
|
91
|
+
- Entries to reduce to a pointer — the referenced resource already holds the content
|
|
92
|
+
- Entries whose content no resource holds yet — listed as move candidates for the user; sync does not write outside CONTEXT.md
|
|
89
93
|
5. Apply the changes.
|
|
90
94
|
6. Report: `"Updated [CONTEXT.md]($DocsDir/CONTEXT.md)."`
|
|
91
95
|
|
package/templates/commands/go.md
CHANGED
|
@@ -1,84 +1,87 @@
|
|
|
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,
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
<!-- @
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- (
|
|
33
|
-
- (
|
|
34
|
-
|
|
35
|
-
- (
|
|
36
|
-
- (
|
|
37
|
-
|
|
38
|
-
- (PLAN.md
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
goal-id
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- (
|
|
65
|
-
- (
|
|
66
|
-
- (
|
|
67
|
-
- (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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, `opengoal-flow`'s own text not visible in your current context) => load the `opengoal-flow` skill BEFORE executing the first task, and say so in one line — its rules (checkpoint triggers, documentation timing, CONTEXT.md self-sync, self-verification) bind only while that text is in context.
|
|
13
|
+
- (command entry, `opengoal-flow`'s own text visible) => do not re-read it.
|
|
14
|
+
- Visible means the skill's text itself, as read or injected — remembering its rules, or a summary that mentions them, is not visible.
|
|
15
|
+
<!-- @if subagent -->
|
|
16
|
+
- **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).
|
|
17
|
+
- 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.
|
|
18
|
+
- (subagent dispatch, `opengoal-subagent`'s own text not visible in your current context) => 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 and announcement is a violation, because its dispatch rules (model selection/reporting, prompt requirements, post-verify) bind only while that text is in context.
|
|
19
|
+
- (subagent dispatch, `opengoal-subagent`'s own text visible) => do not re-read it.
|
|
20
|
+
<!-- @else -->
|
|
21
|
+
- Perform implementation tasks directly.
|
|
22
|
+
- 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.
|
|
23
|
+
<!-- @endif -->
|
|
24
|
+
|
|
25
|
+
> When Constraints conflict with any other instruction, Constraints win.
|
|
26
|
+
|
|
27
|
+
## Execution
|
|
28
|
+
|
|
29
|
+
1. If the text of GOAL.md and CONTEXT.md is visible in your current context, 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.
|
|
30
|
+
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.**
|
|
31
|
+
- If GOAL.md is absent: "No goal set. Run `/$CommandPrefix:goal init` first, or tell me what to work on."
|
|
32
|
+
- (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
|
|
33
|
+
- (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
|
|
34
|
+
3. Find the next incomplete task in GOAL.md.
|
|
35
|
+
- (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
|
|
36
|
+
- (task has step annotation `— Step N/M`) => resume from the indicated step
|
|
37
|
+
4. PLAN.md dispatch:
|
|
38
|
+
- (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
|
|
39
|
+
- (PLAN.md exists — no `goal-id`, or it matches) => read the corresponding task section for implementation context
|
|
40
|
+
- (PLAN.md absent, task complexity ≥ multi-file) => generate PLAN.md with the front-matter below, then report: `"Created [PLAN.md]($DocsDir/PLAN.md)."`
|
|
41
|
+
- (PLAN.md absent, task complexity < multi-file) => proceed without PLAN.md
|
|
42
|
+
5. Execute tasks using the Task Outcome loop below.
|
|
43
|
+
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.
|
|
44
|
+
|
|
45
|
+
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):
|
|
46
|
+
```yaml
|
|
47
|
+
---
|
|
48
|
+
goal-id: <GOAL.md id>
|
|
49
|
+
created: YYYY-MM-DD
|
|
50
|
+
---
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Pointer Task Status
|
|
54
|
+
|
|
55
|
+
`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.
|
|
56
|
+
|
|
57
|
+
- (parked) => name it and note `/$CommandPrefix:goal subgoal switch <slug>` works it
|
|
58
|
+
- (archived) => report that it completed with the pointer left unchecked; nothing is blocked — bare `/$CommandPrefix:goal subgoal` offers the check-off
|
|
59
|
+
- (dangling) => report it as a repairable interrupted `subgoal init`, and point at `/$CommandPrefix:goal subgoal`
|
|
60
|
+
|
|
61
|
+
## Task Outcome
|
|
62
|
+
|
|
63
|
+
loop until (every task is complete or a pointer task OR user pause):
|
|
64
|
+
- (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
|
|
65
|
+
- (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
|
|
66
|
+
- (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
|
|
67
|
+
- (blocked) => report issue and ask user how to proceed
|
|
68
|
+
- (all tasks complete) => suggest `/$CommandPrefix:goal archive` once; do not repeat if user does not act on it
|
|
69
|
+
- (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
|
|
70
|
+
- (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
|
|
71
|
+
|
|
72
|
+
"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.
|
|
73
|
+
|
|
74
|
+
- (a task completed and incomplete tasks remain) => do NOT ask "shall I continue?" — continue; asking here is a violation
|
|
75
|
+
- 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)
|
|
76
|
+
|
|
77
|
+
## Diverge Check
|
|
78
|
+
|
|
79
|
+
- (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."`
|
|
80
|
+
|
|
81
|
+
## Work Principles
|
|
82
|
+
- 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).
|
|
83
|
+
<!-- @if subagent -->
|
|
84
|
+
- Load the `opengoal-subagent` skill, then follow its delegation principles and workflow.
|
|
85
|
+
<!-- @endif -->
|
|
86
|
+
|
|
87
|
+
> When Constraints conflict with any other instruction, Constraints win.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "opengoal:goal"
|
|
3
|
-
description: "Project goal (GOAL.md) management (init|breakdown|checkpoint|suspend|resume|archive)"
|
|
3
|
+
description: "Project goal (GOAL.md) management (init|breakdown|checkpoint|suspend|resume|archive|land)"
|
|
4
4
|
category: Workflow
|
|
5
5
|
tags: [workflow, opengoal, goal]
|
|
6
6
|
---
|
|
@@ -11,12 +11,16 @@ Manages `$DocsDir/GOAL.md`.
|
|
|
11
11
|
|
|
12
12
|
## Constraints
|
|
13
13
|
|
|
14
|
-
- (command entry,
|
|
14
|
+
- (command entry, `opengoal-flow`'s own text not visible in your current context) => load the `opengoal-flow` skill BEFORE writing or moving any document, and say so in one line — its rules (self-verification before marking anything done, User Decision Support format) bind only while that text is in context.
|
|
15
|
+
- (command entry, `opengoal-flow`'s own text visible) => do not re-read it.
|
|
16
|
+
- Visible means the skill's text itself, as read or injected — remembering its rules, or a summary that mentions them, is not visible.
|
|
15
17
|
- GOAL.md is the single source of truth for the current goal's state.
|
|
16
|
-
- Never overwrite GOAL.md
|
|
18
|
+
- Never overwrite GOAL.md — a second goal while one is active goes through the four options in `### init (active goal present)` (worktree / suspend / archive / cancel); none of them overwrites.
|
|
17
19
|
- Preserve existing check states when updating tasks.
|
|
18
20
|
- Task numbers use hierarchical dot notation: `1.`, `1.1.`, `1.2.1.` — numbers are part of the checklist text, no separate id field.
|
|
19
21
|
- (`subgoal init`, the derived slug matches `$DocsDir/suspended/<slug>/` or the active goal's `id`) => refuse outright and ask for a different description — never offer to overwrite; a dangling `→ subgoal: <slug>` pointer task is not a collision (an interrupted `init` must stay re-runnable), and `$DocsDir/archive/` is deliberately not checked because `archive`'s `-<N>` directory rule makes an archived slug safe to reuse.
|
|
22
|
+
- (`land`, the merge reports a conflict) => abort the merge and report the conflicting files — never edit conflict hunks on your own; which side wins is the user's call.
|
|
23
|
+
- (`archive` or `land` running inside a worktree, per `### Worktree Detection`) => never modify the main checkout's working tree except through `land`'s own `git -C <main-root> merge` and its `--abort` — merge timing across worktrees belongs to the user.
|
|
20
24
|
|
|
21
25
|
> When Constraints conflict with any other instruction, Constraints win.
|
|
22
26
|
|
|
@@ -26,6 +30,8 @@ Manages `$DocsDir/GOAL.md`.
|
|
|
26
30
|
|
|
27
31
|
`/$CommandPrefix:goal subgoal <verb> [args]` — sub-goal lifecycle (`init` | `pause` | `switch`, or no verb to list).
|
|
28
32
|
|
|
33
|
+
`/$CommandPrefix:goal land [<id>]` — merge a finished worktree goal into the base branch (runnable from any session).
|
|
34
|
+
|
|
29
35
|
`/$CommandPrefix:goal <goal description>` — shorthand for `init` with that content.
|
|
30
36
|
|
|
31
37
|
## Subcommand Dispatch
|
|
@@ -43,6 +49,7 @@ Manages `$DocsDir/GOAL.md`.
|
|
|
43
49
|
- (args = subgoal) => see Subcommands: subgoal
|
|
44
50
|
- (args = archive, `$DocsDir/GOAL.md` absent) => stop: "No active GOAL to archive."
|
|
45
51
|
- (args = archive, GOAL.md exists) => see Subcommands: archive
|
|
52
|
+
- (args = land) => see Subcommands: land — it resolves its own target and needs no active GOAL.md
|
|
46
53
|
- (args are free-text goal content — multi-word or quoted, not a subcommand keyword — and `$DocsDir/GOAL.md` has `parent:`) => refuse with the same message as `args = init` — free text runs init
|
|
47
54
|
- (args are free-text goal content — multi-word or quoted, not a subcommand keyword — and no `parent:`) => run init with that content
|
|
48
55
|
- (otherwise) => report unknown subcommand and list available subcommands
|
|
@@ -58,8 +65,8 @@ Creates `$DocsDir/GOAL.md`.
|
|
|
58
65
|
|
|
59
66
|
1. If `$ARGUMENTS` has content, use it to write the goal.
|
|
60
67
|
2. If empty, derive from the current session discussion.
|
|
61
|
-
3. If GOAL.md already exists,
|
|
62
|
-
4. Write GOAL.md with the format below.
|
|
68
|
+
3. If GOAL.md already exists, run `### init (active goal present)` below. It either stops (cancel, or the new goal was created in a worktree) or returns here with the canonical slot empty.
|
|
69
|
+
4. Write GOAL.md with the format below. (picked from a `$DocsDir/ROADMAP.md` milestone) => record `milestone: M<N>`; (the description names a code area) => record `scope:`.
|
|
63
70
|
5. Assess task granularity:
|
|
64
71
|
- (tasks are complex, embed multiple implicit steps) => recommend `/$CommandPrefix:goal breakdown` with 1-line rationale
|
|
65
72
|
- (tasks are specific and actionable) => recommend `/$CommandPrefix:design init` (implementation task) or `/$CommandPrefix:go` (analysis task) with 1-line rationale
|
|
@@ -75,6 +82,10 @@ id: <goal-slug>
|
|
|
75
82
|
goal: <one-line summary>
|
|
76
83
|
status: in-progress
|
|
77
84
|
started: YYYY-MM-DD
|
|
85
|
+
milestone: M<N> # optional — the ROADMAP milestone this goal implements
|
|
86
|
+
scope: [<dir>, <dir>] # optional — code areas this goal expects to touch
|
|
87
|
+
base: <branch> # worktree goals only — the branch the worktree was forked from
|
|
88
|
+
worktree: .opengoal/worktrees/<goal-slug> # worktree goals only
|
|
78
89
|
---
|
|
79
90
|
```
|
|
80
91
|
|
|
@@ -90,6 +101,52 @@ Body structure:
|
|
|
90
101
|
- Top-level tasks are numbered `1.`, `2.`, `3.`.
|
|
91
102
|
- Sub-tasks inherit parent number: `1.1.`, `1.2.`, and deeper: `1.2.1.`, `1.2.2.`.
|
|
92
103
|
|
|
104
|
+
### Worktree Detection
|
|
105
|
+
|
|
106
|
+
Used by `init`, `archive`, `land`, and `/$CommandPrefix:scout`. Decide once per command run:
|
|
107
|
+
|
|
108
|
+
- `<main-root>` = the first `worktree` line of `git worktree list --porcelain`.
|
|
109
|
+
- This session is **inside a worktree** when `git rev-parse --show-toplevel` lies under `<main-root>/.opengoal/worktrees/`. GOAL.md's `worktree:` field confirms it but is not required — a goal started by hand in such a directory still counts.
|
|
110
|
+
- Otherwise this session is in the **main checkout**.
|
|
111
|
+
|
|
112
|
+
### init (active goal present)
|
|
113
|
+
|
|
114
|
+
`$DocsDir/GOAL.md` exists and carries no `parent:` (a `parent:` is refused by Subcommand Dispatch before reaching here). The user's intent is ambiguous — a parallel goal, a forgotten archive, or a quick switch — so this is a genuine decision fork. Present it in `opengoal-flow`'s User Decision Support form as plain text (never a menu widget), with exactly one recommendation:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
Active goal <id> is in progress. Options:
|
|
118
|
+
1. New worktree — keep <id> running; start the new goal in .opengoal/worktrees/<new-id>/ for a separate session.
|
|
119
|
+
2. Suspend <id> and start the new goal here.
|
|
120
|
+
3. Archive <id> and start the new goal here.
|
|
121
|
+
4. Cancel.
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Pick the recommendation by the first rule that matches:
|
|
125
|
+
|
|
126
|
+
- (the active goal has no incomplete tasks) => recommend 3
|
|
127
|
+
- (this session is inside a worktree per `### Worktree Detection`) => omit option 1 from the menu — worktrees are created from the main checkout — and recommend 2
|
|
128
|
+
- (the new goal maps to a ROADMAP milestone, or is clearly multi-session work) => recommend 1
|
|
129
|
+
- (otherwise) => recommend 2
|
|
130
|
+
|
|
131
|
+
Then:
|
|
132
|
+
|
|
133
|
+
- (1) => run `#### init in a new worktree` below, and stop — do not continue `init` steps 4–7 here.
|
|
134
|
+
- (2) => perform the `suspend` procedure, replacing its step 5 report with the single line `"Suspended <id> to [$DocsDir/suspended/<id>/]($DocsDir/suspended/<id>/)."`, then continue `init` at step 4.
|
|
135
|
+
- (3) => perform the `archive` procedure, keeping its step 6 report but dropping the closer sentence, then continue `init` at step 4. Inside a worktree this runs `### archive (inside a worktree)` too; the new goal then continues on the same branch, and the worktree is merge-ready again only when that goal archives.
|
|
136
|
+
- (4) => stop: `"Cancelled. Active goal <id> is unchanged."`
|
|
137
|
+
|
|
138
|
+
#### init in a new worktree
|
|
139
|
+
|
|
140
|
+
Run from the main checkout. Only the main checkout may create worktrees — (this session is inside a worktree per `### Worktree Detection`) => stop: `"Worktrees are created from the main checkout. Run /$CommandPrefix:goal init there."`
|
|
141
|
+
|
|
142
|
+
1. Derive `<new-id>` the way `init` derives `id` (kebab-case English slug of the description). (`.opengoal/worktrees/<new-id>/` exists, branch `goal/<new-id>` exists, `$DocsDir/suspended/<new-id>/` exists, or `<new-id>` equals the active goal's `id`) => refuse and ask for a different description.
|
|
143
|
+
2. Preflight: `git status --porcelain -- $DocsDir` on the main checkout must print nothing — a worktree is a checkout of HEAD, so uncommitted docs would be invisible to the new goal. (not clean) => report the files and stop; the user commits first.
|
|
144
|
+
3. Record `<base>` = the branch currently checked out in the main checkout (`git rev-parse --abbrev-ref HEAD`); (`.gitignore` lacks a line covering `.opengoal/`) => append `.opengoal/` to `.gitignore` and say so.
|
|
145
|
+
4. `git worktree add .opengoal/worktrees/<new-id> -b goal/<new-id>`.
|
|
146
|
+
5. In the new worktree, delete the copied goal-owned documents: `$DocsDir/GOAL.md`, `$DocsDir/DESIGN.md`, `$DocsDir/PLAN.md`, `$DocsDir/CHECKPOINT.md` (whichever exist). They belong to the goal still running in the main checkout; `archive`'s worktree closing steps make these deletions merge-neutral.
|
|
147
|
+
6. Write the new goal's GOAL.md at `.opengoal/worktrees/<new-id>/$DocsDir/GOAL.md` using the format above, including `base: <base>` and `worktree: .opengoal/worktrees/<new-id>`, plus `milestone:` / `scope:` per `init` step 4.
|
|
148
|
+
7. Report: `"Created worktree [.opengoal/worktrees/<new-id>/](.opengoal/worktrees/<new-id>/) on branch goal/<new-id> with its GOAL.md. Open a session in that directory and run /$CommandPrefix:scout. The active goal <id> here is unchanged."` No launch command is prescribed — the directory is the contract; any session opened there sees the root install.
|
|
149
|
+
|
|
93
150
|
## breakdown
|
|
94
151
|
|
|
95
152
|
Decomposes existing GOAL.md tasks into sub-tasks.
|
|
@@ -106,7 +163,7 @@ Usage: `/$CommandPrefix:goal breakdown [task-number]`
|
|
|
106
163
|
|
|
107
164
|
### Steps
|
|
108
165
|
|
|
109
|
-
1. Read `$DocsDir/GOAL.md` and `$DocsDir/DESIGN.md` at once (parallel if supported, sequential otherwise). Skip
|
|
166
|
+
1. Read `$DocsDir/GOAL.md` and `$DocsDir/DESIGN.md` at once (parallel if supported, sequential otherwise). Skip a file whose text is visible in your current context — but re-read 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. A file read error means the file does not exist — **do NOT retry failed reads.**
|
|
110
167
|
2. Identify target tasks based on targeting rules above.
|
|
111
168
|
3. Derive sub-tasks:
|
|
112
169
|
- If DESIGN.md was found and has an Execution Order section, use it as a reference for deriving sub-tasks.
|
|
@@ -137,7 +194,7 @@ Saves a progress snapshot to `$DocsDir/CHECKPOINT.md`.
|
|
|
137
194
|
Single file, overwritten each time — the AI only needs the latest state to resume.
|
|
138
195
|
Prevents loss of mid-goal progress when context is compacted.
|
|
139
196
|
|
|
140
|
-
1. Read `$DocsDir/GOAL.md` and `$DocsDir/PLAN.md` at once (parallel if supported, sequential otherwise). Skip
|
|
197
|
+
1. Read `$DocsDir/GOAL.md` and `$DocsDir/PLAN.md` at once (parallel if supported, sequential otherwise). Skip a file whose text is visible in your current context — but re-read 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. A file read error means the file does not exist — **do NOT retry failed reads.**
|
|
141
198
|
2. Requires GOAL.md front-matter `id`.
|
|
142
199
|
3. If `$ARGUMENTS` has content, incorporate it.
|
|
143
200
|
4. Write based on the current session:
|
|
@@ -320,6 +377,7 @@ Archives the current GOAL.md and its siblings.
|
|
|
320
377
|
- (a goal parked under `$DocsDir/suspended/` carries `parent:` equal to this goal's `id`) => refuse: parked sub-goals of this goal remain — offer to finish them, to `/$CommandPrefix:goal subgoal switch <slug>` into one, or to leave the parent open. Never instruct the user to delete anything. This holds whether or not this goal itself has a `parent:`: archiving a middle node would strand its children, whose `parent:` would then name a goal that is live nowhere. (Presenting these options is a genuine decision fork — only the user knows whether the remaining work still matters — not a handoff, per the single-path Constraint's own exception.)
|
|
321
378
|
- (no parked sub-goals of this goal, `$DocsDir/GOAL.md` front-matter has `parent:`, `$DocsDir/suspended/<parent-id>/` exists) => this is a sub-goal completing — see `### archive (sub-goal completion)` below, not the numbered steps
|
|
322
379
|
- (no parked sub-goals of this goal, `parent:` present, `$DocsDir/suspended/<parent-id>/` absent) => archive via `### archive (sub-goal completion)`, report the missing parent, and leave the slot empty — `/$CommandPrefix:goal resume` is the recovery
|
|
380
|
+
- (no parked sub-goals of this goal, no `parent:`, this session is inside a worktree per `### Worktree Detection`) => the numbered steps below, then `### archive (inside a worktree)` — its closer replaces step 6's. A sub-goal completing inside a worktree takes the sub-goal path above instead; the worktree becomes merge-ready only when its top-level goal archives
|
|
323
381
|
- (otherwise) => the numbered steps below, unchanged
|
|
324
382
|
|
|
325
383
|
Both `parent:` checks read the front-matter of each `$DocsDir/suspended/*/GOAL.md` — the same read `resume`'s grouped candidate list and `subgoal`'s Lineage Validation already perform.
|
|
@@ -359,4 +417,53 @@ Reached only from the dispatch above — the steps there are already at the cap,
|
|
|
359
417
|
- (the run was interrupted after step 1, `$DocsDir/suspended/<parent-id>/` exists — distinct from the missing-parent rule above, whose stop after step 1 is its normal end) => the slot is empty with the pointer unchecked; recover with `/$CommandPrefix:goal resume <parent-id>`, then carry out step 3 against the resumed parent — permitted by `### Pointer Task`'s check-off rule.
|
|
360
418
|
- (the run was interrupted after step 2 — parent active, pointer unchecked) => the pointer now resolves **archived**; complete step 3 directly, or let bare `/$CommandPrefix:goal subgoal` offer it — both permitted by `### Pointer Task`'s check-off rule.
|
|
361
419
|
|
|
420
|
+
### archive (inside a worktree)
|
|
421
|
+
|
|
422
|
+
Reached from the dispatch above after `## archive` steps 1–7 ran on this worktree's own copies (ROADMAP tick and BACKLOG sweep included — the merge carries them to the base branch as one-line hunks). This path closes the goal on its branch and leaves the main checkout alone; merging is `land`'s job, because other worktrees may have to land first.
|
|
423
|
+
|
|
424
|
+
1. Read `<base>` from the archived GOAL.md front-matter (`$DocsDir/archive/goals/YYYY-MM-DD-<id>/GOAL.md`); (absent) => use the main checkout's current branch.
|
|
425
|
+
2. Restore the goal-owned documents to the fork point so this branch carries no change to them. With `<fork>` = `git merge-base <base> HEAD`, handle **each** of `$DocsDir/GOAL.md`, `$DocsDir/DESIGN.md`, `$DocsDir/PLAN.md`, `$DocsDir/CHECKPOINT.md` separately — one combined `git restore` fails entirely if any path was absent at the fork:
|
|
426
|
+
- (`git cat-file -e <fork>:<path>` succeeds — the file existed at the fork) => `git checkout <fork> -- <path>`
|
|
427
|
+
- (it did not exist at the fork) => make sure it is absent now (`git rm -q --cached <path>` if tracked, delete the file if present) — absent at both ends is "no change"
|
|
428
|
+
Result check: `git diff --name-only <fork> -- $DocsDir/GOAL.md $DocsDir/DESIGN.md $DocsDir/PLAN.md $DocsDir/CHECKPOINT.md` must print nothing. (it prints a path) => stop before committing and report `"Restore incomplete: <paths> still differ from the fork point."` — this check is what keeps `land` free of modify/delete conflicts when the main checkout still has a goal of its own.
|
|
429
|
+
3. `git add -A` and commit on `goal/<id>` with message `archive <id>`.
|
|
430
|
+
4. Closer: keep step 6's `"Archived <N> file(s) …"` report, and replace only its closing sentence with `" Committed on goal/<id>. This worktree is ready to merge — /$CommandPrefix:goal land merges it into <base> now."`
|
|
431
|
+
|
|
432
|
+
## land
|
|
433
|
+
|
|
434
|
+
Merges a finished worktree goal into its base branch. Runnable from any session — the user should not need to know which window to type it in.
|
|
435
|
+
|
|
436
|
+
Usage: `/$CommandPrefix:goal land [<id>]`
|
|
437
|
+
|
|
438
|
+
### Target Resolution
|
|
439
|
+
|
|
440
|
+
- (this session is inside a worktree per `### Worktree Detection`) => the target is this worktree; an `<id>` argument naming a different one is refused — land that one from the main checkout
|
|
441
|
+
- (main checkout, `<id>` given, `.opengoal/worktrees/<id>/` exists) => that worktree
|
|
442
|
+
- (main checkout, `<id>` given, directory absent) => stop: `"No worktree '<id>'."`
|
|
443
|
+
- (main checkout, no `<id>`, exactly one merge-ready worktree) => select it
|
|
444
|
+
- (main checkout, no `<id>`, several merge-ready) => list them and ask which to land first — merge order is a genuine decision fork; dependencies between goals are known only to the user
|
|
445
|
+
- (main checkout, no `<id>`, none merge-ready) => report the worktree states per `/$CommandPrefix:scout`'s classification and stop
|
|
446
|
+
|
|
447
|
+
**Merge-ready** means: the worktree's `$DocsDir/GOAL.md` is absent, `git status --porcelain` there prints nothing, and `goal/<id>` is ahead of `<base>` (read `<base>` from the archived GOAL.md in that worktree; fall back to the main checkout's current branch).
|
|
448
|
+
|
|
449
|
+
### Steps
|
|
450
|
+
|
|
451
|
+
1. Resolve the target per Target Resolution. (not merge-ready) => stop: `"Worktree <id> is not ready — run /$CommandPrefix:goal archive in it first."`
|
|
452
|
+
2. Busy check on the main checkout. Compute the branch's changed files, `git diff --name-only <base>...goal/<id>`, and the main checkout's dirty files, `git -C <main-root> status --porcelain`.
|
|
453
|
+
- (a merge is in progress — `<main-root>/.git/MERGE_HEAD` exists) => stop: `"The base branch has a merge in progress. Finish or abort it, then land again."`
|
|
454
|
+
- (a dirty file in the main checkout is also a changed file on the branch) => stop: `"Uncommitted changes in <main-root> touch files this merge would update: <files>. Commit or stash them there, then land again."` — the worktree stays merge-ready; nothing is lost
|
|
455
|
+
- (otherwise) => continue. Unrelated uncommitted edits in the main checkout — an active goal's GOAL.md ticks, say — do not block the merge; `archive`'s worktree closing steps already made the goal documents merge-neutral, so they are never on the branch's changed-file list
|
|
456
|
+
3. Confirm `git -C <main-root> rev-parse --abbrev-ref HEAD` is `<base>`. (it is another branch) => stop: `"<main-root> has <branch> checked out, not <base>. Check out <base> there first."` Otherwise `git -C <main-root> merge --no-ff goal/<id>`.
|
|
457
|
+
- (clean) => continue
|
|
458
|
+
- (conflict) => `git -C <main-root> merge --abort`, then stop with `"Merge of goal/<id> conflicts in: <files>. Aborted; <base> is unchanged. Resolve by hand or land another worktree first."` Per Constraints, do not resolve hunks yourself.
|
|
459
|
+
4. Cleanup:
|
|
460
|
+
- (run from the main checkout) => `git worktree remove .opengoal/worktrees/<id>` and `git branch -d goal/<id>`; the step 5 report then ends with `" Worktree and branch removed."`
|
|
461
|
+
- (run from inside the worktree) => skip — a session cannot remove its own directory. The step 5 report then ends with `" Cleanup of this worktree is offered by the next /$CommandPrefix:scout in the main checkout."`
|
|
462
|
+
5. Report: `"Landed goal <id> into <base> (<N> commits)."` plus the cleanup sentence from step 4, then one closer:
|
|
463
|
+
- (another merge-ready worktree remains) => `" Next: /$CommandPrefix:goal land <next-id>."`
|
|
464
|
+
- (peer goals remain under `$DocsDir/suspended/`) => `" Resume a parked goal with /$CommandPrefix:goal resume."`
|
|
465
|
+
- (otherwise) => `" Set a new goal with /$CommandPrefix:goal init."`
|
|
466
|
+
|
|
467
|
+
Every git command here is run by the agent under the normal permission flow; nothing assumes the user types git.
|
|
468
|
+
|
|
362
469
|
> When Constraints conflict with any other instruction, Constraints win.
|
|
@@ -13,7 +13,9 @@ Wraps up the current session by syncing important decisions and findings into th
|
|
|
13
13
|
|
|
14
14
|
## Constraints
|
|
15
15
|
|
|
16
|
-
- (command entry,
|
|
16
|
+
- (command entry, `opengoal-flow`'s own text not visible in your current context) => load the `opengoal-flow` skill BEFORE writing to any document, and say so in one line — its rules (the blocker / sub-goal / backlog discriminant that decides where a scanned finding belongs, self-verification before marking anything done) bind only while that text is in context.
|
|
17
|
+
- (command entry, `opengoal-flow`'s own text visible) => do not re-read it.
|
|
18
|
+
- Visible means the skill's text itself, as read or injected — remembering its rules, or a summary that mentions them, is not visible.
|
|
17
19
|
- Living documents only — recap updates CONTEXT.md, DESIGN.md, OVERVIEW.md, GOAL.md. Never create new archival files.
|
|
18
20
|
- No duplication — if a change is already reflected in a document, skip it.
|
|
19
21
|
- No session transcripts — show what changes, not conversation replay.
|
|
@@ -46,7 +48,9 @@ Wraps up the current session by syncing important decisions and findings into th
|
|
|
46
48
|
|
|
47
49
|
Route each finding to its target document. Only the active goal's documents are routing targets — see Constraints. Recap applies the updates itself in Phase 3 (diff, then apply) — it never invokes another command's procedure.
|
|
48
50
|
|
|
49
|
-
- (working context changes: principles, workflow, resources) => CONTEXT.md
|
|
51
|
+
- (working context changes: principles, workflow, resources) => CONTEXT.md, as a pointer — when to read a resource and where it is
|
|
52
|
+
- (detail only useful after opening a resource, a bullet below routes it) => that document, never CONTEXT.md
|
|
53
|
+
- (detail only useful after opening a resource, no bullet below routes it) => report it to the user — recap writes living documents only
|
|
50
54
|
- (implementation decisions, design changes) => DESIGN.md
|
|
51
55
|
- (project-level understanding: architecture, stack, strategy) => OVERVIEW.md
|
|
52
56
|
- (a routed target — CONTEXT.md, DESIGN.md, OVERVIEW.md, or GOAL.md — does not exist) => skip that routing entirely; a document the project never created is one it has not needed, so there is nothing to sync. This includes one altitude of a dual-altitude finding — the existing altitude's target still writes. Do not create the absent document and do not suggest creating it — Phase 3's report already lists only the documents actually updated. This rule precedes every routing bullet in this Phase, Constraints' project-scoped note included.
|
|
@@ -64,6 +68,7 @@ Route each finding to its target document. Only the active goal's documents are
|
|
|
64
68
|
### CONTEXT.md
|
|
65
69
|
- Add: new workflow step for ...
|
|
66
70
|
- Update: resource path changed to ...
|
|
71
|
+
- Trim: <entry> → pointer only (detail already in <resource>)
|
|
67
72
|
|
|
68
73
|
### DESIGN.md
|
|
69
74
|
- Add: decision to use X instead of Y ...
|
|
@@ -9,16 +9,19 @@ tags: [workflow, opengoal, scout]
|
|
|
9
9
|
|
|
10
10
|
## Constraints
|
|
11
11
|
|
|
12
|
-
- (command entry,
|
|
12
|
+
- (command entry, `opengoal-flow`'s own text not visible in your current context) => load the `opengoal-flow` skill BEFORE reporting status, and say so in one line — its rules (checkpoint triggers, documentation timing, CONTEXT.md self-sync, self-verification) bind only while that text is in context.
|
|
13
|
+
- (command entry, `opengoal-flow`'s own text visible) => do not re-read it.
|
|
14
|
+
- Visible means the skill's text itself, as read or injected — remembering its rules, or a summary that mentions them, is not visible.
|
|
13
15
|
<!-- @if subagent -->
|
|
14
16
|
- **Delegate** exploration tasks (e.g., file discovery, keyword search, tracing) to **subagents** — analysis and judgment stay with main. Direct implementation work is limited to one-line fixes, except where `opengoal-subagent` designates work main-only (iterative collaboration, 2nd-iteration rework, evolving design).
|
|
15
17
|
- Report subagent results to the user.
|
|
16
|
-
- (
|
|
18
|
+
- (subagent dispatch, `opengoal-subagent`'s own text not visible in your current context) => 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 and announcement is a violation, because its dispatch rules (model selection/reporting, prompt requirements, post-verify) bind only while that text is in context.
|
|
19
|
+
- (subagent dispatch, `opengoal-subagent`'s own text visible) => do not re-read it.
|
|
17
20
|
<!-- @else -->
|
|
18
21
|
- Perform analysis and implementation tasks directly.
|
|
19
22
|
- Report results to the user.
|
|
20
23
|
<!-- @endif -->
|
|
21
|
-
- Report status based solely on docs files read during initialization — this includes the `$DocsDir/suspended/*/GOAL.md` front-matter reads in step 2 below and, when a pointer task needs resolving, listing `$DocsDir/archive/goals/` and reading a matching directory's GOAL.md front-matter (the resolver's `parent:` check) — do not read other files proactively.
|
|
24
|
+
- Report status based solely on docs files read during initialization — this includes the `$DocsDir/suspended/*/GOAL.md` front-matter reads in step 2 below, the worktree reads in step 3 (each `.opengoal/worktrees/*/$DocsDir/GOAL.md` and `CHECKPOINT.md`, plus the read-only git queries step 3 names: `worktree list`, `rev-parse`, `status`, `log`, `merge-base`) and, when a pointer task needs resolving, listing `$DocsDir/archive/goals/` and reading a matching directory's GOAL.md front-matter (the resolver's `parent:` check) — do not read other files proactively.
|
|
22
25
|
- Keep suggestions to 1-2 lines — follow the user's direction if they want something different.
|
|
23
26
|
- Skip suggestions if the user starts with a specific task instruction.
|
|
24
27
|
- GOAL.md tasks are always the unit of progress — DESIGN.md is a reference document, not a progress tracker.
|
|
@@ -34,8 +37,17 @@ tags: [workflow, opengoal, scout]
|
|
|
34
37
|
- `$DocsDir/CONTEXT.md`, `$DocsDir/GOAL.md`, `$DocsDir/DESIGN.md`, `$DocsDir/PLAN.md`, `$DocsDir/ROADMAP.md`, `$DocsDir/CHECKPOINT.md`
|
|
35
38
|
- A file read error means the file does not exist — mark it as "not present" and move on. **Do NOT retry failed reads.**
|
|
36
39
|
2. Always check for suspended goals by listing `$DocsDir/suspended/` (this can be a separate call only if needed), and read the front-matter of each `$DocsDir/suspended/*/GOAL.md` — the same read `goal.md`'s `resume` candidate list and `subgoal`'s Lineage Validation already perform. This is what surfaces a parked parent or sibling even while a sub-goal is the active GOAL.md.
|
|
37
|
-
3.
|
|
38
|
-
|
|
40
|
+
3. Worktree goals — decide first whether this session is inside a worktree (the same test `/$CommandPrefix:goal`'s `### Worktree Detection` uses, restated here so scout needs nothing loaded): `<main-root>` is the first `worktree` line of `git worktree list --porcelain`; this session is inside a worktree when `git rev-parse --show-toplevel` lies under `<main-root>/.opengoal/worktrees/`. State the result in one clause of the status report (`"in worktree <id>"` or `"main checkout"`).
|
|
41
|
+
- (inside a worktree) => this session owns one goal; report only this worktree's docs and do not enumerate the other worktrees — the main checkout's state is another session's concern. Classify this worktree alone with the list below so Tier 0 can still suggest `land` here
|
|
42
|
+
- (main checkout, `.opengoal/worktrees/` absent or empty) => nothing to list
|
|
43
|
+
- (main checkout, worktrees present) => classify each `.opengoal/worktrees/<id>/` with the list below
|
|
44
|
+
Classification inputs per worktree: `$DocsDir/GOAL.md` front-matter and task checkboxes, the `CHECKPOINT.md` summary if present, `git status --porcelain` there, and `git log <base>..goal/<id> --oneline` (`<base>` from the GOAL.md or archived GOAL.md front-matter; fall back to the main checkout's branch). Evaluate the states in this order and take the first that matches:
|
|
45
|
+
1. **in progress** — GOAL.md present; report done/total and the checkpoint line
|
|
46
|
+
2. **merge-ready** — GOAL.md absent, status clean, branch ahead of `<base>`
|
|
47
|
+
3. **cleanup-pending** — GOAL.md absent, branch already contained in `<base>` (`git merge-base --is-ancestor goal/<id> <base>` succeeds), directory still present
|
|
48
|
+
4. **stale** — anything else, e.g. uncommitted changes with no GOAL.md
|
|
49
|
+
4. If no GOAL.md exists, also read `$DocsDir/BACKLOG.md` (skip this read when a GOAL is active).
|
|
50
|
+
5. Report status based solely on the above files — worktrees as a **Worktrees** section, one line each with id, state, progress — then suggest the next action based on the dispatch rules below.
|
|
39
51
|
- (the active goal has `parent:`, or a suspended goal's front-matter has `parent:` equal to the active goal's `id`) => report the four kinds `goal.md`'s `subgoal list` uses: **Active scope** (the active goal's `id`, and its `parent:` if present); **Parked sub-goals of this lineage** (children of the active goal, and siblings sharing its `parent:`); **the parent**, shown only when the active goal has `parent:`, together with its return promise — it comes back automatically when this sub-goal completes via `/$CommandPrefix:goal archive`, or immediately via `/$CommandPrefix:goal subgoal pause`; **Unrelated peer goals** (suspended goals outside this lineage).
|
|
40
52
|
- (no active GOAL.md, a suspended goal carries `parent:`) => group the parked sub-goals under their `parent:` alongside the peer goals, so the lineage is visible before `/$CommandPrefix:goal resume` runs.
|
|
41
53
|
- (otherwise) => no lineage grouping; report suspended goals per State Dispatch below, unchanged. This suppresses the four-kind presentation only — it never suppresses the goals themselves.
|
|
@@ -44,7 +56,13 @@ tags: [workflow, opengoal, scout]
|
|
|
44
56
|
|
|
45
57
|
## State Dispatch
|
|
46
58
|
|
|
47
|
-
|
|
59
|
+
Four tiers. Tier 0 is a pre-check on worktrees; Tiers 1–3 are exclusive — no CONTEXT.md and no GOAL.md, CONTEXT.md present without GOAL.md, GOAL.md present. Exactly one suggestion results per session start: a Tier 0 rule, or else one Tier 1–3 rule; within each tier the conditions are mutually exclusive.
|
|
60
|
+
|
|
61
|
+
Tier 0 — worktrees (from the classification in Session Initialization step 3; when a rule here fires, Tiers 1–3 are skipped):
|
|
62
|
+
|
|
63
|
+
- (a merge-ready worktree exists — in the listing, or this worktree itself when inside one) => suggest `/$CommandPrefix:goal land <id>`; finished work waiting to merge outranks starting or continuing anything. With several, the suggestion names the first; the Worktrees section already shows the rest
|
|
64
|
+
- (no merge-ready worktree, a cleanup-pending worktree exists) => suggest its cleanup, for confirmation: `git worktree remove .opengoal/worktrees/<id>` and `git branch -d goal/<id>` — the branch is already in `<base>`, so nothing is lost
|
|
65
|
+
- (no Tier 0 rule applies) => Tiers 1–3 decide; in-progress and stale worktrees appear in the Worktrees section but drive no suggestion
|
|
48
66
|
|
|
49
67
|
Tier 1 — no CONTEXT.md and no GOAL.md (an active GOAL.md without CONTEXT.md is unusual but belongs to Tier 3 — work proceeds, and Documentation Timing may suggest `/$CommandPrefix:context init` later):
|
|
50
68
|
|
|
@@ -11,11 +11,14 @@ Cross-checks the current implementation state against GOAL.md and DESIGN.md to s
|
|
|
11
11
|
|
|
12
12
|
## Constraints
|
|
13
13
|
|
|
14
|
-
- (command entry,
|
|
14
|
+
- (command entry, `opengoal-flow`'s own text not visible in your current context) => load the `opengoal-flow` skill BEFORE reporting verification results, and say so in one line — its rules (backlog handling and disposal, self-verification, checkpoint triggers) bind only while that text is in context.
|
|
15
|
+
- (command entry, `opengoal-flow`'s own text visible) => do not re-read it.
|
|
16
|
+
- Visible means the skill's text itself, as read or injected — remembering its rules, or a summary that mentions them, is not visible.
|
|
15
17
|
<!-- @if subagent -->
|
|
16
18
|
- **Delegate** evidence gathering (e.g., reading files, running checks) to **subagents** — verification synthesis stays with main. Direct work is limited to one-line fixes, except where `opengoal-subagent` designates work main-only (iterative collaboration, 2nd-iteration rework, evolving design).
|
|
17
19
|
- Report subagent results to the user.
|
|
18
|
-
- (
|
|
20
|
+
- (subagent dispatch, `opengoal-subagent`'s own text not visible in your current context) => 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 and announcement is a violation, because its dispatch rules (model selection/reporting, prompt requirements, post-verify) bind only while that text is in context.
|
|
21
|
+
- (subagent dispatch, `opengoal-subagent`'s own text visible) => do not re-read it.
|
|
19
22
|
<!-- @else -->
|
|
20
23
|
- Perform analysis and verification tasks directly.
|
|
21
24
|
- Report results to the user.
|
|
@@ -32,6 +32,8 @@ Execute when any of:
|
|
|
32
32
|
|
|
33
33
|
> Destructive operations (overwriting existing files, archive) still follow state-aware prompts — in-context confirmation does not bypass those guards.
|
|
34
34
|
|
|
35
|
+
- (a recognized command's own instructions are visible in your current context) => execute from them — do not re-read the command file.
|
|
36
|
+
|
|
35
37
|
## Documentation Timing
|
|
36
38
|
|
|
37
39
|
- (implementation plan crystallizes — files, design decisions, execution order) => suggest `/$CommandPrefix:design init`
|
|
@@ -73,7 +75,7 @@ When a reactive trigger fires (the user-invoked-procedure exemption skips this
|
|
|
73
75
|
1. Confirm `$DocsDir/OVERVIEW.md` exists (existence check only).
|
|
74
76
|
2. If absent, inform the user and proceed without it.
|
|
75
77
|
3. If present, surface the affordance to the user — *do not auto-read*. Example: "Architectural ambiguity detected. `$DocsDir/OVERVIEW.md` is available — load it?"
|
|
76
|
-
4. Read only after explicit user approval
|
|
78
|
+
4. Read only after explicit user approval; on a later trigger, use it without re-reading while its text is visible in your current context.
|
|
77
79
|
|
|
78
80
|
> Bias control: when the trigger condition is uncertain, **default to NOT reading**. The cost of missing one read is small; the cost of always-loading is structural.
|
|
79
81
|
|