create-battle-plan 1.2.0 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-battle-plan",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Scaffold a Battle Plan project — a markdown-based context system for LLM-powered project management",
5
5
  "bin": {
6
6
  "create-battle-plan": "./bin/cli.js"
@@ -72,6 +72,18 @@ Run these in parallel:
72
72
 
73
73
  The battle plan is your orientation layer — read it on demand, not by default. `docs/today.md` is what the user sees, so lead with that.
74
74
 
75
+ ## Step 1.6: Events context-debt warning (silent unless overdue)
76
+
77
+ `events.yml` carries past events that haven't been gated yet (transcript / spawned-tasks / insight not captured). Wrap-up's Step 4.5d handles these — but if the user skipped it or no wrap-up ran, they accumulate as context-debt.
78
+
79
+ Run `node tools/events/due-for-gate.js --json` and check whether any returned event has `end || start < (now - 2 days)`. If so, surface in the briefing:
80
+
81
+ > ⚠️ **Context-debt: N past event(s) ungated >2d** — EVT-{id} {title} ({start date}). Run `/wrap-up` Step 4.5d to capture transcript + insights.
82
+
83
+ Don't walk the gate during good-morning — wrap-up is the right time for that. Just flag it so the user knows.
84
+
85
+ If no events are returned, or none are >2d old, this step is silent.
86
+
75
87
  ## Step 2: Present the Briefing
76
88
 
77
89
  Print a compact morning report with these sections:
@@ -97,6 +109,7 @@ Pull all defined metrics from `metrics.yml`. If targets are defined in the battl
97
109
 
98
110
  End with 2-3 short questions:
99
111
  - "Anything happen since we last talked? Replies, updates, new info?"
112
+ - "Any new events to schedule? Calls, demos, meetings I should add to `events.yml`?" — if they name anything, call `node tools/events/add.js --title "..." --start "ISO" [--lead-id <id-if-any>] --source manual-chat`.
100
113
  - If there are stale items (no progress for 2+ days), ask about them specifically
101
114
  - If a key deliverable is outstanding, ask about it
102
115
 
@@ -0,0 +1,93 @@
1
+ ---
2
+ description: Walk through every open task lane-by-lane with a multi-choice action menu. Closes stale items, merges duplicates, re-lanes mis-classified work. Stamps last_triage_at when done.
3
+ ---
4
+
5
+ # Weekly Triage
6
+
7
+ Run this once a week to keep `tasks.yml` honest. The user clicks through each open task with arrow-key choices; you apply each decision to `tasks.yml` immediately.
8
+
9
+ ## Step 0 — Anchor to real time
10
+
11
+ Run `date` to anchor today's date. Don't infer from session context.
12
+
13
+ ## Step 1 — Gather state
14
+
15
+ Run `node tools/tasks/triage.js --json` and parse the output. Also run `git log --oneline -30` for context on recent commits.
16
+
17
+ ## Step 2 — Briefing
18
+
19
+ Tell the user the headline numbers from the report's `stats` block:
20
+
21
+ - Total open
22
+ - Overdue
23
+ - Stale (≥ stale_threshold_days, not overdue)
24
+ - Distribution by lane
25
+
26
+ Surface anything notable: the worst overdue, the most stale lane, any drift flags.
27
+
28
+ Ask:
29
+
30
+ > Walk through lane-by-lane in order (build → outreach → discovery → infra → fundraising → meta), or start with a specific lane?
31
+
32
+ ## Step 3 — Walk one task at a time
33
+
34
+ For each open task in the chosen order:
35
+
36
+ 1. Show 3-4 lines: title, key flags, a one-line context snippet, and the script's `suggestion` if any.
37
+ 2. Use `AskUserQuestion` with these standard options (label them concisely — these are the most common decisions):
38
+ - **Done** — task is complete
39
+ - **Snooze 7 days** — defer; resurfaces in a week
40
+ - **Demote** — drop priority by one
41
+ - **Merge into TASK-X** — kill this task, fold into another (ask for X)
42
+ 3. The user can pick "Other" to type a custom action: `delete`, `promote`, `keep`, `lane <LANE>`, `priority <N>`, `snooze <N>` for a custom snooze window, etc.
43
+
44
+ **Pacing:** present **one task at a time**. If the user says "go faster" or "skip ahead", batch 3-5 per message. If they say "keep all of these", apply `keep` to the whole lane.
45
+
46
+ ## Step 4 — Apply decisions immediately (no batching)
47
+
48
+ For each user choice, Edit `tasks.yml` right away. Map decisions:
49
+
50
+ | Choice | Field changes |
51
+ |---|---|
52
+ | `done` | `status: done`, `done_at: <today>` |
53
+ | `snooze N` | `status: snoozed`, `snoozed_until: <today + N days>` |
54
+ | `demote` | `priority: priority + 1` (capped at 3) |
55
+ | `promote` | `priority: priority - 1` (floored at 1) |
56
+ | `merge X` | `status: cancelled`, prepend `"Merged into TASK-X — <today>"` to context |
57
+ | `delete` | `status: cancelled`, prepend `"Deleted via triage <today>"` to context |
58
+ | `lane <LANE>` | `lane: <LANE>` (validate against VALID_LANES in lib/tasks.js) |
59
+ | `priority <N>` | `priority: <N>` |
60
+ | `keep` | no change |
61
+
62
+ The "Merge into X" action is high-leverage when triaging a long pile — collapse scattered concerns into a single owner with consolidated context.
63
+
64
+ ## Step 5 — Wrap up
65
+
66
+ Three things, in order:
67
+
68
+ ### 5a. Stamp `last_triage_at`
69
+
70
+ This suppresses the SessionStart triage-due nudge until the next cycle. Without this, the nudge keeps firing on every session start and becomes spam.
71
+
72
+ ```bash
73
+ node -e "const t=require('./tools/tasks/lib/tasks'); const s=t.load(); s.last_triage_at='$(date +%Y-%m-%d)'; t.save(s);"
74
+ ```
75
+
76
+ ### 5b. Regenerate today.md
77
+
78
+ ```bash
79
+ node tools/tasks/render-today.js
80
+ ```
81
+
82
+ ### 5c. Print summary
83
+
84
+ - Tasks closed: N
85
+ - Tasks snoozed: N
86
+ - Tasks merged: N
87
+ - Tasks re-laned: N
88
+ - Open tasks remaining: N (was N before)
89
+ - Implications-drift heads-up: list any tasks where the linked doc still hasn't moved and the user kept the task open
90
+
91
+ ## Tone
92
+
93
+ Direct. Bounded decisions. Don't editorialize on each task — you're a UI, not a coach.
@@ -42,6 +42,64 @@ With all info gathered, run the full cascade from CLAUDE.md:
42
42
  4. Run `tools/touch-date.sh` on every modified file
43
43
  5. Run `tools/verify-cascade.sh` — fix any errors
44
44
 
45
+ ## Step 4.5: Task hygiene — REQUIRED daily
46
+
47
+ This step keeps `tasks.yml` honest. Run before regenerating `today.md` so any closures land in the day's surface.
48
+
49
+ **4.5a — Detect drift (tasks that should be closed but aren't):**
50
+
51
+ Run `node tools/tasks/triage.js --json` and scan the output for any open task with non-empty `recent_commits` (commits mentioning `TASK-N` since the task was created). For each:
52
+ - Surface to the user: "TASK-{id} ({title}) — recent commit '{subject}' suggests it's done. Mark closed?"
53
+ - If yes → set `status: done`, `done_at: <today>` via Edit on `tasks.yml`. If no → leave it.
54
+
55
+ Also surface any open task with `implications_drift` flagged (linked doc untouched since task created) — the user may have closed the work without updating the doc, OR the doc work is genuinely pending.
56
+
57
+ **4.5b — Archive old closed tasks:**
58
+
59
+ Run `node tools/tasks/archive.js`. This moves any `status: done|cancelled` row with `done_at < today - 14d` into `tasks-archive.yaml` (created on first run). Idempotent. Default retention = 14 days; pass `--days N` to override or `--all` to archive everything closed.
60
+
61
+ **4.5c — Regenerate today.md:**
62
+
63
+ Run `node tools/tasks/render-today.js --quiet` so today's surface reflects any closures from 4.5a.
64
+
65
+ If 4.5a/4.5b changed anything, list it in Step 5 ("Task hygiene: N closed via git-drift, M archived").
66
+
67
+ **4.5d — Events gate (REQUIRED when past events exist):**
68
+
69
+ `events.yml` is the single source of truth for time-based events (calls, demos, meetings). Past events that haven't been "gated" (transcript + insights + spawned tasks captured) accumulate as context-debt. This step cycles the user through each one so context lands in the right docs before the event is archived.
70
+
71
+ Run `node tools/events/due-for-gate.js --json` and parse. If empty, this step is silent — skip to Step 5.
72
+
73
+ For each event returned, walk the user through them one-by-one (ONE at a time, sequential — do NOT batch):
74
+
75
+ ```
76
+ Gate EVT-{id} — {title} ({start HH:MM}, type={type})
77
+ [a] Transcript path? (drag/paste a file path, or "none" for no recording)
78
+ [b] Hypothesis impacts? (comma-separated like "H47, H49", or "none" — skip if your project has no hypothesis tracker)
79
+ [c] Tasks spawned? (free-text bullets; each becomes a `tools/tasks/add.js` call)
80
+ [d] Insight worth saving? (yes → append to the relevant cascade-target doc; no/skip otherwise)
81
+ [skip] ← leave gate open, will resurface tomorrow
82
+ ```
83
+
84
+ **Apply each answer immediately:**
85
+
86
+ - (a) → If a path was provided, copy/symlink the raw transcript to `docs/archive/transcripts/<slug>-YYYY-MM-DD.<ext>` (save raw verbatim FIRST, then distill). Store the final path on the event's `transcript_path` field via the events lib:
87
+ ```js
88
+ const E = require('./tools/events/lib/events');
89
+ const state = E.load();
90
+ E.upsert(state, { id: <id>, transcript_path: '<path>' });
91
+ E.save(state);
92
+ ```
93
+ - (b) → For each `H{n}`, append a short `> **[UPDATE YYYY-MM-DD · Source: EVT-{id} {title}]**` block to `docs/validation/hypotheses.md` (or your equivalent) near the relevant hypothesis. Store the list in the event's `hypothesis_impacts` field via the events lib. Skip if no hypothesis tracker exists.
94
+ - (c) → For each task description, run `node tools/tasks/add.js "<title>" [--due ...] [--lane ...] [--priority ...]`. Capture returned `TASK-N` ids into the event's `spawned_tasks` field.
95
+ - (d) → Append a dated section to the relevant cascade-target doc (e.g. `docs/validation/external-insights.md` for conversation findings) using its `Compression: chronological` format: `## YYYY-MM-DD — <title>` heading.
96
+ - After ALL non-skipped answers applied → stamp `gate_completed_at` (ISO now) on the event via the events lib.
97
+ - If the user picked `[skip]` → leave `gate_completed_at` null; the event resurfaces in tomorrow's wrap-up.
98
+
99
+ **Outreach add-on (Profile B only):** if `outreach/leads.csv` exists, also ask `[e] Lead status change? (e.g. call_done → verbal, or call_done → dead; "none" if unchanged)`. Update `leads.csv` via the Node load-mutate-save pattern in `tools/outreach/lib/leads.js`, then `node tools/outreach/sync-metrics.js`.
100
+
101
+ **Finally:** run `node tools/events/archive.js`. Moves gated events (terminal status + `gate_completed_at` set) → `events-archive.yml`. Idempotent.
102
+
45
103
  ## Step 5: Report
46
104
 
47
105
  Print:
@@ -49,6 +107,7 @@ Print:
49
107
  - **Docs updated** (list of files touched)
50
108
  - **Verification warnings** (if any)
51
109
  - **Tomorrow's top priorities** (carry-forwards + known agenda items)
110
+ - **Task hygiene** (if Step 4.5 changed anything)
52
111
 
53
112
  ## Step 6: Commit
54
113
 
@@ -1,3 +1,16 @@
1
1
  {
2
- "hooks": {}
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "*",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node tools/tasks/triage-due.js 2>/dev/null || true",
10
+ "timeout": 5
11
+ }
12
+ ]
13
+ }
14
+ ]
15
+ }
3
16
  }
