fdeops 3.23.0 → 3.24.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/README.md CHANGED
@@ -1,107 +1,144 @@
1
1
  # FDEOps
2
2
 
3
- **Forward deployed engineering skills for AI coding agents.**
3
+ **Turn a customer request into the smallest useful delivery - and keep the evidence that it worked.**
4
4
 
5
- You're on a customer site. The AI coding agent writes code in their repo. This kit is the work around that code: the brief, who can say yes, proof on their staging then live, whether they signed off, whether they can run it after you leave.
5
+ FDEOps gives your AI coding agent a method for customer delivery: investigate the request, agree what success means, carry decisions into implementation, and prepare a handoff the customer can operate.
6
6
 
7
- Notes stay on your laptop. Their repo stays theirs. You confirm before anything is written down.
7
+ One `@fde` skill routes 30 field situations. A local CLI keeps dated records in a separate folder for each customer. An offline fieldbook makes those records easy to review before the next meeting.
8
8
 
9
- Keep the coding pack you already use. Install this next to it. FDEOps is the client work. The other pack writes the code.
9
+ Keep your existing coding skills. FDEOps supplies the customer context, scope, approvals, and acceptance criteria around their engineering work.
10
10
 
11
- <img width="1536" height="1024" alt="fdeops" src="https://github.com/user-attachments/assets/2bcb8739-55ee-445d-8a1a-8b38433b7b58" />
11
+ [Quick start](#quick-start) · [Daily workflow](#your-daily-workflow) · [30 skills](#all-30-skills) · [Usage guide](docs/USAGE.md) · [Install options](docs/install.md)
12
12
 
13
- ---
13
+ ## What you get
14
+
15
+ | Start with | Work with your agent toward | Keep on the record |
16
+ |---|---|---|
17
+ | A customer request and an unfamiliar repository | An evidence-backed problem statement and the smallest useful increment | Brief, constraints, open questions, success criteria |
18
+ | Meeting notes and changing requirements | Reviewed decisions, owners, scope changes, and next actions | Dated customer-specific memory |
19
+ | A shipped change | A readout that distinguishes promised, measured, and accepted results | Delivery evidence, acceptance status, operating handoff |
20
+
21
+ For example: a customer asks for an AI reconciliation agent by Friday. FDEOps guides your agent to inspect the existing workflow, distinguish the requested solution from the underlying problem, and establish a baseline and acceptance owner. An existing integration may be enough. The evidence should determine the plan.
22
+
23
+ This is a workflow you carry out with your agent; the CLI does not diagnose a repository or validate customer outcomes by itself.
24
+
25
+ ## Commands
26
+
27
+ One command per stage. Skills load automatically through `@fde`.
28
+
29
+ Use natural language with `@fde` in any supported host. The Claude Code plugin also provides these slash commands. The lifecycle is **Land → Discover → Plan → Ship → Outcome → Close**; your agent routes the situation to the relevant step.
30
+
31
+ | What you need | Command | Stage |
32
+ |---|---|---|
33
+ | Establish the brief and who accepts success | `/brief` | Land |
34
+ | Check the problem against the actual workflow | `/discover` | Discover |
35
+ | Sequence the smallest useful delivery from acceptance backward | `/plan` | Plan |
36
+ | Verify on customer staging and prepare the approved release | `/ship` | Ship |
37
+ | Separate promised, measured, and accepted results | `/outcome` | Outcome |
38
+ | Transfer operations and confirm the handoff | `/close` | Close |
39
+
40
+ For recurring work: `/debrief`, `/prep`, `/trust`, `/receipts`, and `/readout`. A sponsor readout is an Outcome workflow, not an additional lifecycle stage.
14
41
 
15
42
  ## Quick Start
16
43
 
17
- **Try it first, nothing installed.** In any repo:
44
+ Requires **Node.js 18+** and Git for versioned engagement memory. Install on your own machine, where you run your coding agent.
45
+
46
+ ### 1. See the workflow with fictional data
18
47
 
19
48
  ```bash
20
- npx fdeops scan
49
+ npx fdeops demo
21
50
  ```
22
51
 
23
- Two minutes. It prints what to look at on day one and the questions to ask. Local only, nothing written.
52
+ The demo creates a fictional Acme payments engagement, reviews and applies sample notes, retrieves a dated decision, prepares a meeting brief, and generates an HTML fieldbook. Open the file path printed at the end.
53
+
54
+ It runs real local commands in `~/fde-engagements/.demo/`. Re-running resets that demo; `npx fdeops demo --clean` removes it. Your real engagements are separate. No AI account is required for this CLI walkthrough. The first `npx` invocation may download the package; the CLI itself makes no network requests.
24
55
 
25
- **Then install the skill:**
56
+ Want repository reconnaissance first? Run `npx fdeops scan` in a repository. It reads local files and Git state, prints findings and questions, and writes nothing.
57
+
58
+ ### 2. Install the agent skill
26
59
 
27
60
  ```bash
28
61
  npx skills add suboss87/fdeops --skill fde
29
62
  ```
30
63
 
31
- One chat. Name the client:
64
+ In your coding agent, with the customer workspace open:
32
65
 
33
66
  ```text
34
- @fde this is client01
67
+ @fde this is client01. The customer wants to reduce manual order
68
+ reconciliation. Inspect the relevant workflow before asking questions.
69
+ Help me define the smallest useful increment and how we will prove it worked.
35
70
  ```
36
71
 
37
- That creates `~/fde-engagements/client01/.fde/` on your laptop. Paste kickoff notes in the same thread. `@fde` picks what to check. You still decide. After a meeting you get one screen: what changed, new asks, open questions, next actions. Confirm once.
72
+ Your agent sets up `~/fde-engagements/client01/.fde/` and binds the workspace to that engagement. It routes to the relevant skill, investigates the available context, and reviews judgment-based changes with you. Unknown baselines and approvals should remain unknown until confirmed.
73
+
74
+ If setup needs a terminal fallback, run `npx fdeops resume --init client01` from the customer workspace. This creates the engagement record and binds that workspace; running it with another client replaces the binding.
38
75
 
39
- Day to day: [docs/USAGE.md](docs/USAGE.md).
76
+ ### 3. Start the daily loop
77
+
78
+ ```text
79
+ @fde Debrief: <meeting notes>
80
+ @fde Prep me for the next customer meeting.
81
+ @fde Draft a readout. Separate what we promised, measured, and the customer accepted.
82
+ ```
83
+
84
+ Open your engagement's fieldbook:
85
+
86
+ ```bash
87
+ npx fdeops dashboard --open
88
+ ```
89
+
90
+ Continue with the [five-minute walkthrough and daily guide](docs/USAGE.md).
40
91
 
41
92
  <details>
42
- <summary><b>Claude Code</b></summary>
93
+ <summary><b>Claude Code plugin</b></summary>
43
94
 
44
95
  ```text
45
96
  /plugin marketplace add suboss87/fdeops
46
97
  /plugin install fdeops@fdeops
47
98
  ```
48
99
 
49
- Hooks resume where you left off. Slash commands match the table below.
100
+ Includes slash commands and session hooks. The plugin does not add a bare `fde` command to your shell; use `npx fdeops <command>` or install the CLI globally. [Install details](docs/install.md).
50
101
 
51
102
  </details>
52
103
 
53
104
  <details>
54
- <summary><b>Cursor</b></summary>
105
+ <summary><b>Cursor, Codex, Gemini CLI, and Copilot</b></summary>
55
106
 
56
- After the skill install, in the **client repo** you have open (pointer, not a second pack):
107
+ After installing the skill, run this in the customer workspace to add host pointers:
57
108
 
58
109
  ```bash
59
110
  npx fdeops adapters .
60
111
  ```
61
112
 
62
- See [adapters/](adapters/README.md).
113
+ Adapters point at the same skill rather than copying its method. This command adds instruction files to the workspace; review them as you would other repository changes. Session hooks are Claude Code-first; other hosts use the skill and CLI on demand. [Adapters](adapters/README.md).
63
114
 
64
115
  </details>
65
116
 
66
117
  <details>
67
- <summary><b>Air-gap, PATH, override</b></summary>
118
+ <summary><b>Install from a checkout / offline preparation</b></summary>
68
119
 
69
- ```bash
70
- git clone https://github.com/suboss87/fdeops.git && node bin/install.js
71
- ```
72
-
73
- If the agent cannot create the folder:
120
+ On a connected machine:
74
121
 
75
122
  ```bash
76
- npx fdeops resume --init client01 # ~/fde-engagements/client01
123
+ git clone https://github.com/suboss87/fdeops.git
124
+ cd fdeops
125
+ node bin/install.js
77
126
  ```
78
127
 
79
- Requires Node.js >= 18. Override: `FDEOPS_ENGAGEMENT`. See [docs/install.md](docs/install.md). Try the loop: `npx fdeops demo`.
128
+ For an offline machine, transfer the checkout first, then run `node bin/install.js` there. The installer copies the skill and hooks into your local Claude directories. [Install options and overrides](docs/install.md).
80
129
 
81
130
  </details>
82
131
 
83
- ---
84
-
85
- ## Commands
86
-
87
- One command per stage. Skills load automatically.
132
+ ## Your daily workflow
88
133
 
89
- Six stages, same order every job: Land, Discover, Plan, Ship, Outcome, Close.
134
+ | When | In your agent | In the fieldbook |
135
+ |---|---|---|
136
+ | Start the day | `@fde Where did we leave off with this client?` | Review the next action, risks, and gaps needing attention |
137
+ | Before a meeting | `@fde Prep me for the sponsor check-in.` | Review the brief, stakeholders, and recent decisions |
138
+ | After a meeting | `@fde Debrief: <notes>` | Regenerate after reviewing and applying the changes |
139
+ | Before reporting value | `@fde Draft the customer readout with evidence and unresolved gaps.` | Check the promised → measured → accepted ledger |
90
140
 
91
- | What you're doing | Command | Stage |
92
- |-------------------|---------|-------|
93
- | First days. Get the brief. Name who signs. | `/brief` | Land |
94
- | Check the brief is the real job. | `/discover` | Discover |
95
- | Sequence from done, not from the ticket. | `/plan` | Plan |
96
- | Prove it on their staging, then go live. | `/ship` | Ship |
97
- | What you promised, measured, and who accepted. | `/outcome` | Outcome |
98
- | Hand it over. They run it without you. | `/close` | Close |
99
-
100
- Same `@fde`, when you need them: `/debrief` (notes into the record), `/prep` (one page before you walk in), `/trust` (process gap, or they stopped trusting you), `/receipts` (a dated line, or it did not happen), `/readout` (Friday page for the sponsor; not a seventh stage).
101
-
102
- You can also just say it: naming a client, a POC, changing their checkout, going live, asking what was agreed. A typo in a repo that is not a client job can skip this. A named client, a POC, or go-live cannot.
103
-
104
- ---
141
+ `npx fdeops dashboard --all --open` shows every engagement. The fieldbook is a **read-only snapshot**, with search, engagement views, and prompts you can copy into your agent for follow-up work. It does not run the agent or edit memory. Regenerate it after changing the record; the generation date tells you how fresh it is.
105
142
 
106
143
  ## All 30 Skills
107
144
 
@@ -177,161 +214,83 @@ Optional pull: you add the source MCP; we **pull** on request. [mcp/recipes/](mc
177
214
 
178
215
  ## How Skills Work
179
216
 
180
- One `@fde`. One file per situation. One folder per client.
181
-
182
- ```
183
- "@fde this is client01" creates ~/fde-engagements/client01/.fde/
184
- /brief or English the AI coding agent loads skills/fde/SKILL.md
185
- │ routes. you never pick a skill by name
186
- ▼
187
- references/<one>.md one skill, then stop
188
- │
189
- ▼
190
- fde CLI (local) dates, gates, redacts. no network
191
- │ after you confirm
192
- ▼
193
- ~/fde-engagements/client01/.fde/
217
+ ```text
218
+ Customer request + repository + available notes
219
+ ↓
220
+ @fde → one relevant reference → investigation and proposed next step
221
+ ↓
222
+ You review judgment, scope, and commitments
223
+ ↓
224
+ Local CLI + customer-specific .fde/ records
225
+ ↓
226
+ Meeting prep · dated receipts · offline fieldbook · customer readout
194
227
  ```
195
228
 
196
- **A dated line, or it did not happen.** Promised → measured → accepted. If it is not in `.fde/`, it is not on the record.
229
+ The method lives once in [`skills/fde/SKILL.md`](skills/fde/SKILL.md) and its references. Adapters point to it. The CLI handles deterministic file operations, dates, gates, and output redaction. Your coding agent supplies interpretation; you retain responsibility for decisions and customer approval.
197
230
 
198
- **Confirm, then it is written.** The CLI stays on your laptop: git and files, no network. The AI coding agent runs the command. You say yes. Then it is in the folder.
231
+ Agent-proposed judgments are reviewed before they enter the record. Setup, explicitly invoked CLI writes, and configured session hooks can write local files without a separate chat confirmation. [Operating rules](docs/OPERATIONS.md).
199
232
 
200
- **The record is on your laptop.** Change hosts, install `@fde` on the new one, keep talking. The notes are not inside any vendor.
233
+ ## Engagement memory (`.fde/`)
201
234
 
202
- One skill hosts load: `skills/fde/SKILL.md`. It opens one file in `skills/fde/references/` and stops. Slash commands live in `.claude/commands/`. The local CLI is `bin/fde.js` (git + files, no network). Layout: [docs/REPO_LAYOUT.md](docs/REPO_LAYOUT.md).
235
+ One folder per client, stored by default at `~/fde-engagements/<client>/.fde/`. Plain Markdown and local Git history keep the record portable across supported agent hosts.
203
236
 
204
- ---
237
+ | File | What it answers |
238
+ |---|---|
239
+ | `context.md` | Where are we, and what happens next? |
240
+ | `brief.md` / `success.md` | What did the customer request; what counts as success; who accepts it? |
241
+ | `reality.md` / `terrain.md` | What did investigation reveal? |
242
+ | `stakeholders.md` / `trust-profile.md` | Who is involved; what access and approval constraints apply? |
243
+ | `decisions.md` / `risks.md` | What changed, why, and what could block delivery? |
244
+ | `delivery.md` | What shipped; what evidence, rollback, and acceptance were recorded? |
205
245
 
206
- ## Engagement memory (`.fde/`)
246
+ Memory stores what you recorded. A dated note is evidence of that record, not independent proof that a result occurred or that a customer approved it. Keep supporting sources and explicit uncertainty with the claim.
207
247
 
208
- One folder per client. Plain markdown. Grep it, copy it, take it into a meeting.
248
+ Use `FDEOPS_ENGAGEMENTS_ROOT` to change the storage root or `FDEOPS_ENGAGEMENT` for an explicit engagement override. See [install options](docs/install.md#advanced-engagement-overrides).
209
249
 
210
- | File | Holds |
211
- |------|-------|
212
- | `context.md` | Where you are |
213
- | `brief.md` / `success.md` | What they asked; what “done” is and who signs |
214
- | `reality.md` / `terrain.md` | The real problem; the map |
215
- | `stakeholders.md` | `[signal:green\|amber\|red]` |
216
- | `trust-profile.md` | Sacred data, AI policy, approval chain |
217
- | `decisions.md` / `risks.md` / `delivery.md` | Dated choices; live risks; what shipped and how it rolls back |
250
+ [Memory schema](docs/schema.md) · [Multi-client usage](docs/USAGE.md#multiple-engagements)
218
251
 
219
- Schema: [docs/schema.md](docs/schema.md). Local HTML: `npx fdeops dashboard`.
252
+ ## Principles
220
253
 
221
- ---
254
+ - Investigate the actual workflow before committing to a solution.
255
+ - Define a small useful increment, a success criterion, and an acceptance owner.
256
+ - Keep observations, assumptions, and customer decisions distinguishable.
257
+ - Verify the result in the customer environment and preserve its evidence.
258
+ - Separate promised, measured, and accepted outcomes.
259
+ - Hand over something the customer can operate; keep each customer's record separate.
222
260
 
223
261
  ## Who this is for
224
262
 
225
- You sit with a customer's team. An AI coding agent writes in their repo. You need a record of the brief, who can say yes, what went live, and whether they signed off.
226
-
227
- If you ship your own company's product from HQ, with no customer team that has to run it after you leave, you do not need this kit.
263
+ Forward deployed engineers, technical consultants, and solutions engineers working with a customer team that must accept and operate the result. Especially useful when you return across sessions or switch between several engagements.
228
264
 
229
- ---
265
+ FDEOps adds customer-delivery workflows to your existing coding tools. It does not replace code review, engineering tests, customer relationships, or your organization's release process. It does not provide hosted synchronization or a CRM.
230
266
 
231
267
  ## Your data stays yours
232
268
 
233
- The **CLI** is local: git + files, no network, no telemetry. The **host model** sees `.fde/` the agent loads (usually a bounded `context.md`) and any client code you open. It must not see `<private>` blocks - redacted from CLI, dashboard, and hooks; do not paste them or open them with file tools. Nothing is written until you confirm. `~/fde-engagements` is in `$HOME`; iCloud/Dropbox is an NDA incident waiting.
269
+ - **CLI:** local Git and file operations; no network requests or telemetry. Package installation can require network access.
270
+ - **Agent:** your chosen host model sees the context and code you give it. Local storage does not make a cloud-hosted model local.
271
+ - **Private notes:** `<private>` blocks are redacted from CLI, dashboard, and hook outputs. Do not open raw private blocks with agent file tools or paste them into chat.
272
+ - **Storage:** customer records live outside the customer repository by default. Keep the engagement folder out of shared Git and cloud-synced folders unless your customer policy permits them.
273
+ - **Integrations:** optional source MCPs pull on request through your host. They have their own permissions and data boundaries; the CLI does not push to external services.
234
274
 
235
275
  [PRIVACY.md](PRIVACY.md) · [SECURITY.md](SECURITY.md)
236
276
 
237
- ---
238
-
239
- ## Why FDEOps?
240
-
241
- AI coding agents are built for a repo, not for a client. Left alone they skip who signs, whether the brief is true, and whether anyone accepted the number. Monday they start from the ticket again.
242
-
243
- This is the kit you take on site. `@fde` runs the client work around the code. A local command dates every decision. The notes are markdown on your laptop. You confirm; then it is on the record.
244
-
245
- ---
246
-
247
- ## Principles
248
-
249
- - **Who signs** - name them in the first days
250
- - **Brief vs real job** - check the floor, not only the slide
251
- - **Back from done** - sequence from signed-off, not from the ticket
252
- - **Their staging then live** - prove it where they operate, then go live
253
- - **Promised, measured, accepted** - a number nobody signed is claimed, not delivered
254
- - **They run it** - if they cannot operate it without you, you are not done
255
- - **A dated line, or it did not happen** - these files get defended in the room
256
- - **One customer, one folder** - context never bleeds
257
- - **The kit says what to check. You still decide.**
277
+ ## Quality and contributing
258
278
 
259
- ---
279
+ The repository includes deterministic CLI tests, structural checks, and skill-routing evaluations. These verify defined behaviors; they are not a claim of measured customer productivity or fully autonomous delivery.
260
280
 
261
- ## Project Structure
281
+ From a checkout:
262
282
 
283
+ ```bash
284
+ npm run check
285
+ npm run test:skill-routing
263
286
  ```
264
- fdeops/
265
- ├── skills/fde/ # the one skill hosts load
266
- │ ├── SKILL.md # router
267
- │ └── references/ # 30 skills + overlays (you never pick)
268
- │ ├── land.md # Land
269
- │ ├── audit.md
270
- │ ├── who-decides.md
271
- │ ├── earn-trust.md
272
- │ ├── hold-scope.md
273
- │ ├── discover.md # Discover
274
- │ ├── test-assumptions.md
275
- │ ├── score-use-cases.md
276
- │ ├── poc.md
277
- │ ├── plan.md # Plan
278
- │ ├── business-case.md
279
- │ ├── three-options.md
280
- │ ├── pick-three.md
281
- │ ├── ship.md # Ship
282
- │ ├── what-breaks.md
283
- │ ├── rescue.md
284
- │ ├── review.md
285
- │ ├── rollback.md
286
- │ ├── readout.md # Outcome
287
- │ ├── demo-prep.md
288
- │ ├── debrief.md
289
- │ ├── board-memo.md
290
- │ ├── dashboard.md
291
- │ ├── ingest.md
292
- │ ├── connect.md
293
- │ ├── close.md # Close
294
- │ ├── runbook.md
295
- │ ├── switch-clients.md
296
- │ ├── encode-pattern.md
297
- │ ├── red-team.md
298
- │ ├── ai.md # overlays (on signal)
299
- │ ├── artifacts.md
300
- │ ├── eval-pack.md
301
- │ ├── fintech.md
302
- │ ├── healthcare.md
303
- │ └── gov.md
304
- ├── .claude/commands/ # slash commands (each loads @fde)
305
- │ ├── brief.md
306
- │ ├── discover.md
307
- │ ├── plan.md
308
- │ ├── ship.md
309
- │ ├── outcome.md
310
- │ ├── close.md
311
- │ ├── trust.md
312
- │ ├── receipts.md
313
- │ ├── debrief.md
314
- │ ├── prep.md
315
- │ └── readout.md
316
- ├── .claude-plugin/ # Claude Code marketplace
317
- ├── bin/ # local CLI: git + files, no network
318
- ├── hooks/ # session-start / session-stop / pre-compact
319
- ├── adapters/ # Cursor, Gemini, Copilot, Codex pointers
320
- ├── templates/.fde/ # memory files created on first client
321
- ├── examples/ # fictional walkthroughs
322
- ├── mcp/ # optional ingest + source recipes
323
- ├── evals/ # routing checks
324
- └── docs/ # usage, schema, install
325
- ```
326
-
327
- ---
328
287
 
329
- ## Contributing
288
+ Live routing evaluation depends on the configured provider; inspect the output for skipped live checks. See [`evals/`](evals/) for scenarios and [`docs/REPO_LAYOUT.md`](docs/REPO_LAYOUT.md) for the code layout.
330
289
 
331
- **[Subash Natarajan](https://www.linkedin.com/in/subashn/)**. [Issues](https://github.com/suboss87/fdeops/issues) · [Discussions](https://github.com/suboss87/fdeops/discussions) · [CONTRIBUTING.md](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md)
290
+ Maintained by **[Subash Natarajan](https://www.linkedin.com/in/subashn/)**. Share bugs and anonymized field situations through [Issues](https://github.com/suboss87/fdeops/issues) or [Discussions](https://github.com/suboss87/fdeops/discussions). Keep customer data out of contributions.
332
291
 
333
- Skills should be **specific** (actionable steps), **verifiable** (an artifact in `.fde/`), and **minimal**. The `fde` CLI stays local-only.
292
+ [CONTRIBUTING.md](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md)
334
293
 
335
294
  ## License
336
295
 
337
- MIT - use these skills on client work.
296
+ [MIT](LICENSE) - use these skills on client work.
package/bin/fde.js CHANGED
@@ -25,7 +25,7 @@
25
25
  * fde capture session-end snapshot → context.md (hooks use this)
26
26
  * fde preserve pre-compaction context snapshot (hook-internal; hooks use this)
27
27
  * fde status [--all] value ledger first, then trust (pass --all for portfolio)
28
- * fde dashboard [--all] current engagement fieldbook (default) or all (--all)
28
+ * fde dashboard [--all] [--open] [--out <path>] bound fieldbook, or all (--all)
29
29
  * fde vault derived Obsidian vault of the fieldbook (disposable; --redacted)
30
30
  */
31
31
  const fs = require('fs')
@@ -799,7 +799,7 @@ function firstLine(md, maxLen) {
799
799
  // not carry Working theory / Evidence / Differs from brief, do not scrape a
800
800
  // first line that might be the inherited brief and label it truth.
801
801
  function parseReality(md, maxLen) {
802
- const theory = (md.match(/\*\*Working theory:\*\*\s*(.*)/i) || [])[1]
802
+ const theory = (md.match(/\*\*Working theory:\*\*[^\S\r\n]*(.*)/i) || [])[1]
803
803
  const hasSchema = /\*\*(Working theory|Evidence|Differs from brief how):\*\*/i.test(md)
804
804
  const theoryText = (theory || '').trim()
805
805
  if (theoryText) {
@@ -961,6 +961,7 @@ function colIndex(headers, rx) { return headers.findIndex(h => rx.test(h)) }
961
961
  const {
962
962
  personFromSignalText,
963
963
  signalSubjectKey,
964
+ isSignalNameNoise,
964
965
  nextActionLine,
965
966
  computeSignals,
966
967
  resumeTriage,
@@ -1003,10 +1004,14 @@ function displayNameFromSignalText(text) {
1003
1004
  const person = personFromSignalText(text)
1004
1005
  if (person) return person
1005
1006
  const t = String(text).trim()
1006
- const proper = t.match(/^([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/)
1007
- if (proper) return proper[1]
1008
- const word = t.split(/\s+/).find(w => w && !/^(dr|mr|mrs|ms)\.?$/i.test(w))
1009
- return word ? word.replace(/[^A-Za-z0-9.-]/g, '') : t.slice(0, 24)
1007
+ const words = t.split(/\s+/).filter(w => {
1008
+ const bare = w.replace(/[^A-Za-z0-9.-]/g, '')
1009
+ return bare.length >= 2 && !isSignalNameNoise(bare) && !/^(dr|mr|mrs|ms)\.?$/i.test(bare)
1010
+ })
1011
+ if (!words.length) return ''
1012
+ const proper = words.find(w => /^[A-Z][a-z]+(?:\s+[A-Z][a-z]+)?$/.test(w) || /^[A-Z]{2,}$/.test(w))
1013
+ if (proper && !isSignalNameNoise(proper)) return proper.replace(/[^A-Za-z0-9. -]/g, '')
1014
+ return words.slice(0, 2).join(' ').replace(/[^A-Za-z0-9. -]/g, '')
1010
1015
  }
1011
1016
 
1012
1017
  // Stakeholders for prep/dashboard: table rows PLUS people who only appear in
@@ -1063,8 +1068,10 @@ function extractStakeholders(eng) {
1063
1068
  const cur = byKey.get(key)
1064
1069
  byKey.set(key, { ...cur, signal: h.signal, note: cur.note || h.text.slice(0, 80) })
1065
1070
  } else {
1071
+ const name = displayNameFromSignalText(h.text)
1072
+ if (!name || isSignalNameNoise(name)) continue
1066
1073
  byKey.set(key, {
1067
- name: displayNameFromSignalText(h.text),
1074
+ name,
1068
1075
  role: '',
1069
1076
  note: h.text.slice(0, 80),
1070
1077
  signal: h.signal,
@@ -2685,7 +2692,8 @@ function findAmbiguousStakeholders(eng) {
2685
2692
  for (const name of forms) {
2686
2693
  const key = signalSubjectKey(name)
2687
2694
  if (!key || key.startsWith('anon:')) continue
2688
- const norm = name.replace(/\s+/g, ' ').trim().toLowerCase()
2695
+ const norm = name.replace(/\([^)]*\)/g, '').replace(/\s+/g, ' ').trim().toLowerCase()
2696
+ if (!norm || norm.length < 2) continue
2689
2697
  if (!byKey.has(key)) byKey.set(key, new Set())
2690
2698
  byKey.get(key).add(norm)
2691
2699
  }
@@ -2773,6 +2781,7 @@ function parseValueLedger(eng) {
2773
2781
  promised: colIndex(table.headers, /promised/i),
2774
2782
  measured: colIndex(table.headers, /measured/i),
2775
2783
  accepted: colIndex(table.headers, /accept/i),
2784
+ evidence: colIndex(table.headers, /evidence/i),
2776
2785
  }
2777
2786
  const cell = (row, i) => (i === -1 ? '' : String(row[i] || '').trim())
2778
2787
  const rows = []
@@ -2787,7 +2796,8 @@ function parseValueLedger(eng) {
2787
2796
  let state = 'unmeasured'
2788
2797
  if (!measuredPending && acceptedPending) state = 'claimed'
2789
2798
  else if (!measuredPending) state = 'accepted'
2790
- rows.push({ slice, promised, measured, accepted, state })
2799
+ const evidence = cell(row, idx.evidence)
2800
+ rows.push({ slice, promised, measured, accepted, evidence, evidenceMissing: !evidence || PENDING_CELL_RE.test(evidence), state })
2791
2801
  }
2792
2802
  return { rows, columnMissing: idx.accepted === -1 }
2793
2803
  }
@@ -3330,6 +3340,7 @@ function cmdDashboard(args) {
3330
3340
  engagements.forEach(e => {
3331
3341
  const ctx = readClean(e.dir, 'context.md')
3332
3342
  e.next = (sectionBody(ctx, 'Next action', { lastNonEmpty: true }).split('\n').find(l => l.trim()) || '').trim()
3343
+ e.next = e.next.replace(/^[-*]\s+/, '')
3333
3344
  e.hasNext = !!e.next
3334
3345
  e.lastSession = firstLine(sectionBody(ctx, 'Current state'), 240)
3335
3346
  // 220, not 140 - now that brief/reality each get their own full-width
@@ -3346,6 +3357,7 @@ function cmdDashboard(args) {
3346
3357
  e.risks = extractRisks(e.dir)
3347
3358
  e.log = extractLog(e.dir)
3348
3359
  e.stats = extractStats(e.dir)
3360
+ e.valueRows = parseValueLedger(e.dir).rows
3349
3361
  e.highRisks = e.risks.filter(r => r.severity === 'high').length
3350
3362
  e.quiet = e.signals.ageDays !== Infinity && e.signals.ageDays >= 3
3351
3363
  e.slug = slugify(e.name)
@@ -3363,10 +3375,11 @@ function cmdDashboard(args) {
3363
3375
  ...e.log.map(g => g.text), ...e.risks.map(r => r.text),
3364
3376
  ...e.stakeholders.map(p => `${p.name} ${p.role} ${p.note}`),
3365
3377
  ...e.moreSections.map(s => s.title),
3378
+ ...e.valueRows.map(r => `${r.slice} ${r.promised} ${r.measured} ${r.accepted} ${r.evidence}`),
3366
3379
  ].join(' ').toLowerCase())
3367
3380
  })
3368
3381
 
3369
- const html = render.buildFieldbookHtml({ engagements, today })
3382
+ const html = render.buildFieldbookHtml({ engagements, today, generatedAt: new Date().toISOString() })
3370
3383
 
3371
3384
  try {
3372
3385
  fs.mkdirSync(path.dirname(outPath), { recursive: true })
@@ -3745,7 +3758,7 @@ function printUsage() {
3745
3758
  fde owner [set email] who keeps this engagement record
3746
3759
  fde receipts <term> "what did we agree?" with dates
3747
3760
  fde status [--all] value ledger, then trust (pass --all for full portfolio)
3748
- fde dashboard [--all] current engagement fieldbook (pass --all for every client)
3761
+ fde dashboard [--all] [--open] [--out <path>] bound fieldbook (pass --all for every client)
3749
3762
  fde vault derived Obsidian vault of every engagement (--current for one, --redacted for a shared screen, --out <dir>)
3750
3763
  hooks call these; you do not: capture (session-end snapshot), preserve (pre-compaction snapshot)
3751
3764
  env FDEOPS_ENGAGEMENTS_ROOT override ~/fde-engagements (init/status/dashboard/registry)