opencode-teammate 0.1.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.
- package/.bunli/commands.gen.ts +87 -0
- package/.github/workflows/ci.yml +31 -0
- package/.github/workflows/release.yml +140 -0
- package/.oxfmtrc.json +3 -0
- package/.oxlintrc.json +4 -0
- package/.zed/settings.json +76 -0
- package/README.md +15 -0
- package/bunli.config.ts +11 -0
- package/bunup.config.ts +31 -0
- package/package.json +36 -0
- package/src/adapters/assets/index.ts +1 -0
- package/src/adapters/assets/specifications.ts +70 -0
- package/src/adapters/beads/agents.ts +105 -0
- package/src/adapters/beads/config.ts +17 -0
- package/src/adapters/beads/index.ts +4 -0
- package/src/adapters/beads/issues.ts +156 -0
- package/src/adapters/beads/specifications.ts +55 -0
- package/src/adapters/environments/index.ts +43 -0
- package/src/adapters/environments/worktrees.ts +78 -0
- package/src/adapters/teammates/index.ts +15 -0
- package/src/assets/agent/planner.md +196 -0
- package/src/assets/command/brainstorm.md +60 -0
- package/src/assets/command/specify.md +135 -0
- package/src/assets/command/work.md +247 -0
- package/src/assets/index.ts +37 -0
- package/src/cli/commands/manifest.ts +6 -0
- package/src/cli/commands/spec/sync.ts +47 -0
- package/src/cli/commands/work.ts +110 -0
- package/src/cli/index.ts +11 -0
- package/src/plugin.ts +45 -0
- package/src/tools/i-am-done.ts +44 -0
- package/src/tools/i-am-stuck.ts +49 -0
- package/src/tools/index.ts +2 -0
- package/src/use-cases/index.ts +5 -0
- package/src/use-cases/inject-beads-issue.ts +97 -0
- package/src/use-cases/sync-specifications.ts +48 -0
- package/src/use-cases/sync-teammates.ts +35 -0
- package/src/use-cases/track-specs.ts +91 -0
- package/src/use-cases/work-on-issue.ts +110 -0
- package/src/utils/chain.ts +60 -0
- package/src/utils/frontmatter.spec.ts +491 -0
- package/src/utils/frontmatter.ts +317 -0
- package/src/utils/opencode.ts +102 -0
- package/src/utils/polling.ts +41 -0
- package/src/utils/projects.ts +35 -0
- package/src/utils/shell/client.spec.ts +106 -0
- package/src/utils/shell/client.ts +117 -0
- package/src/utils/shell/error.ts +29 -0
- package/src/utils/shell/index.ts +2 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { assert, first, isEmpty } from "radashi";
|
|
2
|
+
|
|
3
|
+
// import * as shell from "#utils/shell/index.js";
|
|
4
|
+
import * as shell from "../../utils/shell/index.js";
|
|
5
|
+
|
|
6
|
+
export type Issue = {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
status: string;
|
|
10
|
+
created_at: string;
|
|
11
|
+
external_ref?: string;
|
|
12
|
+
assignee?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export interface ListOptions {
|
|
16
|
+
all?: boolean;
|
|
17
|
+
ids?: string[];
|
|
18
|
+
type?: string;
|
|
19
|
+
assignee?: string;
|
|
20
|
+
status?: "open" | "in_progress" | "blocked" | "deferred" | "closed";
|
|
21
|
+
sort?:
|
|
22
|
+
| "priority"
|
|
23
|
+
| "created"
|
|
24
|
+
| "updated"
|
|
25
|
+
| "closed"
|
|
26
|
+
| "status"
|
|
27
|
+
| "id"
|
|
28
|
+
| "title"
|
|
29
|
+
| "type"
|
|
30
|
+
| "assignee";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ListReadyOptions {
|
|
34
|
+
parent?: string;
|
|
35
|
+
type?: string;
|
|
36
|
+
unassigned?: boolean;
|
|
37
|
+
assignee?: string;
|
|
38
|
+
sort?: "hybrid" | "priority" | "oldest";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const list = Object.assign(
|
|
42
|
+
async (client: shell.client.ClientInput, options: ListOptions = {}) => {
|
|
43
|
+
if (isEmpty(options.ids)) return [];
|
|
44
|
+
|
|
45
|
+
const $ = shell.client.use(client);
|
|
46
|
+
|
|
47
|
+
const issues = await $<Issue[]>`bd list ${options} --json`.json();
|
|
48
|
+
|
|
49
|
+
return issues;
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
ready: async (client: shell.client.ClientInput, options: ListReadyOptions = {}) => {
|
|
53
|
+
const $ = shell.client.use(client);
|
|
54
|
+
|
|
55
|
+
const issues = await $<Issue[]>`bd ready ${options} --json`.json();
|
|
56
|
+
|
|
57
|
+
return issues;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
export interface UseOptions {
|
|
63
|
+
/** Force re-fetching the issue */
|
|
64
|
+
force?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function use(
|
|
68
|
+
client: shell.client.ClientInput,
|
|
69
|
+
input: { id: string } | Issue,
|
|
70
|
+
options?: UseOptions,
|
|
71
|
+
) {
|
|
72
|
+
if ("status" in input && !options?.force) return input;
|
|
73
|
+
|
|
74
|
+
return first(
|
|
75
|
+
await list(client, {
|
|
76
|
+
...options,
|
|
77
|
+
ids: [input.id],
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface UpdateOptions {
|
|
83
|
+
"add-label"?: string[] | string;
|
|
84
|
+
description?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function update(
|
|
88
|
+
client: shell.client.ClientInput,
|
|
89
|
+
input: { id: string },
|
|
90
|
+
options: UpdateOptions = {},
|
|
91
|
+
) {
|
|
92
|
+
const $ = shell.client.use(client);
|
|
93
|
+
|
|
94
|
+
const issues = await $<Issue[]>`bd update ${input.id} ${options} --json`.json();
|
|
95
|
+
|
|
96
|
+
const [issue] = issues;
|
|
97
|
+
assert(issue, `Issue '${input.id}' not found`);
|
|
98
|
+
|
|
99
|
+
return issue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ClaimOptions {
|
|
103
|
+
/** Assignee of the issue */
|
|
104
|
+
actor?: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function claim(
|
|
108
|
+
client: shell.client.ClientInput,
|
|
109
|
+
input: { id: string },
|
|
110
|
+
options: ClaimOptions = {},
|
|
111
|
+
) {
|
|
112
|
+
const $ = shell.client.use(client);
|
|
113
|
+
|
|
114
|
+
const issues = await $<Issue[]>`bd update ${input.id} ${options} --claim --json`.json();
|
|
115
|
+
|
|
116
|
+
const [issue] = issues;
|
|
117
|
+
assert(issue, `Issue '${input.id}' not found`);
|
|
118
|
+
|
|
119
|
+
return issue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface CloseOptions {
|
|
123
|
+
/** Reason for closing the issue */
|
|
124
|
+
reason?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function close(
|
|
128
|
+
client: shell.client.ClientInput,
|
|
129
|
+
input: { id: string },
|
|
130
|
+
options: CloseOptions = {},
|
|
131
|
+
) {
|
|
132
|
+
const $ = shell.client.use(client);
|
|
133
|
+
|
|
134
|
+
const issues = await $<Issue[]>`bd close ${input.id} ${options} --json`.json();
|
|
135
|
+
|
|
136
|
+
const [issue] = issues;
|
|
137
|
+
assert(issue, `Issue '${input.id}' not found`);
|
|
138
|
+
|
|
139
|
+
return issue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function show(client: shell.client.ClientInput, input: { id: string }) {
|
|
143
|
+
const $ = shell.client.use(client);
|
|
144
|
+
return $`bd show ${input.id}`.text();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export namespace find {
|
|
148
|
+
export async function byExternalRef(
|
|
149
|
+
client: shell.client.ClientInput,
|
|
150
|
+
ref: string,
|
|
151
|
+
options?: ListOptions,
|
|
152
|
+
) {
|
|
153
|
+
const _issues = await list(client, options);
|
|
154
|
+
return _issues.find((data) => data.external_ref === ref);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { assert } from "radashi";
|
|
2
|
+
|
|
3
|
+
// import * as shell from "#utils/shell/index.js";
|
|
4
|
+
import * as shell from "../../utils/shell/index.js";
|
|
5
|
+
|
|
6
|
+
import * as issues from "./issues";
|
|
7
|
+
|
|
8
|
+
export type SpecificationInput = {
|
|
9
|
+
file: string;
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function create(client: shell.client.ClientInput, data: SpecificationInput) {
|
|
15
|
+
const $ = shell.client.use(client);
|
|
16
|
+
|
|
17
|
+
const options = {
|
|
18
|
+
title: data.title,
|
|
19
|
+
description: data.description,
|
|
20
|
+
"external-ref": data.file,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const issue = await $<issues.Issue>`bd create --type epic ${options} --json`.json();
|
|
24
|
+
|
|
25
|
+
return issue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function update(
|
|
29
|
+
client: shell.client.ClientInput,
|
|
30
|
+
input: { id: string },
|
|
31
|
+
data: SpecificationInput,
|
|
32
|
+
) {
|
|
33
|
+
const $ = shell.client.use(client);
|
|
34
|
+
|
|
35
|
+
const options = {
|
|
36
|
+
title: data.title,
|
|
37
|
+
description: data.description,
|
|
38
|
+
"external-ref": data.file,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const _issues = await $<
|
|
42
|
+
issues.Issue[]
|
|
43
|
+
>`bd update ${input.id} --type epic ${options} --json`.json();
|
|
44
|
+
|
|
45
|
+
const [issue] = _issues;
|
|
46
|
+
assert(issue, `Issue '${input.id}' not found`);
|
|
47
|
+
|
|
48
|
+
return issue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export namespace find {
|
|
52
|
+
export function byExternalRef(client: shell.client.ClientInput, ref: string) {
|
|
53
|
+
return issues.find.byExternalRef(client, ref, { type: "epic" });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { $ } from "bun";
|
|
2
|
+
import type { OpencodeClient, Worktree } from "@opencode-ai/sdk/v2/client";
|
|
3
|
+
|
|
4
|
+
import * as polling from "../../utils/polling";
|
|
5
|
+
|
|
6
|
+
import * as worktrees from "./worktrees";
|
|
7
|
+
|
|
8
|
+
export class WorkerEnvironment {
|
|
9
|
+
public readonly ready: Promise<boolean>;
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly client: OpencodeClient,
|
|
13
|
+
private readonly directory: string,
|
|
14
|
+
public readonly worktree: Worktree,
|
|
15
|
+
) {
|
|
16
|
+
this.ready = polling.waitFor(() => worktrees.isReady(worktree), {
|
|
17
|
+
interval: "100ms",
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public get $() {
|
|
22
|
+
return $.cwd(this.worktree.directory);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static async init(options: worktrees.InitOptions) {
|
|
26
|
+
const worktree = await worktrees.init(options);
|
|
27
|
+
|
|
28
|
+
const env = new WorkerEnvironment(options.client, options.directory, worktree);
|
|
29
|
+
await env.ready;
|
|
30
|
+
|
|
31
|
+
return env;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async [Symbol.asyncDispose]() {
|
|
35
|
+
await worktrees
|
|
36
|
+
.remove({
|
|
37
|
+
client: this.client,
|
|
38
|
+
directory: this.directory,
|
|
39
|
+
worktreeDirectory: this.worktree.directory,
|
|
40
|
+
})
|
|
41
|
+
.catch((error) => console.error(error));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { OpencodeClient } from "@opencode-ai/sdk/v2/client";
|
|
2
|
+
import { prompt } from "@bunli/utils";
|
|
3
|
+
import { assert, Semaphore } from "radashi";
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
|
|
6
|
+
import * as projects from "../../utils/projects";
|
|
7
|
+
|
|
8
|
+
const semaphore = new Semaphore(1);
|
|
9
|
+
|
|
10
|
+
export interface InitOptions {
|
|
11
|
+
client: OpencodeClient;
|
|
12
|
+
directory: string;
|
|
13
|
+
name: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function init(options: InitOptions) {
|
|
17
|
+
const { client, directory } = options;
|
|
18
|
+
|
|
19
|
+
const permit = await semaphore.acquire();
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const project = await client.project.current({ directory });
|
|
23
|
+
assert(project.data, `Failed to initialize environment: ${project.error}`);
|
|
24
|
+
|
|
25
|
+
const projectLabel = projects.getProjectLabel(project.data);
|
|
26
|
+
|
|
27
|
+
if (!project.data.commands?.start) {
|
|
28
|
+
const shouldContinue = await prompt.confirm(
|
|
29
|
+
`Opencode project ${projectLabel} does not have a start command. Do you want to continue?`,
|
|
30
|
+
{ default: false },
|
|
31
|
+
);
|
|
32
|
+
assert(shouldContinue, `Failed to initialize environment: user asked to stop`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const worktree = await client.worktree.create({
|
|
36
|
+
directory,
|
|
37
|
+
worktreeCreateInput: {
|
|
38
|
+
name: options.name,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
assert(worktree.data, `Failed to initialize worktree: ${JSON.stringify(worktree.error)}`);
|
|
42
|
+
|
|
43
|
+
return worktree.data;
|
|
44
|
+
} finally {
|
|
45
|
+
permit.release();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface RemoveOptions {
|
|
50
|
+
client: OpencodeClient;
|
|
51
|
+
directory: string;
|
|
52
|
+
worktreeDirectory: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function remove(options: RemoveOptions) {
|
|
56
|
+
const { client, directory } = options;
|
|
57
|
+
|
|
58
|
+
const worktree = await client.worktree.remove({
|
|
59
|
+
directory,
|
|
60
|
+
worktreeRemoveInput: {
|
|
61
|
+
directory: options.worktreeDirectory,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
assert(worktree.data, `Failed to remove worktree: ${JSON.stringify(worktree.error)}`);
|
|
65
|
+
|
|
66
|
+
console.log("Worktree removed");
|
|
67
|
+
|
|
68
|
+
return worktree.data;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function isReady(options: { directory: string }) {
|
|
72
|
+
const existings = await Promise.all([
|
|
73
|
+
fs.exists(`${options.directory}/.opencode`),
|
|
74
|
+
fs.exists(`${options.directory}/.git`),
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
return existings.every((exists) => exists);
|
|
78
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Session } from "@opencode-ai/sdk";
|
|
2
|
+
|
|
3
|
+
const ID_TO_TEAMMATE = new Map<string, string>();
|
|
4
|
+
|
|
5
|
+
export function get(sessionId: string) {
|
|
6
|
+
return ID_TO_TEAMMATE.get(sessionId);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function createFromSession(session: Session) {
|
|
10
|
+
const teammate = "slug" in session ? (session.slug as string) : session.id;
|
|
11
|
+
|
|
12
|
+
ID_TO_TEAMMATE.set(session.id, teammate);
|
|
13
|
+
|
|
14
|
+
return teammate;
|
|
15
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Bridge between human specs and the codebase through an implementation plan stored in Beads.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: github-copilot/claude-sonnet-4.5
|
|
5
|
+
temperature: 0
|
|
6
|
+
tools:
|
|
7
|
+
write: false
|
|
8
|
+
edit: false
|
|
9
|
+
patch: false
|
|
10
|
+
question: false
|
|
11
|
+
permissions:
|
|
12
|
+
bash:
|
|
13
|
+
"*": deny
|
|
14
|
+
"bd *": allow
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Planner
|
|
18
|
+
|
|
19
|
+
You are a non-interactive subagent responsible for reconciling the Beads implementation plan with the current state of a specification. You receive a Beads Epic ID as input and ensure the implementation tasks are synchronized with the related specification.
|
|
20
|
+
|
|
21
|
+
<user_prompt>
|
|
22
|
+
$ARGUMENTS
|
|
23
|
+
</user_prompt>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Phase 1: Context Acquisition
|
|
28
|
+
|
|
29
|
+
### 1.1 Load Epic Details
|
|
30
|
+
|
|
31
|
+
Retrieve the Epic and its current children:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bd show <epic-id> --json
|
|
35
|
+
bd list --parent=<epic-id> --json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Extract from the Epic description:
|
|
39
|
+
|
|
40
|
+
- **Spec Reference**: The path to the related specification file (e.g., `specs/<filename>.md`)
|
|
41
|
+
|
|
42
|
+
### 1.2 Read Current Specification
|
|
43
|
+
|
|
44
|
+
Read the specification file referenced in the Epic to understand the current requirements.
|
|
45
|
+
|
|
46
|
+
### 1.3 Identify Changes
|
|
47
|
+
|
|
48
|
+
Compare the current specification against existing tasks:
|
|
49
|
+
|
|
50
|
+
- New requirements not covered by existing tasks
|
|
51
|
+
- Removed requirements with orphaned tasks
|
|
52
|
+
- Modified requirements requiring task updates
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Phase 2: Design Implementation Tasks
|
|
57
|
+
|
|
58
|
+
Break down specifications into **atomic implementation tasks** suitable for single agent sessions.
|
|
59
|
+
|
|
60
|
+
### 2.1 Task Design Criteria
|
|
61
|
+
|
|
62
|
+
Each task MUST satisfy ALL of the following:
|
|
63
|
+
|
|
64
|
+
- **Small Scope**: Completable in a single agent session (1-3 hours of focused work)
|
|
65
|
+
- **Clear I/O**: Explicit inputs (files to read, dependencies) and outputs (files created/modified, tests passing)
|
|
66
|
+
- **Testable**: Clear verification path (unit tests, integration tests, or manual verification steps)
|
|
67
|
+
- **File-Aware**: Include specific file paths when known (e.g., "Create `src/core/event_emitter.py`")
|
|
68
|
+
- **Self-Contained**: Understandable without reading other tasks
|
|
69
|
+
|
|
70
|
+
### 2.2 Task Description Structure
|
|
71
|
+
|
|
72
|
+
Each task description should follow this format:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
**Goal**: [1-2 sentence summary of what this accomplishes]
|
|
76
|
+
|
|
77
|
+
**Files to Create/Modify**:
|
|
78
|
+
- path/to/file1.py
|
|
79
|
+
- path/to/file2.py
|
|
80
|
+
|
|
81
|
+
**Implementation**:
|
|
82
|
+
[Detailed breakdown including:]
|
|
83
|
+
- Key functions/classes to create
|
|
84
|
+
- Important algorithms or logic flows
|
|
85
|
+
- Integration points with existing code
|
|
86
|
+
|
|
87
|
+
**Acceptance**:
|
|
88
|
+
[Clear verification criteria:]
|
|
89
|
+
- Unit tests pass: [specific test names or scenarios]
|
|
90
|
+
- Manual verification: [specific steps if needed]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2.3 Task Breakdown Strategy
|
|
94
|
+
|
|
95
|
+
When analyzing a specification, break it down following this hierarchy:
|
|
96
|
+
|
|
97
|
+
1. **Infrastructure First**: Test mocks, configuration, base classes
|
|
98
|
+
2. **Core Logic**: Main algorithms, data structures, business logic
|
|
99
|
+
3. **Integration**: Connect components together
|
|
100
|
+
4. **Validation**: Tests, error handling, edge cases
|
|
101
|
+
5. **Polish**: Documentation, logging, refinements
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Phase 3: Execute Reconciliation
|
|
106
|
+
|
|
107
|
+
**🚨 CRITICAL**: ALL tasks MUST be created with `--parent <epic-id>` flag to establish Epic hierarchy.
|
|
108
|
+
|
|
109
|
+
### 3.1 Create New Tasks
|
|
110
|
+
|
|
111
|
+
For each new requirement identified:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
bd create --title "<Task Title>" --type task --parent <epic-id> --description "<description>"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3.2 Update Modified Tasks
|
|
118
|
+
|
|
119
|
+
For tasks requiring updates:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
bd update <task-id> --description "<updated-description>"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 3.3 Close Deprecated Tasks
|
|
126
|
+
|
|
127
|
+
For requirements that have been removed:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
bd close <task-id> --reason "Requirement removed from specification"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 3.4 Manage Dependencies
|
|
134
|
+
|
|
135
|
+
Link task dependencies:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bd dep add <blocked-task> <blocker-task>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Phase 4: Report Changes
|
|
144
|
+
|
|
145
|
+
Output a clear summary of all changes made:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
## Reconciliation Summary for Epic: <epic-id>
|
|
149
|
+
|
|
150
|
+
**Specification**: specs/<filename>.md
|
|
151
|
+
|
|
152
|
+
### Tasks:
|
|
153
|
+
|
|
154
|
+
#### 1. [Task Title] (Priority: P1)
|
|
155
|
+
- **Goal**: [What this accomplishes]
|
|
156
|
+
- **Dependencies**: [None | Blocked by: Task X]
|
|
157
|
+
|
|
158
|
+
#### 2. [Task Title] (Priority: P2)
|
|
159
|
+
- **Goal**: [What this accomplishes]
|
|
160
|
+
- **Dependencies**: [Blocked by: Task 1]
|
|
161
|
+
|
|
162
|
+
[Continue for all tasks...]
|
|
163
|
+
|
|
164
|
+
### Tasks Closed:
|
|
165
|
+
- `<task-id>`: <task-title> — <reason for closure>
|
|
166
|
+
|
|
167
|
+
### Task Dependency Graph:
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Task 1 (Infrastructure)
|
|
171
|
+
↓
|
|
172
|
+
Task 2 (Core Logic) → Task 3 (Core Logic)
|
|
173
|
+
↓ ↓
|
|
174
|
+
Task 4 (Integration) ←---┘
|
|
175
|
+
↓
|
|
176
|
+
Task 5 (Validation)
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### No Changes:
|
|
181
|
+
[If no changes were needed, state: "Implementation plan is already in sync with specification."]
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Key Principles
|
|
187
|
+
|
|
188
|
+
- **Specs are the WHAT:** Requirements, user scenarios, success criteria
|
|
189
|
+
- **Beads are the HOW:** Implementation tasks, technical breakdown, execution order
|
|
190
|
+
- **Non-Interactive**: Execute reconciliation without user prompts
|
|
191
|
+
- **Epic Hierarchy**: ALWAYS use `--parent <epic-id>` when creating tasks
|
|
192
|
+
- **Traceability**: The Epic contains the spec reference; child tasks don't need to repeat it
|
|
193
|
+
- **Be Atomic**: Tasks should be independently completable and testable
|
|
194
|
+
- **Think Dependencies**: Make blocking relationships explicit in the task graph
|
|
195
|
+
- **Use `bd update`**: NEVER use `bd edit` — always use `bd update` for modifications
|
|
196
|
+
- **Report Clearly**: Output a concise summary of all changes made
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brainstorm
|
|
3
|
+
model: github-copilot/claude-sonnet-4.5
|
|
4
|
+
agent: plan
|
|
5
|
+
description: "Help turn ideas into fully formed designs and specs through natural collaborative dialogue."
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Brainstorming Ideas Into Designs
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
|
|
13
|
+
|
|
14
|
+
Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design in small sections (200-300 words), checking after each section whether it looks right so far.
|
|
15
|
+
|
|
16
|
+
<brainstorming_subject>
|
|
17
|
+
$ARGUMENTS
|
|
18
|
+
</brainstorming_subject>
|
|
19
|
+
|
|
20
|
+
## 1. The Process
|
|
21
|
+
|
|
22
|
+
**Understanding the idea:**
|
|
23
|
+
|
|
24
|
+
- Check out the current project state first (files, docs, recent commits): use the @codebase-analyser to get advanced insights on the codebase
|
|
25
|
+
- Ask questions one at a time to refine the idea
|
|
26
|
+
- Prefer multiple choice questions when possible, but open-ended is fine too
|
|
27
|
+
- Only one question per message - if a topic needs more exploration, break it into multiple questions
|
|
28
|
+
- Focus on understanding: purpose, constraints, success criteria
|
|
29
|
+
- Reply to the user's question: bidirectional flow helps both parties to align on the idea
|
|
30
|
+
|
|
31
|
+
**Exploring approaches:**
|
|
32
|
+
|
|
33
|
+
- Propose 2-3 different approaches with trade-offs
|
|
34
|
+
- Present options conversationally with your recommendation and reasoning
|
|
35
|
+
- Lead with your recommended option and explain why
|
|
36
|
+
|
|
37
|
+
**Presenting the design:**
|
|
38
|
+
|
|
39
|
+
- Once you believe you understand what you're building, present the design
|
|
40
|
+
- Break it into sections of 200-300 words
|
|
41
|
+
- Ask after each section whether it looks right so far
|
|
42
|
+
- Cover: architecture, components, data flow, error handling, testing
|
|
43
|
+
- Be ready to go back and clarify if something doesn't make sense
|
|
44
|
+
|
|
45
|
+
## 2. The Design Redaction
|
|
46
|
+
|
|
47
|
+
**Documentation:**
|
|
48
|
+
|
|
49
|
+
- Write the validated design to `specs/thoughts/YYYY-MM-DD-<topic>.md`
|
|
50
|
+
- Use elements-of-style:writing-clearly-and-concisely skill if available
|
|
51
|
+
- Commit the design document to git
|
|
52
|
+
|
|
53
|
+
## Key Principles
|
|
54
|
+
|
|
55
|
+
- **One question at a time** - Don't overwhelm with multiple questions
|
|
56
|
+
- **Multiple choice preferred** - Easier to answer than open-ended when possible
|
|
57
|
+
- **YAGNI ruthlessly** - Remove unnecessary features from all designs
|
|
58
|
+
- **Explore alternatives** - Always propose 2-3 approaches before settling
|
|
59
|
+
- **Incremental validation** - Present design in sections, validate each
|
|
60
|
+
- **Be flexible** - Go back and clarify when something doesn't make sense
|