@@ -1,144 +1,171 @@
1
- # Battle Plan — System Prompt
1
+ # Battle Plan — Project Instructions
2
2
 
3
- You are helping manage an interconnected documentation system. Every document stays in sync through a cascade protocol. Follow these rules exactly.
3
+ ## How this project works read this first
4
4
 
5
- ---
6
-
7
- ## Two-View Model — Read This First
5
+ Two views of the same project, and Claude operates across both.
8
6
 
9
- **The cascade is your orientation layer. `docs/today.md` is the user's operating surface.**
7
+ **Claude's view (the cascade):** `docs/battle-plan.md` at the top, source docs below it (under `docs/`), `metrics.yml` as numeric truth, `events.yml` for time-based events, `tasks.yml` for strategic tasks. Narrative, deep, linked. Claude reads and writes this freely — it's how project state is reconstructed across sessions.
10
8
 
11
- - **Your view (the cascade):** `docs/battle-plan.md` at the top, source docs below it, `metrics.yml` as numeric truth. Narrative, deep, linked. You read and write this freelyit is how you reconstruct project state and cascade new information.
12
- - **User's view:** `docs/today.md`, generated by `tools/tasks/render-today.js` from `tasks.yml`. Rendered in Obsidian Tasks plugin format — query blocks project pill-styled lists over a raw `## Task data` section at the bottom. The user checks boxes in Obsidian; `tools/tasks/flush-today.js` reconciles those edits back into `tasks.yml`. The user's other primary surface is chat — when they want deep context, they ask, and you traverse the cascade on their behalf.
9
+ **User's view:** `docs/today.md` — generated by `tools/tasks/render-today.js` from `tasks.yml`, rendered in Obsidian Tasks plugin format (query blocks projecting pill-styled lists over a raw `## Task data` section at the bottom, lane-grouped within each priority bucket). The user checks boxes in Obsidian; `tools/tasks/flush-today.js` reconciles those edits back into `tasks.yml`. Their other primary surface is this chatwhen they want deep context, they ask, and Claude traverses the cascade on their behalf.
13
10
 
