@fledge/workflow 0.6.3 → 0.7.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/dist/scripts/brief.js +113 -50
- package/package.json +2 -2
- package/skills/brief/SKILL.md +53 -31
package/dist/scripts/brief.js
CHANGED
|
@@ -554,7 +554,6 @@ const string$1 = (params) => {
|
|
|
554
554
|
const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
|
|
555
555
|
return new RegExp(`^${regex}$`);
|
|
556
556
|
};
|
|
557
|
-
const boolean$1 = /^(?:true|false)$/i;
|
|
558
557
|
const lowercase = /^[^A-Z]*$/;
|
|
559
558
|
const uppercase = /^[^a-z]*$/;
|
|
560
559
|
//#endregion
|
|
@@ -1166,24 +1165,6 @@ const $ZodJWT = /* @__PURE__ */ $constructor("$ZodJWT", (inst, def) => {
|
|
|
1166
1165
|
});
|
|
1167
1166
|
};
|
|
1168
1167
|
});
|
|
1169
|
-
const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
|
|
1170
|
-
$ZodType.init(inst, def);
|
|
1171
|
-
inst._zod.pattern = boolean$1;
|
|
1172
|
-
inst._zod.parse = (payload, _ctx) => {
|
|
1173
|
-
if (def.coerce) try {
|
|
1174
|
-
payload.value = Boolean(payload.value);
|
|
1175
|
-
} catch (_) {}
|
|
1176
|
-
const input = payload.value;
|
|
1177
|
-
if (typeof input === "boolean") return payload;
|
|
1178
|
-
payload.issues.push({
|
|
1179
|
-
expected: "boolean",
|
|
1180
|
-
code: "invalid_type",
|
|
1181
|
-
input,
|
|
1182
|
-
inst
|
|
1183
|
-
});
|
|
1184
|
-
return payload;
|
|
1185
|
-
};
|
|
1186
|
-
});
|
|
1187
1168
|
const $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
|
|
1188
1169
|
$ZodType.init(inst, def);
|
|
1189
1170
|
inst._zod.parse = (payload) => payload;
|
|
@@ -2146,13 +2127,6 @@ function _isoDuration(Class, params) {
|
|
|
2146
2127
|
});
|
|
2147
2128
|
}
|
|
2148
2129
|
/* @__NO_SIDE_EFFECTS__ */
|
|
2149
|
-
function _boolean(Class, params) {
|
|
2150
|
-
return new Class({
|
|
2151
|
-
type: "boolean",
|
|
2152
|
-
...normalizeParams(params)
|
|
2153
|
-
});
|
|
2154
|
-
}
|
|
2155
|
-
/* @__NO_SIDE_EFFECTS__ */
|
|
2156
2130
|
function _unknown(Class) {
|
|
2157
2131
|
return new Class({ type: "unknown" });
|
|
2158
2132
|
}
|
|
@@ -3336,14 +3310,6 @@ const ZodJWT = /* @__PURE__ */ $constructor("ZodJWT", (inst, def) => {
|
|
|
3336
3310
|
$ZodJWT.init(inst, def);
|
|
3337
3311
|
ZodStringFormat.init(inst, def);
|
|
3338
3312
|
});
|
|
3339
|
-
const ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
|
|
3340
|
-
$ZodBoolean.init(inst, def);
|
|
3341
|
-
ZodType.init(inst, def);
|
|
3342
|
-
inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
|
|
3343
|
-
});
|
|
3344
|
-
function boolean(params) {
|
|
3345
|
-
return /* @__PURE__ */ _boolean(ZodBoolean, params);
|
|
3346
|
-
}
|
|
3347
3313
|
const ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
|
|
3348
3314
|
$ZodUnknown.init(inst, def);
|
|
3349
3315
|
ZodType.init(inst, def);
|
|
@@ -3650,8 +3616,10 @@ function superRefine(fn) {
|
|
|
3650
3616
|
//#region ../cli/dist/schemas/brief.js
|
|
3651
3617
|
const briefStatus = _enum([
|
|
3652
3618
|
"draft",
|
|
3619
|
+
"ready",
|
|
3653
3620
|
"active",
|
|
3654
|
-
"completed"
|
|
3621
|
+
"completed",
|
|
3622
|
+
"cancelled"
|
|
3655
3623
|
]);
|
|
3656
3624
|
const briefFrontmatter = object({
|
|
3657
3625
|
name: string().min(1),
|
|
@@ -3663,16 +3631,36 @@ const briefFrontmatter = object({
|
|
|
3663
3631
|
/**
|
|
3664
3632
|
* Valid state transitions for a brief.
|
|
3665
3633
|
* Each key maps to the set of states it can transition to.
|
|
3634
|
+
*
|
|
3635
|
+
* draft → ready: brief skill marks the brief as designed and enriched
|
|
3636
|
+
* ready → active: implement skill begins implementation
|
|
3637
|
+
* ready → draft: brief needs rework
|
|
3638
|
+
* active → completed: implement skill finishes all tasks
|
|
3639
|
+
* draft/ready/active → cancelled: feature is dropped
|
|
3666
3640
|
*/
|
|
3667
3641
|
const briefTransitions = {
|
|
3668
|
-
draft: ["
|
|
3669
|
-
|
|
3670
|
-
|
|
3642
|
+
draft: ["ready", "cancelled"],
|
|
3643
|
+
ready: [
|
|
3644
|
+
"active",
|
|
3645
|
+
"draft",
|
|
3646
|
+
"cancelled"
|
|
3647
|
+
],
|
|
3648
|
+
active: ["completed", "cancelled"],
|
|
3649
|
+
completed: [],
|
|
3650
|
+
cancelled: []
|
|
3671
3651
|
};
|
|
3652
|
+
//#endregion
|
|
3653
|
+
//#region ../cli/dist/schemas/tasks.js
|
|
3654
|
+
const taskStatus = _enum([
|
|
3655
|
+
"pending",
|
|
3656
|
+
"active",
|
|
3657
|
+
"completed",
|
|
3658
|
+
"skipped"
|
|
3659
|
+
]);
|
|
3672
3660
|
const tasksFrontmatter = object({ tasks: array(object({
|
|
3673
3661
|
name: string().min(1),
|
|
3674
3662
|
group: string().min(1).optional(),
|
|
3675
|
-
|
|
3663
|
+
status: taskStatus.default("pending")
|
|
3676
3664
|
})) });
|
|
3677
3665
|
//#endregion
|
|
3678
3666
|
//#region ../cli/dist/brief.js
|
|
@@ -3726,6 +3714,16 @@ function getTasksFile(context, name) {
|
|
|
3726
3714
|
return path.join(getBriefDirectory(context, name), "tasks.md");
|
|
3727
3715
|
}
|
|
3728
3716
|
/**
|
|
3717
|
+
* Returns the absolute path to a brief's `spec.md` file.
|
|
3718
|
+
*
|
|
3719
|
+
* @param context - The brief context.
|
|
3720
|
+
* @param name - The brief name.
|
|
3721
|
+
* @returns The absolute path to `spec.md`.
|
|
3722
|
+
*/
|
|
3723
|
+
function getSpecFile(context, name) {
|
|
3724
|
+
return path.join(getBriefDirectory(context, name), "spec.md");
|
|
3725
|
+
}
|
|
3726
|
+
/**
|
|
3729
3727
|
* Checks whether a brief directory exists.
|
|
3730
3728
|
*
|
|
3731
3729
|
* @param context - The brief context.
|
|
@@ -3815,6 +3813,35 @@ const projectDirectory = {
|
|
|
3815
3813
|
description: "Project root directory. Overrides cwd() for locating .fledge/briefs/."
|
|
3816
3814
|
};
|
|
3817
3815
|
//#endregion
|
|
3816
|
+
//#region ../cli/dist/commands/brief/cancel.js
|
|
3817
|
+
var cancel_default = defineCommand({
|
|
3818
|
+
meta: {
|
|
3819
|
+
name: "cancel",
|
|
3820
|
+
description: "Cancel a brief"
|
|
3821
|
+
},
|
|
3822
|
+
args: {
|
|
3823
|
+
name: {
|
|
3824
|
+
type: "positional",
|
|
3825
|
+
required: true,
|
|
3826
|
+
description: "The name of the brief to cancel"
|
|
3827
|
+
},
|
|
3828
|
+
projectDirectory
|
|
3829
|
+
},
|
|
3830
|
+
run(context) {
|
|
3831
|
+
const ctx = createBriefContext(context.args.projectDirectory);
|
|
3832
|
+
const { name } = context.args;
|
|
3833
|
+
if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
|
|
3834
|
+
const brief = readBriefFrontmatter(ctx, name);
|
|
3835
|
+
validateTransition(brief.status, "cancelled");
|
|
3836
|
+
updateBriefFrontmatter(ctx, name, {
|
|
3837
|
+
...brief,
|
|
3838
|
+
status: "cancelled",
|
|
3839
|
+
updated: formatDate()
|
|
3840
|
+
});
|
|
3841
|
+
stdout.write(`Brief "${name}" has been cancelled\n`);
|
|
3842
|
+
}
|
|
3843
|
+
});
|
|
3844
|
+
//#endregion
|
|
3818
3845
|
//#region ../cli/dist/commands/brief/complete.js
|
|
3819
3846
|
var complete_default = defineCommand({
|
|
3820
3847
|
meta: {
|
|
@@ -3836,10 +3863,10 @@ var complete_default = defineCommand({
|
|
|
3836
3863
|
const brief = readBriefFrontmatter(ctx, name);
|
|
3837
3864
|
validateTransition(brief.status, "completed");
|
|
3838
3865
|
if (!brief.summary) throw new Error("Brief must have a summary before completing. Add a \"summary\" field to the brief.md frontmatter.");
|
|
3839
|
-
const incomplete = readTasksFrontmatter(ctx, name).tasks.filter((task) =>
|
|
3866
|
+
const incomplete = readTasksFrontmatter(ctx, name).tasks.filter((task) => task.status !== "completed" && task.status !== "skipped");
|
|
3840
3867
|
if (incomplete.length > 0) {
|
|
3841
|
-
const names = incomplete.map((task) => ` - ${task.name}`).join("\n");
|
|
3842
|
-
throw new Error(`Cannot complete brief with ${incomplete.length}
|
|
3868
|
+
const names = incomplete.map((task) => ` - ${task.name} [${task.status}]`).join("\n");
|
|
3869
|
+
throw new Error(`Cannot complete brief with ${incomplete.length} unfinished task(s):\n${names}`);
|
|
3843
3870
|
}
|
|
3844
3871
|
updateBriefFrontmatter(ctx, name, {
|
|
3845
3872
|
...brief,
|
|
@@ -3878,6 +3905,7 @@ var create_default = defineCommand({
|
|
|
3878
3905
|
updated: date
|
|
3879
3906
|
}));
|
|
3880
3907
|
fs.writeFileSync(getTasksFile(ctx, name), writeFrontmatter({ tasks: [] }));
|
|
3908
|
+
fs.writeFileSync(getSpecFile(ctx, name), "");
|
|
3881
3909
|
stdout.write(`Created brief "${name}" at "${directory}"\n`);
|
|
3882
3910
|
}
|
|
3883
3911
|
});
|
|
@@ -3892,7 +3920,7 @@ var list_default = defineCommand({
|
|
|
3892
3920
|
status: {
|
|
3893
3921
|
type: "string",
|
|
3894
3922
|
required: false,
|
|
3895
|
-
description: "Filter by brief status (draft, active, completed)"
|
|
3923
|
+
description: "Filter by brief status (draft, ready, active, completed, cancelled)"
|
|
3896
3924
|
},
|
|
3897
3925
|
projectDirectory
|
|
3898
3926
|
},
|
|
@@ -3906,7 +3934,7 @@ var list_default = defineCommand({
|
|
|
3906
3934
|
let briefs = names.map((name) => {
|
|
3907
3935
|
const brief = readBriefFrontmatter(ctx, name);
|
|
3908
3936
|
const { tasks } = readTasksFrontmatter(ctx, name);
|
|
3909
|
-
const done = tasks.filter((task) => task.
|
|
3937
|
+
const done = tasks.filter((task) => task.status === "completed" || task.status === "skipped").length;
|
|
3910
3938
|
return {
|
|
3911
3939
|
...brief,
|
|
3912
3940
|
tasksDone: done,
|
|
@@ -3934,6 +3962,35 @@ var list_default = defineCommand({
|
|
|
3934
3962
|
}
|
|
3935
3963
|
});
|
|
3936
3964
|
//#endregion
|
|
3965
|
+
//#region ../cli/dist/commands/brief/ready.js
|
|
3966
|
+
var ready_default = defineCommand({
|
|
3967
|
+
meta: {
|
|
3968
|
+
name: "ready",
|
|
3969
|
+
description: "Transition a brief from draft to ready"
|
|
3970
|
+
},
|
|
3971
|
+
args: {
|
|
3972
|
+
name: {
|
|
3973
|
+
type: "positional",
|
|
3974
|
+
required: true,
|
|
3975
|
+
description: "The name of the brief to mark as ready"
|
|
3976
|
+
},
|
|
3977
|
+
projectDirectory
|
|
3978
|
+
},
|
|
3979
|
+
run(context) {
|
|
3980
|
+
const ctx = createBriefContext(context.args.projectDirectory);
|
|
3981
|
+
const { name } = context.args;
|
|
3982
|
+
if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
|
|
3983
|
+
const brief = readBriefFrontmatter(ctx, name);
|
|
3984
|
+
validateTransition(brief.status, "ready");
|
|
3985
|
+
updateBriefFrontmatter(ctx, name, {
|
|
3986
|
+
...brief,
|
|
3987
|
+
status: "ready",
|
|
3988
|
+
updated: formatDate()
|
|
3989
|
+
});
|
|
3990
|
+
stdout.write(`Brief "${name}" is ready for implementation\n`);
|
|
3991
|
+
}
|
|
3992
|
+
});
|
|
3993
|
+
//#endregion
|
|
3937
3994
|
//#region ../cli/dist/commands/brief/schema.js
|
|
3938
3995
|
var schema_default = defineCommand({
|
|
3939
3996
|
meta: {
|
|
@@ -3953,7 +4010,7 @@ var schema_default = defineCommand({
|
|
|
3953
4010
|
var start_default = defineCommand({
|
|
3954
4011
|
meta: {
|
|
3955
4012
|
name: "start",
|
|
3956
|
-
description: "Transition a brief from
|
|
4013
|
+
description: "Transition a brief from ready to active"
|
|
3957
4014
|
},
|
|
3958
4015
|
args: {
|
|
3959
4016
|
name: {
|
|
@@ -3969,7 +4026,6 @@ var start_default = defineCommand({
|
|
|
3969
4026
|
if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
|
|
3970
4027
|
const brief = readBriefFrontmatter(ctx, name);
|
|
3971
4028
|
validateTransition(brief.status, "active");
|
|
3972
|
-
if (readTasksFrontmatter(ctx, name).tasks.length === 0) throw new Error("Brief must have at least one task before starting");
|
|
3973
4029
|
updateBriefFrontmatter(ctx, name, {
|
|
3974
4030
|
...brief,
|
|
3975
4031
|
status: "active",
|
|
@@ -3997,13 +4053,18 @@ function groupTasks(tasks) {
|
|
|
3997
4053
|
return groups;
|
|
3998
4054
|
}
|
|
3999
4055
|
/**
|
|
4000
|
-
*
|
|
4056
|
+
* Maps a task status to a display indicator.
|
|
4001
4057
|
*
|
|
4002
4058
|
* @param task - The task to format.
|
|
4003
|
-
* @returns The formatted task string.
|
|
4059
|
+
* @returns The formatted task string with status indicator.
|
|
4004
4060
|
*/
|
|
4005
4061
|
function formatTask(task) {
|
|
4006
|
-
return ` ${
|
|
4062
|
+
return ` ${{
|
|
4063
|
+
pending: "[ ]",
|
|
4064
|
+
active: "[~]",
|
|
4065
|
+
completed: "[x]",
|
|
4066
|
+
skipped: "[-]"
|
|
4067
|
+
}[task.status] ?? "[ ]"} ${task.name}`;
|
|
4007
4068
|
}
|
|
4008
4069
|
//#endregion
|
|
4009
4070
|
//#region ../cli/dist/run-brief.js
|
|
@@ -4013,9 +4074,11 @@ runMain(defineCommand({
|
|
|
4013
4074
|
description: "Manage feature briefs"
|
|
4014
4075
|
},
|
|
4015
4076
|
subCommands: {
|
|
4077
|
+
cancel: cancel_default,
|
|
4016
4078
|
complete: complete_default,
|
|
4017
4079
|
create: create_default,
|
|
4018
4080
|
list: list_default,
|
|
4081
|
+
ready: ready_default,
|
|
4019
4082
|
schema: schema_default,
|
|
4020
4083
|
start: start_default,
|
|
4021
4084
|
status: defineCommand({
|
|
@@ -4037,7 +4100,7 @@ runMain(defineCommand({
|
|
|
4037
4100
|
if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
|
|
4038
4101
|
const brief = readBriefFrontmatter(ctx, name);
|
|
4039
4102
|
const { tasks } = readTasksFrontmatter(ctx, name);
|
|
4040
|
-
const done = tasks.filter((task) => task.
|
|
4103
|
+
const done = tasks.filter((task) => task.status === "completed" || task.status === "skipped").length;
|
|
4041
4104
|
const lines = [];
|
|
4042
4105
|
lines.push(`${name} [${brief.status}] ${done}/${tasks.length} tasks done`);
|
|
4043
4106
|
lines.push("");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fledge/workflow",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"author": "René Schapka",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"files": [
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"node": ">=24"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@fledge/cli": "^0.
|
|
18
|
+
"@fledge/cli": "^0.10.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@antfu/eslint-config": "7.7.3",
|
package/skills/brief/SKILL.md
CHANGED
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fledge-brief
|
|
3
3
|
description: >-
|
|
4
|
-
Guide feature brief creation and lifecycle. Plan new features, create or update feature briefs,
|
|
4
|
+
Guide feature brief creation and lifecycle. Plan new features, create or update feature briefs, enrich with project knowledge, or complete a feature.
|
|
5
5
|
Invoked directly via /fledge-brief, not auto-triggered.
|
|
6
6
|
metadata:
|
|
7
7
|
type: workflow
|
|
8
|
-
allowed-tools: Bash(node *scripts/brief.js
|
|
8
|
+
allowed-tools: Bash(node *scripts/brief.js*)
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
## Lifecycle overview
|
|
12
|
+
|
|
13
|
+
The brief skill owns two workflow phases: **Brief** (capture what to build) and **Enrich** (connect to project knowledge). See [docs/workflow.md](../../docs/workflow.md) for the full workflow.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Brief → Enrich → [Implement] → [Verify] → [Complete]
|
|
17
|
+
└── this skill ──┘ └── implement skill (future) ──────────┘
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**States this skill manages:** `draft → ready`
|
|
21
|
+
**States managed by the implement skill:** `ready → active → completed`
|
|
22
|
+
|
|
23
|
+
A brief directory contains three files:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
.fledge/briefs/<name>/
|
|
27
|
+
brief.md what, why, scope, design decisions (product-level)
|
|
28
|
+
spec.md data models, APIs, external services (technical context)
|
|
29
|
+
tasks.md implementation tasks (empty until implement phase)
|
|
30
|
+
```
|
|
31
|
+
|
|
11
32
|
## Available scripts
|
|
12
33
|
|
|
13
34
|
**Important:** Run all scripts with `node` (e.g. `node scripts/brief.js list`). Always pass `--project-dir` pointing to the project root.
|
|
14
35
|
|
|
15
36
|
- **`node scripts/brief.js create <name> --project-dir <path>`** -- Create a new brief with stub files
|
|
16
|
-
- **`node scripts/brief.js
|
|
37
|
+
- **`node scripts/brief.js ready <name> --project-dir <path>`** -- Transition a brief from draft to ready
|
|
38
|
+
- **`node scripts/brief.js start <name> --project-dir <path>`** -- Transition a brief from ready to active
|
|
17
39
|
- **`node scripts/brief.js complete <name> --project-dir <path>`** -- Transition a brief from active to completed
|
|
40
|
+
- **`node scripts/brief.js cancel <name> --project-dir <path>`** -- Cancel a brief
|
|
18
41
|
- **`node scripts/brief.js status <name> --project-dir <path>`** -- Show status and task progress
|
|
19
42
|
- **`node scripts/brief.js list [--status <status>] --project-dir <path>`** -- List all briefs with progress and summary
|
|
20
43
|
- **`node scripts/brief.js validate <name> --project-dir <path>`** -- Validate brief files against schemas
|
|
@@ -25,8 +48,8 @@ allowed-tools: Bash(node *scripts/brief.js *)
|
|
|
25
48
|
Ask what the user wants to do, or infer from context. Present these options:
|
|
26
49
|
|
|
27
50
|
1. **New brief** -- plan a new feature from scratch. Proceed to Step 1.
|
|
28
|
-
2. **Continue a brief** -- pick up an existing brief. Proceed to Step
|
|
29
|
-
3. **Complete a brief** -- wrap up a finished feature. Proceed to Step
|
|
51
|
+
2. **Continue a brief** -- pick up an existing brief. Proceed to Step 5.
|
|
52
|
+
3. **Complete a brief** -- wrap up a finished feature. Proceed to Step 6.
|
|
30
53
|
|
|
31
54
|
If unclear, run `node scripts/brief.js list --project-dir <path>` to show current briefs and ask.
|
|
32
55
|
|
|
@@ -66,59 +89,58 @@ Proceed to Step 3.
|
|
|
66
89
|
|
|
67
90
|
---
|
|
68
91
|
|
|
69
|
-
## Step 3:
|
|
92
|
+
## Step 3: Enrich with project knowledge
|
|
70
93
|
|
|
71
|
-
|
|
94
|
+
Connect the brief to the technical reality of the project. Read the codebase and project knowledge sources to understand:
|
|
72
95
|
|
|
73
|
-
- **
|
|
74
|
-
- **
|
|
75
|
-
- **
|
|
96
|
+
- **Data models**: what existing models does the feature interact with? What new models are needed?
|
|
97
|
+
- **APIs**: what endpoints exist? What new endpoints are needed?
|
|
98
|
+
- **External services**: what third-party integrations are involved?
|
|
99
|
+
- **Domain concepts**: what domain terms and relationships are relevant?
|
|
76
100
|
|
|
77
|
-
Write the tasks
|
|
101
|
+
Write this technical context into `spec.md`. The spec grounds the product-level brief in the project's actual structure. It does **not** include implementation tasks or technology-specific guidance (those come from the implement skill and technology skills).
|
|
102
|
+
|
|
103
|
+
Proceed to Step 4.
|
|
78
104
|
|
|
79
|
-
```yaml
|
|
80
|
-
---
|
|
81
|
-
tasks:
|
|
82
|
-
- name: <clear, actionable task name>
|
|
83
|
-
group: <area>
|
|
84
|
-
done: false
|
|
85
105
|
---
|
|
86
|
-
```
|
|
87
106
|
|
|
88
|
-
|
|
107
|
+
## Step 4: Mark as ready
|
|
108
|
+
|
|
109
|
+
Run `node scripts/brief.js validate <name> --project-dir <path>` to confirm the brief is valid.
|
|
89
110
|
|
|
90
|
-
|
|
111
|
+
Present the complete brief (`brief.md`) and spec (`spec.md`) to the user for review.
|
|
91
112
|
|
|
92
|
-
|
|
113
|
+
Once approved, run `node scripts/brief.js ready <name> --project-dir <path>` to transition to ready. The brief is now ready for the implement skill to pick up.
|
|
93
114
|
|
|
94
115
|
---
|
|
95
116
|
|
|
96
|
-
## Step
|
|
117
|
+
## Step 5: Continue a brief
|
|
97
118
|
|
|
98
119
|
Run `node scripts/brief.js list --project-dir <path>` to show all briefs. If the user does not specify which brief, ask them to pick one.
|
|
99
120
|
|
|
100
|
-
Run `node scripts/brief.js status <name> --project-dir <path>` to show progress. Read the brief and tasks files to understand the full context.
|
|
121
|
+
Run `node scripts/brief.js status <name> --project-dir <path>` to show progress. Read the brief, spec, and tasks files to understand the full context.
|
|
101
122
|
|
|
102
123
|
From here, the user may want to:
|
|
103
|
-
- **Discuss
|
|
104
|
-
- **Update
|
|
105
|
-
- **Revise the brief** -- update scope or design decisions based on what was learned
|
|
124
|
+
- **Discuss the brief** -- talk through scope or design decisions
|
|
125
|
+
- **Update the spec** -- add or revise technical context
|
|
126
|
+
- **Revise the brief** -- update scope or design decisions based on what was learned
|
|
127
|
+
- **Send back to draft** -- if a ready brief needs significant rework, update the status back to draft
|
|
106
128
|
|
|
107
|
-
When updating
|
|
129
|
+
When updating files, run `node scripts/brief.js validate <name> --project-dir <path>` afterward to confirm validity.
|
|
108
130
|
|
|
109
131
|
---
|
|
110
132
|
|
|
111
|
-
## Step
|
|
133
|
+
## Step 6: Complete a brief
|
|
112
134
|
|
|
113
135
|
Run `node scripts/brief.js status <name> --project-dir <path>` to verify all tasks are done.
|
|
114
136
|
|
|
115
137
|
If there are incomplete tasks, ask the user whether to:
|
|
116
|
-
1. Mark remaining tasks as
|
|
117
|
-
2.
|
|
138
|
+
1. Mark remaining tasks as completed (if they were completed outside this conversation)
|
|
139
|
+
2. Mark tasks as skipped (if they are no longer needed)
|
|
118
140
|
3. Continue working on them first
|
|
119
141
|
|
|
120
142
|
Write a summary into the `brief.md` frontmatter `summary` field. The summary should be one to two sentences capturing:
|
|
121
143
|
- What was built
|
|
122
144
|
- Key decisions or patterns established that future features should know about
|
|
123
145
|
|
|
124
|
-
Run `node scripts/brief.js complete <name> --project-dir <path>` to transition to completed. The script validates that all tasks are done and the summary is present.
|
|
146
|
+
Run `node scripts/brief.js complete <name> --project-dir <path>` to transition to completed. The script validates that all tasks are done or skipped and the summary is present.
|