deepflow 0.1.50 → 0.1.51
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.md +15 -13
- package/bin/install.js +12 -3
- package/hooks/df-consolidation-check.js +67 -0
- package/package.json +1 -1
- package/src/commands/df/consolidate.md +58 -0
- package/src/commands/df/debate.md +0 -4
- package/src/commands/df/discover.md +0 -2
- package/src/commands/df/execute.md +8 -6
- package/src/commands/df/note.md +1 -0
- package/src/commands/df/plan.md +0 -4
- package/src/commands/df/spec.md +0 -4
- package/src/commands/df/verify.md +22 -3
- package/templates/decision-capture.md +0 -19
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
- **Spike-first planning** — Validate risky hypotheses before full implementation
|
|
28
28
|
- **Worktree isolation** — Main branch stays clean during execution
|
|
29
29
|
- **Parallel execution** with context-aware checkpointing
|
|
30
|
+
- **Automatic decision capture** on spec completion, periodic consolidation
|
|
30
31
|
- **Atomic commits** for clean rollback
|
|
31
32
|
|
|
32
33
|
## Quick Start
|
|
@@ -65,7 +66,6 @@ claude
|
|
|
65
66
|
```
|
|
66
67
|
/df:discover <name>
|
|
67
68
|
│ Socratic questioning (motivation, scope, constraints...)
|
|
68
|
-
│ Captures decisions to .deepflow/decisions.md
|
|
69
69
|
▼
|
|
70
70
|
/df:debate <topic> ← optional
|
|
71
71
|
│ 4 perspectives: User Advocate, Tech Skeptic,
|
|
@@ -90,7 +90,8 @@ claude
|
|
|
90
90
|
/df:verify
|
|
91
91
|
│ Checks requirements met
|
|
92
92
|
│ Merges worktree to main, cleans up
|
|
93
|
-
│
|
|
93
|
+
│ Extracts decisions → .deepflow/decisions.md
|
|
94
|
+
│ Deletes done-* spec after extraction
|
|
94
95
|
```
|
|
95
96
|
|
|
96
97
|
## Spec Lifecycle
|
|
@@ -99,7 +100,7 @@ claude
|
|
|
99
100
|
specs/
|
|
100
101
|
feature.md → new, needs /df:plan
|
|
101
102
|
doing-feature.md → in progress, has tasks in PLAN.md
|
|
102
|
-
done-feature.md →
|
|
103
|
+
done-feature.md → transient (decisions extracted, then deleted)
|
|
103
104
|
```
|
|
104
105
|
|
|
105
106
|
## Works With Any Project
|
|
@@ -145,8 +146,9 @@ Statusline shows context usage. At ≥50%:
|
|
|
145
146
|
| `/df:spec <name>` | Generate spec from conversation |
|
|
146
147
|
| `/df:plan` | Compare specs to code, create tasks |
|
|
147
148
|
| `/df:execute` | Run tasks with parallel agents |
|
|
148
|
-
| `/df:verify` | Check specs satisfied |
|
|
149
|
-
| `/df:note` | Capture decisions from conversation |
|
|
149
|
+
| `/df:verify` | Check specs satisfied, merge to main |
|
|
150
|
+
| `/df:note` | Capture decisions ad-hoc from conversation |
|
|
151
|
+
| `/df:consolidate` | Deduplicate and clean up decisions.md |
|
|
150
152
|
| `/df:resume` | Session continuity briefing |
|
|
151
153
|
| `/df:update` | Update deepflow to latest |
|
|
152
154
|
|
|
@@ -156,16 +158,16 @@ Statusline shows context usage. At ≥50%:
|
|
|
156
158
|
your-project/
|
|
157
159
|
├── specs/
|
|
158
160
|
│ ├── auth.md # new spec
|
|
159
|
-
│
|
|
160
|
-
│ └── done-payments.md # completed
|
|
161
|
+
│ └── doing-upload.md # in progress
|
|
161
162
|
├── PLAN.md # active tasks
|
|
162
163
|
└── .deepflow/
|
|
163
|
-
├── config.yaml
|
|
164
|
-
├── decisions.md
|
|
165
|
-
├──
|
|
166
|
-
├──
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
├── config.yaml # project settings
|
|
165
|
+
├── decisions.md # auto-extracted + ad-hoc decisions
|
|
166
|
+
├── last-consolidated.json # consolidation timestamp
|
|
167
|
+
├── context.json # context % tracking
|
|
168
|
+
├── experiments/ # spike results (pass/fail)
|
|
169
|
+
└── worktrees/ # isolated execution
|
|
170
|
+
└── upload/ # one worktree per spec
|
|
169
171
|
```
|
|
170
172
|
|
|
171
173
|
## Configuration
|
package/bin/install.js
CHANGED
|
@@ -196,6 +196,7 @@ async function configureHooks(claudeDir) {
|
|
|
196
196
|
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
197
197
|
const statuslineCmd = `node "${path.join(claudeDir, 'hooks', 'df-statusline.js')}"`;
|
|
198
198
|
const updateCheckCmd = `node "${path.join(claudeDir, 'hooks', 'df-check-update.js')}"`;
|
|
199
|
+
const consolidationCheckCmd = `node "${path.join(claudeDir, 'hooks', 'df-consolidation-check.js')}"`;
|
|
199
200
|
|
|
200
201
|
let settings = {};
|
|
201
202
|
|
|
@@ -234,7 +235,7 @@ async function configureHooks(claudeDir) {
|
|
|
234
235
|
// Remove any existing deepflow update check hooks
|
|
235
236
|
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(hook => {
|
|
236
237
|
const cmd = hook.hooks?.[0]?.command || '';
|
|
237
|
-
return !cmd.includes('df-check-update');
|
|
238
|
+
return !cmd.includes('df-check-update') && !cmd.includes('df-consolidation-check');
|
|
238
239
|
});
|
|
239
240
|
|
|
240
241
|
// Add update check hook
|
|
@@ -244,6 +245,14 @@ async function configureHooks(claudeDir) {
|
|
|
244
245
|
command: updateCheckCmd
|
|
245
246
|
}]
|
|
246
247
|
});
|
|
248
|
+
|
|
249
|
+
// Add consolidation check hook
|
|
250
|
+
settings.hooks.SessionStart.push({
|
|
251
|
+
hooks: [{
|
|
252
|
+
type: 'command',
|
|
253
|
+
command: consolidationCheckCmd
|
|
254
|
+
}]
|
|
255
|
+
});
|
|
247
256
|
log('SessionStart hook configured');
|
|
248
257
|
|
|
249
258
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
@@ -330,7 +339,7 @@ async function uninstall() {
|
|
|
330
339
|
];
|
|
331
340
|
|
|
332
341
|
if (level === 'global') {
|
|
333
|
-
toRemove.push('hooks/df-statusline.js', 'hooks/df-check-update.js');
|
|
342
|
+
toRemove.push('hooks/df-statusline.js', 'hooks/df-check-update.js', 'hooks/df-consolidation-check.js');
|
|
334
343
|
}
|
|
335
344
|
|
|
336
345
|
for (const item of toRemove) {
|
|
@@ -359,7 +368,7 @@ async function uninstall() {
|
|
|
359
368
|
if (settings.hooks?.SessionStart) {
|
|
360
369
|
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(hook => {
|
|
361
370
|
const cmd = hook.hooks?.[0]?.command || '';
|
|
362
|
-
return !cmd.includes('df-check-update');
|
|
371
|
+
return !cmd.includes('df-check-update') && !cmd.includes('df-consolidation-check');
|
|
363
372
|
});
|
|
364
373
|
if (settings.hooks.SessionStart.length === 0) {
|
|
365
374
|
delete settings.hooks.SessionStart;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* deepflow consolidation checker
|
|
4
|
+
* Checks if decisions.md needs consolidation, outputs suggestion if overdue
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const DAYS_THRESHOLD = 7;
|
|
11
|
+
const LINES_THRESHOLD = 20;
|
|
12
|
+
const DEEPFLOW_DIR = path.join(process.cwd(), '.deepflow');
|
|
13
|
+
const DECISIONS_FILE = path.join(DEEPFLOW_DIR, 'decisions.md');
|
|
14
|
+
const LAST_CONSOLIDATED_FILE = path.join(DEEPFLOW_DIR, 'last-consolidated.json');
|
|
15
|
+
|
|
16
|
+
function checkConsolidation() {
|
|
17
|
+
try {
|
|
18
|
+
// Check if decisions.md exists
|
|
19
|
+
if (!fs.existsSync(DECISIONS_FILE)) {
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Check if decisions.md has more than LINES_THRESHOLD lines
|
|
24
|
+
const decisionsContent = fs.readFileSync(DECISIONS_FILE, 'utf8');
|
|
25
|
+
const lineCount = decisionsContent.split('\n').length;
|
|
26
|
+
if (lineCount <= LINES_THRESHOLD) {
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Get last consolidated timestamp
|
|
31
|
+
let lastConsolidated;
|
|
32
|
+
if (fs.existsSync(LAST_CONSOLIDATED_FILE)) {
|
|
33
|
+
try {
|
|
34
|
+
const data = JSON.parse(fs.readFileSync(LAST_CONSOLIDATED_FILE, 'utf8'));
|
|
35
|
+
if (data.last_consolidated) {
|
|
36
|
+
lastConsolidated = new Date(data.last_consolidated);
|
|
37
|
+
}
|
|
38
|
+
} catch (e) {
|
|
39
|
+
// Fall through to use mtime
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Fallback: use mtime of decisions.md
|
|
44
|
+
if (!lastConsolidated || isNaN(lastConsolidated.getTime())) {
|
|
45
|
+
const stat = fs.statSync(DECISIONS_FILE);
|
|
46
|
+
lastConsolidated = stat.mtime;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Calculate days since last consolidation
|
|
50
|
+
const now = new Date();
|
|
51
|
+
const diffMs = now - lastConsolidated;
|
|
52
|
+
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
53
|
+
|
|
54
|
+
if (diffDays >= DAYS_THRESHOLD) {
|
|
55
|
+
process.stderr.write(
|
|
56
|
+
`\u{1F4A1} decisions.md hasn't been consolidated in ${diffDays} days. Run /df:consolidate to clean up.\n`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
} catch (e) {
|
|
61
|
+
// Fail silently
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
checkConsolidation();
|
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# /df:consolidate — Consolidate Decisions
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Remove duplicates, superseded entries, and promote stale provisionals. Keep decisions.md dense and useful.
|
|
5
|
+
|
|
6
|
+
**NEVER:** use EnterPlanMode, use ExitPlanMode
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
```
|
|
10
|
+
/df:consolidate # Consolidate decisions.md
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Behavior
|
|
14
|
+
|
|
15
|
+
### 1. LOAD
|
|
16
|
+
Read `.deepflow/decisions.md`. If missing or empty, report and exit.
|
|
17
|
+
|
|
18
|
+
### 2. ANALYZE
|
|
19
|
+
Model-driven analysis (not regex):
|
|
20
|
+
- Identify duplicate decisions (same meaning, different wording)
|
|
21
|
+
- Identify superseded decisions (later entry contradicts earlier)
|
|
22
|
+
- Identify stale `[PROVISIONAL]` entries (>30 days old, no resolution)
|
|
23
|
+
|
|
24
|
+
### 3. CONSOLIDATE
|
|
25
|
+
- Remove duplicates (keep the more precise wording)
|
|
26
|
+
- Silently remove superseded entries (the later decision wins)
|
|
27
|
+
- Promote stale `[PROVISIONAL]` to `[DEBT]` (needs revisiting)
|
|
28
|
+
- Preserve all `[APPROACH]` entries unless superseded
|
|
29
|
+
- Preserve all `[ASSUMPTION]` entries unless invalidated
|
|
30
|
+
- Target: 200-500 lines (if currently longer)
|
|
31
|
+
- When in doubt, keep both entries (conservative)
|
|
32
|
+
|
|
33
|
+
### 4. WRITE
|
|
34
|
+
- Rewrite `.deepflow/decisions.md` with consolidated content
|
|
35
|
+
- Write timestamp to `.deepflow/last-consolidated.json`:
|
|
36
|
+
```json
|
|
37
|
+
{ "last_consolidated": "{ISO-8601 timestamp}" }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 5. REPORT
|
|
41
|
+
```
|
|
42
|
+
✓ Consolidated: {before} → {after} lines, {n} removed, {n} promoted to [DEBT]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Tags
|
|
46
|
+
| Tag | Meaning | Source |
|
|
47
|
+
|-----|---------|--------|
|
|
48
|
+
| `[APPROACH]` | Firm decision | Auto-extraction, /df:note |
|
|
49
|
+
| `[PROVISIONAL]` | Revisit later | Auto-extraction, /df:note |
|
|
50
|
+
| `[ASSUMPTION]` | Unverified | Auto-extraction, /df:note |
|
|
51
|
+
| `[DEBT]` | Needs revisiting | Consolidation only |
|
|
52
|
+
|
|
53
|
+
## Rules
|
|
54
|
+
- Conservative: when in doubt, keep both entries
|
|
55
|
+
- Never add new decisions — only remove, merge, or re-tag
|
|
56
|
+
- [DEBT] is never manually assigned — only produced by consolidation
|
|
57
|
+
- Preserve chronological ordering within sections
|
|
58
|
+
- decisions.md stays a single flat file, human-readable
|
|
@@ -160,10 +160,6 @@ Create `specs/.debate-{name}.md` with sections: Context · Codebase Context · P
|
|
|
160
160
|
|
|
161
161
|
Present key tensions and open decisions, then: `Next: Run /df:spec {name} to formalize into a specification`
|
|
162
162
|
|
|
163
|
-
### 7. CAPTURE DECISIONS
|
|
164
|
-
|
|
165
|
-
Follow the **default** variant from `templates/decision-capture.md`. Command name: `debate`.
|
|
166
|
-
|
|
167
163
|
---
|
|
168
164
|
|
|
169
165
|
## Rules
|
|
@@ -85,8 +85,6 @@ Example questions:
|
|
|
85
85
|
- Keep your responses short between questions — don't lecture
|
|
86
86
|
- Acknowledge answers briefly before asking the next question
|
|
87
87
|
|
|
88
|
-
### Decision Capture
|
|
89
|
-
Follow the **default** variant from `templates/decision-capture.md`. Command name: `discover`.
|
|
90
88
|
### When the User Wants to Move On
|
|
91
89
|
When the user signals they want to advance (e.g., "I think that's enough", "let's move on", "ready for next step"):
|
|
92
90
|
|
|
@@ -380,13 +380,19 @@ When a task fails and cannot be auto-fixed:
|
|
|
380
380
|
When all tasks done for a `doing-*` spec:
|
|
381
381
|
1. Embed history in spec: `## Completed` section with task list and commit hashes
|
|
382
382
|
2. Rename: `doing-upload.md` → `done-upload.md`
|
|
383
|
-
3.
|
|
383
|
+
3. Extract decisions from done-* spec: Read the `done-{name}.md` file. Model-extract architectural decisions — look for explicit choices (→ `[APPROACH]`), unvalidated assumptions (→ `[ASSUMPTION]`), and "for now" decisions (→ `[PROVISIONAL]`). Append as a new section to **main tree** `.deepflow/decisions.md`:
|
|
384
|
+
```
|
|
385
|
+
### {YYYY-MM-DD} — {spec-name}
|
|
386
|
+
- [TAG] decision text — rationale
|
|
387
|
+
```
|
|
388
|
+
After successful append, delete `specs/done-{name}.md`. If write fails, preserve the file.
|
|
389
|
+
4. Remove the spec's ENTIRE section from PLAN.md:
|
|
384
390
|
- The `### doing-{spec}` header
|
|
385
391
|
- All task entries (`- [x] **T{n}**: ...` and their sub-items)
|
|
386
392
|
- Any `## Execution Summary` block for that spec
|
|
387
393
|
- Any `### Fix Tasks` sub-section for that spec
|
|
388
394
|
- Separators (`---`) between removed sections
|
|
389
|
-
|
|
395
|
+
5. Recalculate the Summary table at the top of PLAN.md (update counts for completed/pending)
|
|
390
396
|
|
|
391
397
|
### 10. ITERATE (Notification-Driven)
|
|
392
398
|
|
|
@@ -408,10 +414,6 @@ After spawning wave agents, your turn ENDS. Completion notifications drive the l
|
|
|
408
414
|
|
|
409
415
|
**Repeat** until: all done, all blocked, or context ≥50% (checkpoint).
|
|
410
416
|
|
|
411
|
-
### 11. CAPTURE DECISIONS
|
|
412
|
-
|
|
413
|
-
Follow the **main-tree** variant from `templates/decision-capture.md`. Command name: `execute`.
|
|
414
|
-
|
|
415
417
|
## Rules
|
|
416
418
|
|
|
417
419
|
| Rule | Detail |
|
package/src/commands/df/note.md
CHANGED
|
@@ -132,6 +132,7 @@ No decisions saved.
|
|
|
132
132
|
- `[APPROACH]` — deliberate design or implementation choice
|
|
133
133
|
- `[PROVISIONAL]` — works for now, will revisit at scale or with more information
|
|
134
134
|
- `[ASSUMPTION]` — treating something as true without full confirmation
|
|
135
|
+
- `[DEBT]` — needs revisiting; produced only by `/df:consolidate`, never manually assigned
|
|
135
136
|
|
|
136
137
|
**Contradiction handling:** Never delete prior entries. When a new decision contradicts an older one, include a reference in the rationale: `was "X", now "Y" because Z`.
|
|
137
138
|
|
package/src/commands/df/plan.md
CHANGED
|
@@ -154,10 +154,6 @@ Append tasks grouped by `### doing-{spec-name}`. Include spec gaps and validatio
|
|
|
154
154
|
|
|
155
155
|
`✓ Plan generated — {n} specs, {n} tasks. Run /df:execute`
|
|
156
156
|
|
|
157
|
-
### 12. CAPTURE DECISIONS
|
|
158
|
-
|
|
159
|
-
Follow the **default** variant from `templates/decision-capture.md`. Command name: `plan`.
|
|
160
|
-
|
|
161
157
|
## Rules
|
|
162
158
|
- **Spike-first** — Generate spike task before full implementation if no `--passed.md` experiment exists
|
|
163
159
|
- **Block on spike** — Full implementation tasks MUST be blocked by spike validation
|
package/src/commands/df/spec.md
CHANGED
|
@@ -130,10 +130,6 @@ Acceptance criteria: {count}
|
|
|
130
130
|
Next: Run /df:plan to generate tasks
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
### 6. CAPTURE DECISIONS
|
|
134
|
-
|
|
135
|
-
Follow the **default** variant from `templates/decision-capture.md`. Command name: `spec`.
|
|
136
|
-
|
|
137
133
|
## Rules
|
|
138
134
|
- **Orchestrator never searches** — Spawn agents for all codebase exploration
|
|
139
135
|
- Do NOT generate spec if critical gaps remain
|
|
@@ -201,6 +201,28 @@ git branch -d "${WORKTREE_BRANCH}"
|
|
|
201
201
|
rm -f .deepflow/checkpoint.json
|
|
202
202
|
```
|
|
203
203
|
|
|
204
|
+
### 4. RENAME SPEC
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Rename spec to done
|
|
208
|
+
mv specs/doing-${SPEC_NAME}.md specs/done-${SPEC_NAME}.md
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 5. EXTRACT DECISIONS
|
|
212
|
+
|
|
213
|
+
Read the renamed `specs/done-${SPEC_NAME}.md` file. Model-extract architectural decisions:
|
|
214
|
+
- Explicit choices → `[APPROACH]`
|
|
215
|
+
- Unvalidated assumptions → `[ASSUMPTION]`
|
|
216
|
+
- "For now" decisions → `[PROVISIONAL]`
|
|
217
|
+
|
|
218
|
+
Append to `.deepflow/decisions.md`:
|
|
219
|
+
```
|
|
220
|
+
### {YYYY-MM-DD} — {spec-name}
|
|
221
|
+
- [TAG] decision text — rationale
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
After successful append, delete `specs/done-${SPEC_NAME}.md`. If write fails, preserve the file.
|
|
225
|
+
|
|
204
226
|
Output:
|
|
205
227
|
```
|
|
206
228
|
✓ Merged df/upload to main
|
|
@@ -210,6 +232,3 @@ Output:
|
|
|
210
232
|
Workflow complete! Ready for next feature: /df:spec <name>
|
|
211
233
|
```
|
|
212
234
|
|
|
213
|
-
### 4. CAPTURE DECISIONS (success path only)
|
|
214
|
-
|
|
215
|
-
Follow the **success-path-only** variant from `templates/decision-capture.md`. Command name: `verify`.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Decision Capture — Shared Pattern
|
|
2
|
-
|
|
3
|
-
## Common Flow
|
|
4
|
-
Extract up to 4 candidates → `AskUserQuestion(multiSelect: true)` → append confirmed to `.deepflow/decisions.md`.
|
|
5
|
-
Each option: `label: "[TAG] <decision>"`, `description: "<rationale>"`. Tags: `[APPROACH]` `[PROVISIONAL]` `[ASSUMPTION]`.
|
|
6
|
-
Format: `### {YYYY-MM-DD} — {command}` / `- [TAG] decision text — rationale`
|
|
7
|
-
|
|
8
|
-
## Variant: default
|
|
9
|
-
Used by: discover, debate, spec, plan, note.
|
|
10
|
-
Append confirmed decisions to `.deepflow/decisions.md` (create if missing). Max 4 candidates.
|
|
11
|
-
If a decision contradicts a prior entry, note conflict inline; never delete prior entries.
|
|
12
|
-
|
|
13
|
-
## Variant: main-tree
|
|
14
|
-
Used by: execute.
|
|
15
|
-
Same as default but write to **main tree** `.deepflow/decisions.md` (repo root, parent of `.deepflow/worktrees/`), not the worktree path.
|
|
16
|
-
|
|
17
|
-
## Variant: success-path-only
|
|
18
|
-
Used by: verify.
|
|
19
|
-
Same as default but **only run this step when verification passes**. Skip entirely on failure.
|