14
- **Rules:**
15
- - Never grow the battle plan's TL;DR into a wall of prose. Keep header blocks terse; append Daily Log entries chronologically.
16
- - When the user drops new tasks, add them via `node tools/tasks/add.js "..." [--due YYYY-MM-DD] [--tag X] [--priority 1|2|3]`. Don't bury tasks in battle plan prose.
17
- - After any task mutation (add, complete, snooze), run `node tools/tasks/render-today.js` so `docs/today.md` stays fresh.
18
- - `verify-cascade.sh` Check 6 confirms `today.md` is not stale relative to `tasks.yml`.
11
+ **Core principle:** the user should never have to look at the cascade, the battle plan, `tasks.yml`, `events.yml`, or any internal markdown to operate the system. The chat with Claude is the UI; the cascade is Claude's memory; `docs/today.md` is a thin clickable surface for ticking through the day. Everything else exists for Claude, not them.
19
12
 
20
13
  ---
21
14
 
22
- ## The Cascade Protocol
15
+ ## The Cascade — the core protocol
23
16
 
24
- **Trigger:** Any incoming information that relates to the project calls, messages, research, signals, status changes, decisions.
17
+ **Trigger:** any information shared in chat (or surfaced from tool output) that affects project state. This includes:
18
+ - Conversations, calls, or meetings (any signal — positive, negative, ambiguous)
19
+ - Research findings (desk research, web search, competitor intel)
20
+ - New targets, contacts, or refinements
21
+ - Metric changes
22
+ - Information that validates, invalidates, or adds nuance to a hypothesis
23
+ - New time-based events (calls, demos, meetings, anything with a start datetime + counterparty)
24
+ - Outreach activity (if the outreach add-on is installed — Profile B)
25
25
 
