fdeops 3.9.16 → 3.9.18
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 +8 -2
- package/bin/check.js +13 -0
- package/bin/fde.js +153 -19
- package/bin/lib/trust.js +3 -1
- package/package.json +1 -1
- package/skills/fde/SKILL.md +17 -4
- package/skills/fde/references/build.md +1 -1
- package/skills/fde/references/debrief.md +22 -8
- package/skills/fde/references/discover.md +1 -1
- package/skills/fde/references/review.md +8 -1
- package/skills/fde/references/stakeholder-radar.md +2 -0
- package/templates/.fde/stakeholders.md +4 -2
- package/templates/.fde/terrain.md +2 -1
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
**Memory + methodology + skills, in one kit.** Skill packs teach your AI agent how to build. None of them remember who the client is, what was decided, or what's safe to ship. FDEOps adds the missing layer: a private fieldbook per engagement (`.fde/`), a field methodology (land → close), and one `@fde` skill that routes it all.
|
|
11
|
+
|
|
12
|
+
Built for Forward Deployed Engineers, and anyone embedded in client work: consultants, agency developers, solutions architects, fractional CTOs. Feels like a second brain; behaves like a defensible record (dated, sourced, yours).
|
|
11
13
|
|
|
12
14
|
```
|
|
13
15
|
land discover plan build ship close
|
|
@@ -195,4 +197,8 @@ cd fdeops && git pull && node bin/install.js
|
|
|
195
197
|
|
|
196
198
|
Built and maintained by **[Subash Natarajan](https://www.linkedin.com/in/subashn/)**. Share your feedback via [Issues](https://github.com/suboss87/fdeops/issues) - see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
197
199
|
|
|
198
|
-
|
|
200
|
+
Thanks to builders whose craft helped sharpen the thinking behind this kit, among them [Andrej Karpathy](https://karpathy.ai/)'s engineering guidelines and the [agentic engineering workflow](https://github.com/pawel-cell/micky-podcast-agentic-engineering) notes from David Ondrej / Michael Shimeles. FDEOps itself is handcrafted for field work; any resemblance is inspiration, not a fork.
|
|
201
|
+
|
|
202
|
+
**What we won't build:** SaaS sync or Slack/Notion connectors inside the CLI, CRM as core, hardware capture, or generic code-craft skill packs (TDD/review already exist elsewhere - FDEOps owns the engagement, not the keyboard). The `fde` CLI stays local-only.
|
|
203
|
+
|
|
204
|
+
[FDE Methodology](FDE-METHODOLOGY.md) - [SECURITY.md](SECURITY.md) - [PRIVACY.md](PRIVACY.md) - [Repo layout](docs/REPO_LAYOUT.md) - [Skills matrix](docs/skills.md) - MIT
|
package/bin/check.js
CHANGED
|
@@ -235,6 +235,19 @@ if (!skillBody.includes('fde prep')) {
|
|
|
235
235
|
if (!skillBody.includes('debrief --smart')) {
|
|
236
236
|
fail('SKILL.md must prefer fde debrief --smart for messy notes')
|
|
237
237
|
}
|
|
238
|
+
const debriefRef = read('skills/fde/references/debrief.md')
|
|
239
|
+
if (!/gate \+ writer|not a brain/i.test(debriefRef) || !/rewrite.*prefix/i.test(debriefRef)) {
|
|
240
|
+
fail('debrief.md must state --smart is a gate (agent rewrites propose with prefixes)')
|
|
241
|
+
} else ok('debrief --smart honesty contract')
|
|
242
|
+
if (!/existing.*## Next action|never append a second/i.test(skillBody)) {
|
|
243
|
+
fail('SKILL.md must warn against appending a second ## Next action')
|
|
244
|
+
} else ok('session-end Next action instruction')
|
|
245
|
+
if (!/session digest/i.test(skillBody) || !/Key decisions & why/i.test(skillBody)) {
|
|
246
|
+
fail('SKILL.md memory contract must define session digest (TL;DR / decisions & why → .fde/)')
|
|
247
|
+
} else ok('session digest in memory contract')
|
|
248
|
+
if (!/transcript/i.test(skillBody) || !/judgment/i.test(skillBody)) {
|
|
249
|
+
fail('SKILL.md must reject transcript dumps in favor of judgment in .fde/')
|
|
250
|
+
} else ok('session digest anti-transcript gate')
|
|
238
251
|
if (!/\btriage\b/.test(hook)) {
|
|
239
252
|
fail('session-start must still inject TRIAGE')
|
|
240
253
|
}
|
package/bin/fde.js
CHANGED
|
@@ -443,16 +443,56 @@ const {
|
|
|
443
443
|
} = createMemoryApi({ fs, path, gitBinOk, writeOwnerIfMissing, atomicWriteFile })
|
|
444
444
|
|
|
445
445
|
// Pull the body under a "## Heading" up to the next "##" (or EOF).
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
446
|
+
// opts.lastNonEmpty: when duplicate headings exist (common skill trap: template
|
|
447
|
+
// "## Next action" left empty, agent appends a second), prefer the last filled
|
|
448
|
+
// body so triage/resume do not silently report "(none set)".
|
|
449
|
+
function sectionBody(md, heading, opts) {
|
|
450
|
+
const preferLast = opts && opts.lastNonEmpty
|
|
451
|
+
const lines = String(md || '').split('\n')
|
|
452
|
+
const re = new RegExp('^#{1,6}\\s+' + heading + '\\b', 'i')
|
|
453
|
+
let first = ''
|
|
454
|
+
let lastFilled = ''
|
|
455
|
+
let seen = false
|
|
456
|
+
for (let i = 0; i < lines.length; i++) {
|
|
457
|
+
if (!re.test(lines[i].trim())) continue
|
|
458
|
+
const body = []
|
|
459
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
460
|
+
if (/^#{1,6}\s/.test(lines[j].trim())) break
|
|
461
|
+
body.push(lines[j])
|
|
462
|
+
}
|
|
463
|
+
const text = body.join('\n').trim()
|
|
464
|
+
if (!seen) { first = text; seen = true }
|
|
465
|
+
if (text) lastFilled = text
|
|
454
466
|
}
|
|
455
|
-
return
|
|
467
|
+
if (!seen) return ''
|
|
468
|
+
return preferLast ? (lastFilled || first) : first
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function countSections(md, heading) {
|
|
472
|
+
const re = new RegExp('^#{1,6}\\s+' + heading + '\\b', 'i')
|
|
473
|
+
let n = 0
|
|
474
|
+
for (const raw of String(md || '').split('\n')) {
|
|
475
|
+
if (re.test(raw.trim())) n++
|
|
476
|
+
}
|
|
477
|
+
return n
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Remove every "## Heading" section (heading line + body). Used to collapse
|
|
481
|
+
// duplicate Next action blocks before writing a single canonical one.
|
|
482
|
+
function stripAllSections(md, heading) {
|
|
483
|
+
const lines = String(md || '').split('\n')
|
|
484
|
+
const re = new RegExp('^#{1,6}\\s+' + heading + '\\b', 'i')
|
|
485
|
+
const out = []
|
|
486
|
+
for (let i = 0; i < lines.length; i++) {
|
|
487
|
+
if (re.test(lines[i].trim())) {
|
|
488
|
+
i++
|
|
489
|
+
while (i < lines.length && !/^#{1,6}\s/.test(lines[i].trim())) i++
|
|
490
|
+
i--
|
|
491
|
+
continue
|
|
492
|
+
}
|
|
493
|
+
out.push(lines[i])
|
|
494
|
+
}
|
|
495
|
+
return out.join('\n').replace(/\n{3,}/g, '\n\n').replace(/^\n+/, '').replace(/\n*$/, '\n')
|
|
456
496
|
}
|
|
457
497
|
|
|
458
498
|
// Append `entry` as the last line of a "## Heading" section, creating the
|
|
@@ -1106,11 +1146,12 @@ function setContextPhase(eng, phase) {
|
|
|
1106
1146
|
|
|
1107
1147
|
|
|
1108
1148
|
// Meeting notes → structured memory. Deterministic routing, zero AI: lines that
|
|
1109
|
-
// start with decision:/risk:/delivery:/contact: (case-insensitive) go to
|
|
1110
|
-
// LOG_FILES target as dated bullets; everything else lands in context.md
|
|
1111
|
-
// dated debrief block. contact: lines may carry an inline [signal:x]
|
|
1112
|
-
// anywhere in the text - preserved verbatim so computeSignals can trust it.
|
|
1113
|
-
// --smart: heuristic propose
|
|
1149
|
+
// start with decision:/risk:/delivery:/contact:/next: (case-insensitive) go to
|
|
1150
|
+
// their LOG_FILES target as dated bullets; everything else lands in context.md
|
|
1151
|
+
// as one dated debrief block. contact: lines may carry an inline [signal:x]
|
|
1152
|
+
// token anywhere in the text - preserved verbatim so computeSignals can trust it.
|
|
1153
|
+
// --smart: thin heuristic propose (existing prefixes + light keywords). Not a
|
|
1154
|
+
// brain — the agent rewrites .debrief-propose with prefixes; --apply commits.
|
|
1114
1155
|
// --dry-run prints the routing without writing anything.
|
|
1115
1156
|
function inferContactSignal(text) {
|
|
1116
1157
|
const t = String(text)
|
|
@@ -1178,8 +1219,13 @@ function setNextAction(eng, text) {
|
|
|
1178
1219
|
const p = path.join(eng, 'context.md')
|
|
1179
1220
|
let md = readEng(eng, 'context.md')
|
|
1180
1221
|
if (!md) md = '# Engagement context\n\n'
|
|
1181
|
-
|
|
1182
|
-
|
|
1222
|
+
// Collapse duplicate ## Next action headings (skill-append trap) into one.
|
|
1223
|
+
md = stripAllSections(md, 'Next action')
|
|
1224
|
+
if (/^##\s+Current state\b/im.test(md)) {
|
|
1225
|
+
md = md.replace(
|
|
1226
|
+
/(^##\s+Current state\b[^\n]*\n)([\s\S]*?)(?=^##\s|\s*$)/im,
|
|
1227
|
+
(_, h, body) => `${h}${String(body).replace(/\n*$/, '\n')}\n## Next action\n\n${bullet}\n\n`
|
|
1228
|
+
)
|
|
1183
1229
|
} else {
|
|
1184
1230
|
md = md.replace(/\n*$/, `\n\n## Next action\n\n${bullet}\n`)
|
|
1185
1231
|
}
|
|
@@ -1593,8 +1639,13 @@ function collectDoctorIssues(eng) {
|
|
|
1593
1639
|
}
|
|
1594
1640
|
const success = readClean(eng, 'success.md')
|
|
1595
1641
|
if (!firstLine(success, 80)) issues.push('success.md has no stated done-definition - fill before plan/build')
|
|
1596
|
-
|
|
1642
|
+
const ctxMd = readClean(eng, 'context.md')
|
|
1643
|
+
if (!sectionBody(ctxMd, 'Next action', { lastNonEmpty: true })) {
|
|
1597
1644
|
issues.push('no ## Next action in context.md - Monday morning has nothing to drive')
|
|
1645
|
+
} else if (countSections(ctxMd, 'Next action') > 1) {
|
|
1646
|
+
issues.push(
|
|
1647
|
+
'duplicate ## Next action headings in context.md - fill the first (template) section and remove extras; triage reads the last non-empty'
|
|
1648
|
+
)
|
|
1598
1649
|
}
|
|
1599
1650
|
if ((s.phase === 'close' || s.phase === 'ship') && s.openRisks > 0) {
|
|
1600
1651
|
issues.push(
|
|
@@ -1620,9 +1671,92 @@ function collectDoctorIssues(eng) {
|
|
|
1620
1671
|
`${dupes.length} duplicate open-risk cluster(s) (e.g. "${sample}${sample.length >= 60 ? '…' : ''}") - consolidate or retire echoes in risks.md`
|
|
1621
1672
|
)
|
|
1622
1673
|
}
|
|
1674
|
+
// Failure-path (exception-led operating map): required once past discover.
|
|
1675
|
+
// Land seeds; discover fills; plan+ without a real break→owner row is wallpaper.
|
|
1676
|
+
if (/^(plan|build|ship|close)$/.test(s.phase) && !hasOperatingMapContent(eng)) {
|
|
1677
|
+
issues.push(
|
|
1678
|
+
`phase is ${s.phase} with empty operating map - fill terrain.md ## Operating map (exception-led): break → who notices → workaround → evidence`
|
|
1679
|
+
)
|
|
1680
|
+
}
|
|
1681
|
+
const aliases = findAmbiguousStakeholders(eng)
|
|
1682
|
+
if (aliases.length) {
|
|
1683
|
+
const sample = aliases[0].forms.slice(0, 3).join(' / ')
|
|
1684
|
+
issues.push(
|
|
1685
|
+
`${aliases.length} stakeholder identity cluster(s) (e.g. "${sample}") - same person under different names? consolidate in stakeholders.md`
|
|
1686
|
+
)
|
|
1687
|
+
}
|
|
1623
1688
|
return issues
|
|
1624
1689
|
}
|
|
1625
1690
|
|
|
1691
|
+
// True when ## Operating map has at least one real exception row (not the empty template).
|
|
1692
|
+
function hasOperatingMapContent(eng) {
|
|
1693
|
+
const terrain = stripTemplateNoise(readClean(eng, 'terrain.md'))
|
|
1694
|
+
const body = sectionBody(terrain, 'Operating map')
|
|
1695
|
+
if (!body.trim()) return false
|
|
1696
|
+
const table = parseMdTable(body)
|
|
1697
|
+
if (table) {
|
|
1698
|
+
const exIdx = colIndex(table.headers, /exception|break/i)
|
|
1699
|
+
const idx = exIdx !== -1 ? exIdx : 0
|
|
1700
|
+
for (const row of table.rows) {
|
|
1701
|
+
const cell = (row[idx] || '').trim()
|
|
1702
|
+
if (cell && !/^unknown/i.test(cell)) return true
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
for (const raw of body.split('\n')) {
|
|
1706
|
+
const t = raw.trim().replace(/^[-*]\s+/, '')
|
|
1707
|
+
if (!t || t.startsWith('#') || t.startsWith('|') || /^\*\*/.test(t)) continue
|
|
1708
|
+
if (t.length >= 8 && !/^unknown/i.test(t)) return true
|
|
1709
|
+
}
|
|
1710
|
+
return false
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
// Near-duplicate stakeholder forms sharing a first-name key (Denise vs Denise Chen).
|
|
1714
|
+
function findAmbiguousStakeholders(eng) {
|
|
1715
|
+
const forms = []
|
|
1716
|
+
const md = readClean(eng, 'stakeholders.md')
|
|
1717
|
+
const table = parseMdTable(md)
|
|
1718
|
+
if (table) {
|
|
1719
|
+
const nameIdx = colIndex(table.headers, /name|who/i)
|
|
1720
|
+
if (nameIdx !== -1) {
|
|
1721
|
+
for (const row of table.rows) {
|
|
1722
|
+
const name = (row[nameIdx] || '').trim()
|
|
1723
|
+
if (!name || name.length < 2) continue
|
|
1724
|
+
forms.push(name)
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
for (const h of parseSignalHistoryEntries(eng)) {
|
|
1729
|
+
const name = displayNameFromSignalText(h.text)
|
|
1730
|
+
if (name && name.length >= 2 && !/^anon:/i.test(name)) forms.push(name)
|
|
1731
|
+
}
|
|
1732
|
+
const byKey = new Map()
|
|
1733
|
+
for (const name of forms) {
|
|
1734
|
+
const key = signalSubjectKey(name)
|
|
1735
|
+
if (!key || key.startsWith('anon:')) continue
|
|
1736
|
+
const norm = name.replace(/\s+/g, ' ').trim().toLowerCase()
|
|
1737
|
+
if (!byKey.has(key)) byKey.set(key, new Set())
|
|
1738
|
+
byKey.get(key).add(norm)
|
|
1739
|
+
}
|
|
1740
|
+
const clusters = []
|
|
1741
|
+
for (const [key, set] of byKey) {
|
|
1742
|
+
if (set.size < 2) continue
|
|
1743
|
+
// Prefer clusters where forms aren't just identical casing - already lowercased.
|
|
1744
|
+
// Require at least one multi-token form vs a shorter form (Denise / Denise Chen).
|
|
1745
|
+
const list = [...set]
|
|
1746
|
+
const hasLong = list.some(f => f.split(/\s+/).length >= 2)
|
|
1747
|
+
const hasShort = list.some(f => f.split(/\s+/).length === 1)
|
|
1748
|
+
if (hasLong && hasShort) {
|
|
1749
|
+
clusters.push({ key, forms: list })
|
|
1750
|
+
continue
|
|
1751
|
+
}
|
|
1752
|
+
// Or two multi-token forms that share first token but differ later (Denise Chen / Denise C.)
|
|
1753
|
+
if (list.length >= 2 && list.every(f => f.split(/\s+/).length >= 2)) {
|
|
1754
|
+
clusters.push({ key, forms: list })
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
return clusters
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1626
1760
|
// Strip template comments / italic *(hints)* so doctor does not treat stubs as filled.
|
|
1627
1761
|
function stripTemplateNoise(md) {
|
|
1628
1762
|
return String(md || '')
|
|
@@ -2090,7 +2224,7 @@ function cmdDashboard(args) {
|
|
|
2090
2224
|
// one-liners, sector/overlay, days elapsed, and the four structured widgets.
|
|
2091
2225
|
engagements.forEach(e => {
|
|
2092
2226
|
const ctx = readClean(e.dir, 'context.md')
|
|
2093
|
-
e.next = (sectionBody(ctx, 'Next action').split('\n').find(l => l.trim()) || '').trim()
|
|
2227
|
+
e.next = (sectionBody(ctx, 'Next action', { lastNonEmpty: true }).split('\n').find(l => l.trim()) || '').trim()
|
|
2094
2228
|
e.hasNext = !!e.next
|
|
2095
2229
|
e.lastSession = firstLine(sectionBody(ctx, 'Current state'), 240)
|
|
2096
2230
|
// 220, not 140 - now that brief/reality each get their own full-width
|
|
@@ -2158,7 +2292,7 @@ function printUsage() {
|
|
|
2158
2292
|
fde log phase <phase> set engagement phase (land|discover|plan|build|ship|close)
|
|
2159
2293
|
fde log --undo remove the last CLI log/debrief entry from memory
|
|
2160
2294
|
fde debrief [file] meeting notes → memory (prefixed lines; --dry-run; --force)
|
|
2161
|
-
fde debrief --smart propose
|
|
2295
|
+
fde debrief --smart heuristic propose (prefix + light keywords); agent routes, CLI gates → --apply
|
|
2162
2296
|
fde prep [label] grounded walk-in brief from existing .fde/ only
|
|
2163
2297
|
fde doctor lint engagement memory (stale signals, gaps)
|
|
2164
2298
|
fde redact <term> preview/remove lines containing a buried term (pass --apply to commit)
|
package/bin/lib/trust.js
CHANGED
|
@@ -85,7 +85,9 @@ function createTrustApi(deps) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
function nextActionLine(ctx) {
|
|
88
|
-
|
|
88
|
+
// lastNonEmpty: template ships an empty ## Next action; agents often append a
|
|
89
|
+
// second heading with the real bullet — first-match would report "(none set)".
|
|
90
|
+
const body = sectionBody(ctx, 'Next action', { lastNonEmpty: true })
|
|
89
91
|
for (const raw of body.split('\n')) {
|
|
90
92
|
const t = raw.trim().replace(/^[-*]\s+/, '')
|
|
91
93
|
if (t) return t.slice(0, 120)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fdeops",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.18",
|
|
4
4
|
"description": "Field kit for engineers embedded in client work - a real CLI (recon, memory, portfolio), one @fde skill with field judgment on top, and hooks that make it automatic. Claude Code plugin and any agent that loads skills.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fdeops": "bin/install.js",
|
package/skills/fde/SKILL.md
CHANGED
|
@@ -35,7 +35,18 @@ This is what makes fdeops a second brain instead of a chat window.
|
|
|
35
35
|
2. **Deliverable = memory.** The output of every phase IS a `.fde/` file. You never ask the FDE to "update their notes" - producing the work and writing the memory are one action. The phase reference tells you which file.
|
|
36
36
|
3. **Evidence rule.** Every claim in an artifact carries its source: `(validated with: ops lead, Day 5)`, `(churn: 47 commits/90d)`, `(stated, unverified)`. The FDE defends these files in front of skeptical clients - traceable beats plausible.
|
|
37
37
|
4. **No invented facts - ever.** People, names, quotes, meetings, and numbers exist only if the FDE said them or the repo shows them. Never invent a stakeholder, a conversation, or a source to make the narrative richer - one fabricated name poisons every real citation around it. A missing fact is written as `unknown - ask: <the question>`, nothing else.
|
|
38
|
-
5. **On exit:** before the session ends
|
|
38
|
+
5. **On exit (session digest):** before the session ends — and again before opening a PR — capture the *thinking*, not the chat. Propose this digest in plain language; on FDE confirm, write into existing `.fde/` files (never a transcript dump, never a product-repo history folder):
|
|
39
|
+
|
|
40
|
+
| Digest beat | Lands in |
|
|
41
|
+
|-------------|----------|
|
|
42
|
+
| **TL;DR** (1–2 sentences: what moved) | `context.md` current state / short dated note |
|
|
43
|
+
| **Key decisions & why** (only real ones) | `decisions.md` dated lines — skip if none |
|
|
44
|
+
| **Pivot / aha** (course correction that mattered) | one line in `context.md`, or `decisions.md` if it changed the plan |
|
|
45
|
+
| **Scope + verification** (files/slice + how you checked) | `delivery.md` when code or a PR is in play; else skip |
|
|
46
|
+
| **Gotchas for the next reader** | `context.md` (teammate / Monday-you) |
|
|
47
|
+
| **Next action** | existing `## Next action` — **replace** the bullet; never append a second heading |
|
|
48
|
+
|
|
49
|
+
The `session-stop` hook backstops a thin snapshot; **you** write the meaningful digest. Raw agent transcripts stay on the machine — judgment is what ships in the fieldbook.
|
|
39
50
|
6. **One customer, one folder.** Never merge two engagements into one `.fde/`. Confirm which engagement applies when multiple exist.
|
|
40
51
|
7. **Never delete a code-read section when rewriting an artifact.** `stakeholders.md`'s `## Signal history` holds dated `[signal:...]` tokens that `fde status`/`fde receipts`/the dashboard read verbatim; `risks.md`'s `## Retired` is read the same way. Rewriting either file as an artifact (land, audit, stakeholder-radar) is fine - dropping one of these sections is not. Carry existing entries forward untouched.
|
|
41
52
|
|
|
@@ -51,6 +62,7 @@ These stop confident fiction. They are not optional soft tips.
|
|
|
51
62
|
| Fill `success.md` / `terrain.md` with plausible defaults when the brief is thin | **Stop.** Run **brief interrogation** in land/discover (one Q + GUESS + confidence) until you can write without guessing, or leave gaps explicit. |
|
|
52
63
|
| Ship / go-live / irreversible change with "probably fine" | **Stop.** Run **intent vs diff** (KEEP/JUSTIFY/SPLIT/DROP) then **pre-blast challenge** in ship (or red-team) — CLAIM → CHALLENGE → VERDICT — and log both. |
|
|
53
64
|
| Grill the FDE with a checklist when they're mid-flow | **Stop.** Playback rule wins. Probe only when a missing fact changes the next move. |
|
|
65
|
+
| Sync chat transcripts / agent brain folders into the product git repo for "team share" | **Stop.** Run **session digest** into `.fde/` (judgment only). Transcripts stay local. |
|
|
54
66
|
|
|
55
67
|
When NOT to interrogate or challenge: unambiguous one-liners, mechanical ops, FDE explicitly asked for speed, answer already in `.fde/`.
|
|
56
68
|
|
|
@@ -70,16 +82,16 @@ When NOT to interrogate or challenge: unambiguous one-liners, mechanical ops, FD
|
|
|
70
82
|
|-----------------------------|---------|
|
|
71
83
|
| (session entry / where are we) | `fde resume` or use injected TRIAGE; `fde resume --init <name>` only if unbound |
|
|
72
84
|
| Day-1 look at the repo | `fde scan` - then you interpret against the brief |
|
|
73
|
-
| "Debrief these notes" / pastes meeting notes | Prefer `fde debrief --smart <notes>` →
|
|
85
|
+
| "Debrief these notes" / pastes meeting notes | Prefer `fde debrief --smart <notes>` → **you** (the agent) rewrite `.debrief-propose` with `decision:`/`risk:`/`delivery:`/`contact:`/`next:` prefixes where needed → show FDE → on confirm `fde debrief --apply`. `--smart` is a prefix/keyword gate, not a brain. Fallback: structure prefixed lines yourself, show FDE, then `fde debrief` |
|
|
74
86
|
| "Prep me for the meeting with …" / walk-in brief | `fde prep "<short label>"` - present the brief in plain language; do not invent facts missing from `.fde/` |
|
|
75
87
|
| "When did we agree…?" / scope dispute | `fde receipts <term>` - answer with dates; no hit = gap, not proof |
|
|
76
88
|
| "Draft the sponsor update" / how are we doing | `fde status` then follow `references/status.md` for the narrative |
|
|
77
89
|
| "Log that they went quiet" / trust signal | `fde log contact "…" --signal amber\|green\|red`. If they already named the color ("log that as amber"), that is the confirm — write it. If they only described the situation, playback the color once, then write. |
|
|
78
90
|
| Want the HTML fieldbook | `fde dashboard` |
|
|
79
|
-
| "Clean up the fieldbook" / hygiene / memory feels messy | `fde doctor` - walk issues in plain language; propose fixes; never auto-rewrite without confirm. Contradictions need judgment (brief vs reality) - doctor is structural; you handle meaning. |
|
|
91
|
+
| "Clean up the fieldbook" / hygiene / memory feels messy | `fde doctor` - walk issues in plain language; propose fixes; never auto-rewrite without confirm. Includes structural gaps: empty operating map (plan+), stakeholder name forks (Denise vs Denise Chen), duplicates, ship/close risks. Contradictions need judgment (brief vs reality) - doctor is structural; you handle meaning. |
|
|
80
92
|
| "Scrub this secret / redact that token" (buried line, not just last write) | `fde redact <term>` preview, then `fde redact <term> --apply` after confirm. Undo is last-write only; redact is for buried lines. Remind them to rotate the real credential. |
|
|
81
93
|
|
|
82
|
-
**The debrief verb.** Highest-frequency loop. When the FDE shares notes or says "debrief": **you** run the smart path (write notes to a temp file if needed). Show the proposed routing in plain language. Only `--apply` (or pipe prefixed lines) after they confirm. Never ask them to run the CLI. Detail: `references/debrief.md`.
|
|
94
|
+
**The debrief verb.** Highest-frequency loop. When the FDE shares notes or says "debrief": **you** run the smart path (write notes to a temp file if needed). `--smart` writes a propose file via deterministic heuristics (existing prefixes + light keywords); authentic rambling notes often land mostly in context until **you** rewrite lines with type prefixes. Show the proposed routing in plain language. Only `--apply` (or pipe prefixed lines) after they confirm. Never ask them to run the CLI. Detail: `references/debrief.md`.
|
|
83
95
|
|
|
84
96
|
CLI missing → use the manual fallbacks inside each reference (still you write files; still never ask the FDE to run setup).
|
|
85
97
|
|
|
@@ -244,6 +256,7 @@ Getting to production without surprises.
|
|
|
244
256
|
| Ready to deploy, going live, pre-flight check | ship | `references/ship.md` |
|
|
245
257
|
| Review this change, is it safe, does it match what we agreed | review | `references/review.md` |
|
|
246
258
|
| Diff grew / scope creep in the PR / "did we only build what we said" / KEEP JUSTIFY SPLIT DROP | review (+ ship if going live) | `references/review.md` Stage 1 · `references/ship.md` Intent vs diff |
|
|
259
|
+
| Wrap the session / share the thinking / catch teammates up / before I open the PR | (memory contract — session digest) | SKILL.md **On exit** — write TL;DR + decisions/why into `.fde/`; no transcript sync |
|
|
247
260
|
| "We can always revert" - need to actually test the escape route | rollback-drill | `references/rollback-drill.md` |
|
|
248
261
|
| Need to test from user perspective, "works on my machine" | qa-live | `references/qa-live.md` |
|
|
249
262
|
|
|
@@ -58,7 +58,7 @@ The spec becomes the test list - every line is something to verify after build.
|
|
|
58
58
|
- `[DEFERRED]` intentionally left for a later task (state which one)
|
|
59
59
|
Surface the results to the FDE. If any scenario fails, fix it before cleanup. This is not optional - the spec is the contract.
|
|
60
60
|
9. **Cleanup pass after it works.** Dedupe repeated mechanics into the smallest service module; behavior unchanged; re-run the same tests. If you wrote 200 lines and 50 would do, rewrite before review.
|
|
61
|
-
10. **Review gate (before merge):**
|
|
61
|
+
10. **Review gate (before merge):** three beats, in order - (a) **session digest**: TL;DR + decisions/why + scope/verification into `.fde/` so the PR carries thinking, not just code (memory contract On exit; see `review.md`); (b) **intent vs diff**: every path KEEP / JUSTIFY / SPLIT / DROP against the stated slice in `decisions.md` (see `review.md` Stage 1); (c) **safety**: blast radius honest, tests meaningful, rollback real, secrets absent. Fix real findings, re-verify, repeat until clean or blocked on a human decision.
|
|
62
62
|
11. **Log and deliver.** Update the artifacts (below). Visible progress beats invisible perfection - every 2–3 tasks something shown to a stakeholder.
|
|
63
63
|
|
|
64
64
|
**Touching existing code - classify before changing:**
|
|
@@ -6,21 +6,34 @@
|
|
|
6
6
|
|
|
7
7
|
**Who runs the CLI:** you (the agent). Never tell the FDE to type `fde debrief …`.
|
|
8
8
|
|
|
9
|
+
## Honest contract (read once)
|
|
10
|
+
|
|
11
|
+
- The `fde` CLI is **local, deterministic, no AI**. `--smart` is a **gate + writer**, not a brain.
|
|
12
|
+
- It keeps lines that already have `decision:` / `risk:` / `delivery:` / `contact:` / `next:` prefixes, plus a thin keyword pass (e.g. "we agreed", person+verb lines, "open question").
|
|
13
|
+
- Real messy notes without prefixes often route **0 useful lines** — everything else lands as a context dump. That is expected. **You are the router:** rewrite `.debrief-propose` with type prefixes, then `--apply`.
|
|
14
|
+
- `.debrief-propose` is raw lines only (no routing annotations). "Edit if mis-routed" means **rewrite the line with the right prefix**, not leave a comment in the file.
|
|
15
|
+
|
|
9
16
|
## Method (you do this work)
|
|
10
17
|
|
|
11
18
|
### Preferred path - smart debrief (messy notes)
|
|
12
19
|
|
|
13
20
|
1. Save the FDE's notes to a temp `.md` file in the workspace (or pipe stdin).
|
|
14
21
|
2. Run `fde debrief --smart <notes.md>` (or `npx fdeops debrief --smart …`).
|
|
15
|
-
3.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
3. Open `.debrief-propose`. If lines lack type prefixes, **rewrite them** before showing the FDE, e.g.:
|
|
23
|
+
- `decision: agreed chargebacks stay phase 2 — Priya`
|
|
24
|
+
- `risk: legal may reopen scope if we slip the SOW date`
|
|
25
|
+
- `contact: Priya pushed hard on Friday deck [signal:amber]`
|
|
26
|
+
- `next: send one-pager before Thursday 9am`
|
|
27
|
+
- unprefixed lines stay context color only
|
|
28
|
+
4. Show the **proposed** routing in plain language (what would become decisions, risks, contacts, next).
|
|
29
|
+
5. On FDE confirm → run `fde debrief --apply`.
|
|
30
|
+
6. On reject → stop; ask what to change; do not apply.
|
|
31
|
+
|
|
32
|
+
No invented names or quotes. If the propose looks wrong, fix prefixes with judgment then re-apply or use the fallback path.
|
|
20
33
|
|
|
21
34
|
### Fallback - you structure, then route
|
|
22
35
|
|
|
23
|
-
If `--smart` is unavailable or
|
|
36
|
+
If `--smart` is unavailable or you already have clean prefixes:
|
|
24
37
|
|
|
25
38
|
1. Extract into buckets - **only what was actually said**:
|
|
26
39
|
- **Decisions** - agreed, by whom, in their words where possible
|
|
@@ -28,7 +41,7 @@ If `--smart` is unavailable or the notes are already cleanly prefixed:
|
|
|
28
41
|
- **Stakeholder signals** - tone shifts with evidence → green/amber/red
|
|
29
42
|
- **Risks** - new / confirmed / retired
|
|
30
43
|
- **Open questions** - what to chase next
|
|
31
|
-
2. Format lines as `decision:` / `risk:` / `delivery:` / `contact:` (contacts may end with `[signal:green|amber|red]`).
|
|
44
|
+
2. Format lines as `decision:` / `risk:` / `delivery:` / `contact:` / `next:` (contacts may end with `[signal:green|amber|red]`).
|
|
32
45
|
3. Show that structured version to the FDE for confirmation.
|
|
33
46
|
4. Pipe to `fde debrief` (or write a file and run it).
|
|
34
47
|
|
|
@@ -37,7 +50,8 @@ One clarifying question max if the dump is ambiguous - then write. Never stall c
|
|
|
37
50
|
## Artifact
|
|
38
51
|
|
|
39
52
|
- Smart apply / debrief CLI writes the dated routes into the right `.fde/` files.
|
|
40
|
-
-
|
|
53
|
+
- `next:` updates the existing `## Next action` in `context.md` (collapses duplicates). Do not append a second `## Next action` heading by hand.
|
|
54
|
+
- If you must write directly: decisions → `decisions.md`; signals → `stakeholders.md` Signal history; risks → `risks.md`; next actions → fill under the template `## Next action` in `context.md`. Prefer the CLI.
|
|
41
55
|
|
|
42
56
|
## Checkpoint
|
|
43
57
|
|
|
@@ -92,7 +92,7 @@ The real spec is what people **do** when the system fails - not what the slide d
|
|
|
92
92
|
- **The hesitation.** When someone says "well, there's also this other thing we do…" - stop them, ask them to finish. The main story is what they're comfortable explaining; the hesitation is the real problem.
|
|
93
93
|
- **"Which part of the codebase do you least want to touch?"** The answer is unanimous and it's the load-bearing wall. Check it against your churn scan - when the human answer and the churn data agree, that's your first map landmark.
|
|
94
94
|
- **Shadow AI.** Someone pasting data into ChatGPT to cope = a real unmet need + an uncontrolled data risk. Note both.
|
|
95
|
-
- **Exception-led operating map.** For each real break (not the slide-deck process): what fails, who notices first, what they do today, and which artifact is trusted in that moment. Prefer exceptions over happy-path swimlanes — the workaround is the operating system. Write rows under `terrain.md` → `## Operating map (exception-led)`. If the section is missing on an older engagement, add it; never regenerate the rest of terrain. When AI is in play, also fill `## Intelligence placement` (deterministic vs LLM judgement vs human approve).
|
|
95
|
+
- **Exception-led operating map.** For each real break (not the slide-deck process): what fails, who notices first, what they do today, and which artifact is trusted in that moment. Prefer exceptions over happy-path swimlanes — the workaround is the operating system. Write rows under `terrain.md` → `## Operating map (exception-led)`. If the section is missing on an older engagement, add it; never regenerate the rest of terrain. When AI is in play, also fill `## Intelligence placement` (deterministic vs LLM judgement vs human approve). **`fde doctor` requires at least one filled exception row before plan/build/ship/close** — empty map after discover is a hygiene fail, not optional polish.
|
|
96
96
|
|
|
97
97
|
## Method - part 3: workshop facilitation
|
|
98
98
|
|
|
@@ -57,9 +57,15 @@ Five dimensions, line-specific ("line 47 fails under concurrent writes - no lock
|
|
|
57
57
|
5. Re-run tests/typechecks - state what ran.
|
|
58
58
|
6. Re-review. Repeat until Pass/Pass or a human must decide scope/product.
|
|
59
59
|
|
|
60
|
+
## Before the PR - thinking for the next reader
|
|
61
|
+
|
|
62
|
+
Code alone loses the "why." Before you call the change reviewable, run the **session digest** from the memory contract (SKILL.md On exit): TL;DR, key decisions & rationale, scope + how you verified, gotchas. Confirm with the FDE, then write into `.fde/` — `decisions.md` / `delivery.md` / `context.md`. Reviewers (or Monday-you) should answer "why this approach?" from the fieldbook, not from a chat transcript. Do **not** dump agent logs into the product repo.
|
|
63
|
+
|
|
60
64
|
## Artifact
|
|
61
65
|
|
|
62
|
-
**`decisions.md`** - each cycle logged: what was reviewed, flagged, fixed, verified. Stage 1 failures recorded with the specific mismatch.
|
|
66
|
+
**`decisions.md`** - each cycle logged: what was reviewed, flagged, fixed, verified. Stage 1 failures recorded with the specific mismatch. Digest decisions (with *why*) land here too when the slice ships.
|
|
67
|
+
|
|
68
|
+
**`delivery.md`** - scope + verification from the digest when a PR is opening; intent-vs-diff receipt stays the ship gate.
|
|
63
69
|
|
|
64
70
|
## Principles
|
|
65
71
|
|
|
@@ -68,3 +74,4 @@ Five dimensions, line-specific ("line 47 fails under concurrent writes - no lock
|
|
|
68
74
|
- Specific or silent - vague concerns waste everyone's time.
|
|
69
75
|
- No rollback path = first finding.
|
|
70
76
|
- A clean review proves this diff is safe as agreed - not that the feature was right.
|
|
77
|
+
- Judgment in `.fde/` beats transcript in git.
|
|
@@ -28,6 +28,8 @@ The org chart tells you who reports to whom. The stakeholder radar tells you who
|
|
|
28
28
|
|
|
29
29
|
**3. The 48-hour rule.** A stakeholder who goes amber has roughly 48 hours before they go red. A stakeholder who goes red is already escalating above you. Respond same-day to amber signals - not with more delivery, with a conversation.
|
|
30
30
|
|
|
31
|
+
**3b. One name per person.** If the table says "Denise Chen" and Signal history says "Denise" or "D. Chen", trust keys fork and prep lies. Consolidate to one spelling. `fde doctor` flags these identity clusters — treat that as a fix, not a nit.
|
|
32
|
+
|
|
31
33
|
**4. Detect the invisible escalation.** Three markers:
|
|
32
34
|
- Questions shift from "what are you building" to "when will it be done" - someone above is asking.
|
|
33
35
|
- A meeting gets shortened or cancelled - they're meeting without you.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Stakeholders
|
|
2
2
|
|
|
3
|
-
<!-- Champions, blockers, veto power. Trust signals: quiet = escalate.
|
|
3
|
+
<!-- Champions, blockers, veto power. Trust signals: quiet = escalate.
|
|
4
|
+
One row per real person - if Denise / Denise Chen / D. Chen appear, consolidate. -->
|
|
4
5
|
|
|
5
6
|
| Name | Role | Stance | Notes |
|
|
6
7
|
|------|------|--------|-------|
|
|
@@ -14,5 +15,6 @@
|
|
|
14
15
|
<!-- `fde log contact --signal <color>` and `fde debrief` write dated tokens here.
|
|
15
16
|
fde status/receipts read the LATEST dated [signal:...] token in this section
|
|
16
17
|
to drive the trust column - do not delete this heading, and if you rewrite
|
|
17
|
-
this file as an artifact, keep this section's entries intact.
|
|
18
|
+
this file as an artifact, keep this section's entries intact.
|
|
19
|
+
Prefer the same Name spelling as the table so trust keys don't fork. -->
|
|
18
20
|
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
## Operating map (exception-led)
|
|
10
10
|
|
|
11
|
-
<!-- How work actually runs when the happy path fails. Fill in discover; leave blank until heard/seen.
|
|
11
|
+
<!-- How work actually runs when the happy path fails. Fill in discover; leave blank until heard/seen.
|
|
12
|
+
fde doctor requires ≥1 real exception row before plan/build/ship/close. -->
|
|
12
13
|
|
|
13
14
|
| Exception / break | Who notices first | What they do today (workaround) | System of record then | Blast if wrong | Evidence |
|
|
14
15
|
|-------------------|-------------------|---------------------------------|-----------------------|----------------|----------|
|