26
- When triggered, update in this exact order:
26
+ When triggered, update top-down in this exact order. Each step depends on the one above it. Never skip.
27
27
 
28
- ### Step 0: Update `metrics.yml`
29
- If any key metric changed, update `metrics.yml` first. This is the numeric source of truth.
28
+ ```
29
+ Step 0: raw state changes metrics.yml / tasks.yml / events.yml / (leads.csv if Profile B)
30
+
31
+ Step 1: docs/battle-plan.md ← TL;DR + Key Metrics table + Daily Log entry
32
+
33
+ Step 2: source docs (only the relevant ones):
34
+ ├── docs/validation/external-insights.md ← conversations & meetings (chronological)
35
+ ├── docs/validation/hypotheses.md ← validation/invalidation (amended)
36
+ ├── docs/market/ ← persona / strategy / competitive intel
37
+ ├── docs/research/ ← foundational knowledge
38
+ └── (any other domain docs you've added)
39
+
40
+ Step 3: tools/touch-date.sh ← stamp Last Updated on every modified file
41
+
42
+ Step 4: tools/verify-cascade.sh ← verify TL;DR / metrics / dates / today.md staleness
43
+ ```
30
44
 
31
- ### Step 1: Update Battle Plan (`docs/battle-plan.md`)
32
- - Update the **TL;DR** with current status
33
- - Update the **Key Metrics** table (numbers reference metrics.yml)
34
- - Update **Today's Priorities** if relevant
35
- - Append to **Daily Log** for today
45
+ If `outreach/leads.csv` exists (Profile B — outreach add-on), Step 0 also covers leads.csv mutations, and `sync-metrics.js` auto-chains from every `flush-*.js` script (it derives `metrics.yml` from the CSV — never hand-edit metrics directly).
36
46
 
37
- ### Step 2: Update Cascade Docs
38
- Update only the docs relevant to the new information. Route new info to the appropriate domain doc under `docs/`. Common patterns:
47
+ **Sources of truth one per concept, no parallel stores:**
48
+ - `metrics.yml` every metric (derived from leads.csv when outreach is installed; hand-edited otherwise)
49
+ - `events.yml` / `events-archive.yml` — every time-based event
50
+ - `tasks.yml` — every strategic / build / milestone task
51
+ - `docs/battle-plan.md` — current state ("where are we right now")
52
+ - `outreach/leads.csv` (Profile B only) — every lead
39
53
 
40
- | Info type | Route to... |
41
- |-----------|------------|
42
- | Conversation, call, or meeting | `docs/external-insights.md` — append as new dated session |
43
- | Evidence for/against a hypothesis | The relevant domain doc — amend the claim with an `[UPDATE]` block |
44
- | Outreach sent/received | The relevant market or sales doc — update tracking tables |
45
- | Competitor intel | The relevant strategy or market doc |
46
- | New foundational knowledge | The relevant research or domain doc |
54
+ Never put state in markdown tables that lives somewhere structured. Never create a parallel store.
47
55
 
48
- If no doc exists for the info, append it to the closest domain overview doc. Only create a new file if the info doesn't fit anywhere.
56
+ ---
49
57
 
50
- ### Step 3: Update Dates
51
- Run `tools/touch-date.sh` on every file you modified in this session:
58
+ ## Behavioral rules when X happens, do Y
52
59
 
53
- ```bash
54
- tools/touch-date.sh docs/battle-plan.md docs/validation/hypotheses.md [etc.]
55
- ```
60
+ **When the user mentions a time-based event** ("demo with X Thursday 2pm", "advisor call Friday 10am", "dentist Monday 9am"): call `node tools/events/add.js --title "..." --start "ISO" [--lead-id <id>] [--attendee "X"] [--type ...]`. Two criteria for an event (both required): a start datetime AND a counterparty/attendee. Anything failing either stays in `tasks.yml`.
56
61
 
57
- ### Step 4: Verify
58
- Run `tools/verify-cascade.sh` and fix any issues it reports:
62
+ **When the user drops a transcript** (paste, file path, attachment): save the raw verbatim file FIRST to `docs/archive/transcripts/<slug>-YYYY-MM-DD.<ext>`. Do not rewrite, summarize, or trim. THEN distill into the appropriate cascade-target doc. Always link back: `_Raw transcript: [path](...)._` Never delete transcripts — they're immutable audit trail.
59
63
 
60
- ```bash
61
- tools/verify-cascade.sh
62
- ```
64
+ **When the user drops new tasks:** add via `node tools/tasks/add.js "..." --lane LANE [--due ...] [--tag ...] [--priority 1|2|3] [--implication PATH] [--blocked-by N]`. `--lane` is required (one of: `build` / `outreach` / `discovery` / `infra` / `fundraising` / `meta` — customize in `tools/tasks/lib/tasks.js`). After any task mutation, run `node tools/tasks/render-today.js` so `docs/today.md` stays fresh.
63
65
 
64
- ---
66
+ **When a number from one doc appears in another:** annotate as a markdown link.
67
+ - Tier 1 — numbers in `metrics.yml`: `[**42**](metrics.yml#outreach_sent)`
68
+ - Tier 2 — numbers from another doc: `[**60%**](external-insights.md#session-2) of time on evidence`
69
+
70
+ Numbers native to a doc (where they originate) have no annotation. Verified by `tools/check-metrics.sh`.
65
71
 
66
- ## Source Reference Rules
72
+ **When stating a claim:** mark its confidence — `Unvalidated` / `Soft signal` / `Practitioner-validated` / `Data-validated`. Include the source.
67
73
 
68
- ### Registry Metrics (Tier 1 deterministic)
69
- Numbers defined in `metrics.yml`. Reference as: `[**N**](metrics.yml#field_name)`
74
+ **When `verify-cascade.sh` reports an issue:** fix it before ending the turn. Don't ship a known-stale state.
70
75
 
71
- This renders as a bold clickable number. Example: `[**42**](metrics.yml#outreach_sent)`
76
+ ### Outreach add-on (Profile B only when `outreach/leads.csv` exists)
72
77
 
73
- These are verified by exact numeric comparison via `tools/check-metrics.sh`.
78
+ **When the user mentions a lead** (reply, accept, call booked, status change, new contact, dead): update `leads.csv` — do not just acknowledge in chat. Options: drop a line into `outreach/inbox/updates.md` + `flush-updates.js` (Haiku-powered), or a Node one-liner. Then run the cascade.
74
79
 
75
- ### Inline Metrics (Tier 2 LLM-verified)
76
- Less common numbers from another doc. Reference as: `[**N**](source-doc.md#section-slug)`
80
+ **When the user reports a routine lead-by-name follow-up** ("chase X", "second follow-up to Y"): do NOT add to `tasks.yml`. The blitz pipeline (`daily-targets.js`) rotates these automatically from `leads.csv` flags. `tasks.yml` is for strategic / milestone / multi-party work.
77
81
 
78
- Example: `60% of time on evidence [**60**](external-insights.md#session-2-key-insights)`
82
+ **When the user drops names** ("did we already contact X?"): run `node tools/outreach/lookup.js "Name1, Name2, ..."` FIRST. Fuzzy-matches against `leads.csv` — prevents duplicates.
79
83
 
80
- **Rule:** Every number referenced from another document MUST include a source annotation. Only numbers native to a doc (where they originate) have no annotation.
84
+ **When the user asks for numbers** ("how many in X bucket?", "what's the funnel?"): run `node tools/outreach/stats.js` first. Live tally with template performance, weekly breakdown, channel split, FU template breakdown.
81
85
 
82
86
  ---
83
87
 
84
- ## Document Format
88
+ ## Schemas & format
85
89
 
86
- Every doc in `docs/` must have this frontmatter:
90
+ ### Document frontmatter (every doc in `docs/`)
87
91
 
88
92
  ```markdown
89
93
  # Document Title
90
94
 
91
- **Last Updated:** 2026-04-07
95
+ **Last Updated:** YYYY-MM-DD
92
96
  **Status:** Active | Draft | Archived
93
97
  **Role:** source-of-truth | cascade-target
94
98
  **Compression:** chronological | amended | none
95
99
 
96
- **TL;DR:** One paragraph summary with key numbers and source references.
97
-
98
- ---
100
+ **TL;DR:** One paragraph with key numbers and source references.
99
101
  ```
100
102
 
101
- - **Last Updated** must match today's date on any file modified in the current session.
102
- - **Status:** `Active` = live, `Draft` = WIP, `Archived` = excluded from cascade.
103
- - **Role:** `source-of-truth` = authoritative for its numbers. `cascade-target` = references numbers from elsewhere.
104
- - **Compression:** required field. One of `chronological`, `amended`, or `none` (see Compression Modes section below).
105
- - **TL;DR** must exist and contain all key metrics that appear in the doc.
106
-
107
- ---
108
-
109
- ## Compression Modes & Timestamping Rules
110
-
111
- Every doc declares a `Compression:` mode in frontmatter. This tells the `/distill` command (and humans) how new info gets added to the doc and how old info gets compressed when it grows too long. The mode IS the timestamping rule for new info.
112
-
113
- ### `Compression: chronological`
114
- The doc is an append-only log of dated entries. Each new piece of info goes in a new dated section.
115
-
116
- - **Timestamping rule:** every new entry MUST start with a dated heading: `## Session N (YYYY-MM-DD) <title>`, `## YYYY-MM-DD — <title>`, or `## DD Month YYYY — <title>`. No exceptions.
117
- - **Examples:** `docs/battle-plan.md` (daily log), `docs/validation/external-insights.md` (conversation journal).
118
- - **`/distill` behavior:** keeps the N most recent dated sections verbatim, archives the rest into `docs/archive/<same-path>`, replaces them with a thorough summary.
119
-
120
- ### `Compression: amended`
121
- The doc is a living reference. Claims are amended in place over time.
122
-
123
- - **Timestamping rule:** every new finding that revises an existing claim MUST be added as an inline `> **[UPDATE YYYY-MM-DD · Source: ...]**` block placed immediately above the claim it modifies. Brand-new claims with no prior version don't need a stamp; they're stamped implicitly by the doc's `Last Updated` date and git history.
124
- - **Examples:** `docs/validation/hypotheses.md`, `docs/market/icp-and-targets.md`, `docs/market/competitive-landscape.md`.
125
- - **`/distill` behavior:** collapses old `[UPDATE]` blocks into the body text (preserving their content as integrated current-state), archives the raw blocks verbatim. Keeps the N most recent amendments per section inline.
126
-
127
- ### `Compression: none`
128
- The doc is a static thesis or reference. It gets rewritten, not amended. Git history is the timeline.
129
-
130
- - **Timestamping rule:** none. Just edit the doc and let `Last Updated` + git track changes.
131
- - **Examples:** `docs/strategy/product-thesis.md`, `docs/research/domain-101.md`.
132
- - **`/distill` behavior:** refuses to run. If a `none` doc has grown unwieldy, rewrite it manually or change its `Compression:` mode first.
133
-
134
- ### Why this matters
135
- The TL;DR is current state, not history. It can't tell `/distill` what's new vs old. The `Compression:` mode + timestamping rule is the only mechanism that makes distillation deterministic. Skipping the timestamp on a new entry in a `chronological` or `amended` doc is a bug; it will get silently absorbed into the wrong era during distillation.
136
-
137
- When in doubt about which mode a new doc should use: chronological logs choose `chronological`, claim trackers choose `amended`, everything else is `none`.
103
+ - `Last Updated` must match today's date on any file modified in the current session.
104
+ - `Status` `Active` = live; `Draft` = WIP; `Archived` = excluded from cascade.
105
+ - `Role` `source-of-truth` = authoritative for its numbers. `cascade-target` = references numbers from elsewhere.
106
+ - `TL;DR` contains all key metrics that appear in the doc.
107
+
108
+ ### Compression modes (drives `/distill`)
109
+
110
+ | Mode | Doc type | Timestamp rule for new entries |
111
+ |---|---|---|
112
+ | `chronological` | append-only log (battle-plan.md, external-insights.md) | every entry MUST start with a dated heading: `## YYYY-MM-DD — <title>` or `## Session N (YYYY-MM-DD) — <title>` |
113
+ | `amended` | living reference (hypotheses.md, icp-and-targets.md, competitive-landscape.md) | every revision MUST be a `> **[UPDATE YYYY-MM-DD · Source: ...]**` block placed immediately above the claim it modifies |
114
+ | `none` | static thesis (product-thesis.md, domain-101.md) | none — rewrite, don't amend. Git history is the timeline. `/distill` refuses to run. |
115
+
116
+ Skipping the timestamp on a new entry in a `chronological` or `amended` doc is a bug it gets silently absorbed into the wrong era during distillation.
117
+
118
+ ### `tasks.yml`task lanes
119
+
120
+ Every task has a `lane` (groups by *primary action*, not topic). Default vocabulary (customize in `tools/tasks/lib/tasks.js`):
121
+
122
+ | Lane | Primary action |
123
+ |---|---|
124
+ | `build` | Build, design, or document the product itself |
125
+ | `outreach` | Cold DMs / InMails / templates / cold-email infra |
126
+ | `discovery` | Chase or nurture a named human relationship |
127
+ | `infra` | Plumbing DNS, GCP/AWS, deploy, env, secrets |
128
+ | `fundraising` | Accelerator / VC / angel relationships |
129
+ | `meta` | Doc/process work with no other natural lane (default fallback) |
130
+
131
+ Tasks may carry:
132
+ - `due: YYYY-MM-DD` deadline (sorted to top by date).
133
+ - `priority: 1|2|3` — Today / This week / Backlog.
134
+ - `implications: [docs/path-a.md, ...]` docs that should change when the task closes. `triage.js` flags drift when a linked doc's last commit predates the task.
135
+ - `blocked_by: [TASK-IDs]` — tasks that must close first. `render-today.js` emits the marker only for *still-open* blockers.
136
+
137
+ **Strategic vs routine:** `tasks.yml` is for strategic / multi-party / load-bearing work. Routine name-by-name follow-ups belong in the outreach blitz (Profile B), not here.
138
+
139
+ ### `events.yml` time-based events
140
+
141
+ Single source of truth for calls, demos, meetings, advisor sessions, dentist appointments, anything with a start datetime + counterparty.
142
+
143
+ - `events.yml` — future scheduled events.
144
+ - `events-archive.yml` — terminal events after the wrap-up gate has captured transcript / spawned tasks / insights.
145
+
146
+ ```yaml
147
+ - id: 1
148
+ title: Demo v1 walkthrough — Counterparty / Company
149
+ start: "2026-05-14T14:00:00+02:00" # ISO 8601 with TZ
150
+ end: "2026-05-14T14:45:00+02:00"
151
+ type: demo # demo|discovery|investor|admin|personal|unspecified|other
152
+ status: scheduled # scheduled|in_progress|done|cancelled|no_show|rescheduled
153
+ attendees: [Counterparty, Me]
154
+ lead_id: https://www.linkedin.com/in/example # nullable (links to leads.csv if Profile B)
155
+ location: Google Meet
156
+ notes: free-form
157
+ source: manual-chat # manual-chat|flush-updates|migrate-from-csv|hand-edit
158
+ created_at: "2026-05-11T10:38:00.372Z"
159
+ # populated by the wrap-up gate after the event ends:
160
+ transcript_path: docs/archive/transcripts/...
161
+ spawned_tasks: [TASK-86, TASK-87]
162
+ hypothesis_impacts: [H47, H49]
163
+ gate_completed_at: "2026-05-14T16:30:00+02:00"
164
+ ```
138
165
 
139
- ---
166
+ Lifecycle: `scheduled` → `done` → `gated` (wrap-up Step 4.5d fills `gate_completed_at`) → archived (`tools/events/archive.js` moves to events-archive.yml). Personal events (gym, dentist) can carry `type: personal` and skip the gate.
140
167
 
141
- ## Vault Rules
168
+ ### Vault rules
142
169
 
143
170
  1. **Update, don't duplicate.** Amend with `> **[UPDATE YYYY-MM-DD · Source: ...]**`
144
171
  2. **Cross-link everything.** Claims reference their source doc.
@@ -146,95 +173,33 @@ When in doubt about which mode a new doc should use: chronological logs choose `
146
173
  4. **Source everything.** Who said it, when, confidence level.
147
174
  5. **Minimize file count.** Append, don't create new files.
148
175
 
149
- ---
150
-
151
- ## The `/wrap-up` Protocol
152
-
153
- When the user says `/wrap-up`, run this end-of-day sequence:
154
-
155
- **Step 1 — Scan:** Read the battle plan. Identify all tasks for today. Categorize: done, partially done, not started, new.
176
+ ### Outreach `leads.csv` — Profile B only
156
177
 
157
- **Step 2 Present:** Show the user: "Here's today's status: [list]. Does this look right?"
178
+ If `outreach/leads.csv` exists in the project, the outreach add-on is active. See `outreach/README.md` for setup. `leads.csv` is the single source of truth for outreach metrics — `metrics.yml` is derived from it via `sync-metrics.js` (auto-chained from every `flush-*.js`).
158
179
 
159
- **Step 3 Prompt:** Ask: "Anything else happen today? Even small things a reply, an accept, a thought, a link. Everything counts."
180
+ Key columns (full HEADERS list in `tools/outreach/lib/leads.js`): `linkedin_url`, `first_name`, `last_name`, `title`, `company`, `country`, `email`, `source`, `tags`, `status`, `priority`, `contacted_at`, `replied_at`, `followed_up_at`, `channel`, `template`, `inmail_template`, `followup_template`, `notes`.
160
181
 
161
- **Step 4 Cascade:** With all info gathered, run the full cascade (Steps 0-4 above).
182
+ Status flow: `new dm_sent replied call_booked call_done verbal loi → paying`. Branches: `dead`, `withdrawn`.
162
183
 
163
- **Step 5Report:** Print:
164
- - Metrics changed today (before → after)
165
- - Docs updated
166
- - Verification warnings (if any)
167
- - Tomorrow's top priorities
168
-
169
- **Step 6 — Commit:** Ask: "Want me to commit today's updates?" If yes, commit with message: `eod YYYY-MM-DD: [summary]`
184
+ Tags grow forward with `, ` separator. Notes grow forward with `| ` separator never overwrite.
170
185
 
171
186
  ---
172
187
 
173
- ## Outreach System (Add-on)
174
-
175
- **Trigger:** If `outreach/leads.csv` exists in the project, the outreach system is active.
176
-
177
- ### Overview
178
-
179
- The outreach system tracks a LinkedIn (or any channel) outreach pipeline through `outreach/leads.csv`. This CSV is the **single source of truth** for all outreach metrics — `metrics.yml` is derived from it, never edited directly for outreach numbers.
180
-
181
- ### First-Time Setup
182
-
183
- If `outreach/leads.csv` exists but `.outreach-initialized` does NOT exist, read `outreach/README.md` and follow the Interactive Setup instructions to onboard the user.
184
-
185
- ### Daily Workflow Integration
186
-
187
- The outreach system plugs into the cascade protocol:
188
-
189
- 1. User runs `node tools/outreach/daily-targets.js` → generates blitz checklist
190
- 2. User sends messages, ticks checkboxes
191
- 3. User runs `node tools/outreach/flush-targets.js` → updates leads.csv
192
- 4. `flush-targets.js` calls `sync-metrics.js` → derives metrics.yml from CSV
193
- 5. `sync-metrics.js` calls `update-dashboard.js` → regenerates mermaid dashboard
194
- 6. The cascade protocol takes over: metrics.yml → battle-plan.md → domain docs
195
-
196
- ### Scripts Reference
197
-
198
- | Script | Purpose |
199
- |--------|---------|
200
- | `tools/outreach/daily-targets.js [N]` | Generate daily blitz checklist |
201
- | `tools/outreach/flush-targets.js` | Process checked items from blitz |
202
- | `tools/outreach/flush-updates.js` | Parse free-form natural language updates |
203
- | `tools/outreach/flush-accepts.js` | Batch-process connection accepts |
204
- | `tools/outreach/flush-inbox.js` | Add leads from manual URL list |
205
- | `tools/outreach/sync-metrics.js` | Derive metrics.yml from leads.csv |
206
- | `tools/outreach/update-dashboard.js` | Regenerate mermaid conversion dashboard |
207
- | `tools/outreach/stats.js` | Print pipeline summary |
208
- | `tools/outreach/lookup.js "Name"` | Fuzzy-search leads |
209
-
210
- ### Metrics Derivation
211
-
212
- These metrics in `metrics.yml` are **derived** from leads.csv (never hand-edit):
213
-
214
- - `outreach_sent` = leads with status past `new` or `contacted_at` set
215
- - `responses` = `replied_at` set or status past `replied`
216
- - `invitations_accepted` = leads tagged `accepted`
217
- - `discovery_calls` = `call_at` in the past or status `call_done`
218
- - `calls_booked` = status `call_booked` (snapshot)
219
- - `verbal_commitments` = status `verbal`, `loi`, or `paying`
220
-
221
- ### Template System
222
-
223
- Message templates live in `tools/outreach/templates.json`. The daily blitz assigns templates based on the `country_template_map` field (or round-robin if no mapping). Template performance (sent/accepted/replied/calls) is tracked automatically and displayed in the blitz checklist.
224
-
225
- ### Mermaid Dashboard
188
+ ## Pointers
226
189
 
227
- `docs/analysis/icp-conversion.md` is auto-generated — never hand-edit. It contains:
228
- - Overall funnel chart (contacted accepted replied call → verbal)
229
- - Conversion breakdown by role, company size, country, company type
230
- - Template A/B comparison
231
- - Kill/Keep/Scale verdicts per segment
190
+ **Daily scripts:**
191
+ - `tools/tasks/` task lifecycle: `add.js`, `render-today.js`, `flush-today.js`, `triage.js`, `archive.js`, `migrate-lanes.js`
192
+ - `tools/events/` events lifecycle: `add.js`, `upcoming.js`, `due-for-gate.js`, `archive.js`, `migrate-from-csv.js`
193
+ - `tools/touch-date.sh` — stamp Last Updated in frontmatter
194
+ - `tools/verify-cascade.sh` — verify TL;DR / metrics / dates / today.md staleness
195
+ - `tools/check-metrics.sh` — verify Tier 1 metric link references
232
196
 
233
- View in any mermaid-capable renderer (GitHub, VS Code preview, etc.).
197
+ **Outreach scripts (Profile B):** `tools/outreach/` — `daily-targets.js`, `flush-targets.js`, `flush-updates.js`, `flush-accepts.js`, `flush-inbox.js`, `sync-metrics.js`, `update-dashboard.js`, `stats.js`, `lookup.js`, `stale-invitations.js`.
234
198
 
235
- ### Adapting the System
199
+ **Skills (`.claude/commands/`):**
200
+ - `good-morning` — morning standup (metrics + today.md + events context-debt check)
201
+ - `wrap-up` — end-of-day reconciliation + task hygiene + events gate
202
+ - `weekly-triage` — task-pile sweep
203
+ - `distill` — compress chronological / amended doc history
236
204
 
237
- - **Different metrics:** Edit the derivation rules in `tools/outreach/sync-metrics.js`
238
- - **Different time horizon:** The system tracks weekly breakdowns — adjust `daily-targets.js` count parameter
239
- - **Different channels:** The `channel` column supports any value (connection, inmail, email, etc.)
240
- - **Different statuses:** Add to `VALID_STATUS` in `tools/outreach/lib/leads.js` and update derivation rules
205
+ **Auto-nudges:** `tools/tasks/triage-due.js` runs on every session start. When it prints a nudge, mention `/weekly-triage` to the user do not auto-invoke.