kushi-agents 3.4.2 → 3.12.1

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.
Files changed (69) hide show
  1. package/README.md +33 -0
  2. package/package.json +15 -3
  3. package/plugin/agents/kushi.agent.md +155 -147
  4. package/plugin/instructions/ado-bootstrap-discovery.instructions.md +111 -0
  5. package/plugin/instructions/ado-engagement-tree.instructions.md +73 -0
  6. package/plugin/instructions/answer-from-evidence.instructions.md +1 -1
  7. package/plugin/instructions/auth-and-retry.instructions.md +51 -16
  8. package/plugin/instructions/azure-auth-patterns.instructions.md +13 -6
  9. package/plugin/instructions/bootstrap-status-format.instructions.md +113 -0
  10. package/plugin/instructions/capture-learnings.instructions.md +95 -0
  11. package/plugin/instructions/cleanup-on-resolution.instructions.md +69 -0
  12. package/plugin/instructions/crm-bootstrap-discovery.instructions.md +79 -0
  13. package/plugin/instructions/crm-internal-vs-confirmed.instructions.md +79 -0
  14. package/plugin/instructions/evidence-confidence-ladder.instructions.md +66 -0
  15. package/plugin/instructions/evidence-layout-canonical.instructions.md +115 -0
  16. package/plugin/instructions/evidence-thoroughness.instructions.md +82 -12
  17. package/plugin/instructions/full-view-gate.instructions.md +91 -0
  18. package/plugin/instructions/m365-id-registry.instructions.md +134 -0
  19. package/plugin/instructions/meetings-verbatim-required.instructions.md +176 -0
  20. package/plugin/instructions/run-reports.instructions.md +129 -0
  21. package/plugin/instructions/scope-boundaries.instructions.md +218 -0
  22. package/plugin/instructions/snapshot-vs-stream.instructions.md +2 -0
  23. package/plugin/instructions/update-ledger.instructions.md +132 -0
  24. package/plugin/instructions/verbatim-by-default.instructions.md +73 -0
  25. package/plugin/instructions/workiq-first.instructions.md +15 -31
  26. package/plugin/instructions/workiq-only.instructions.md +193 -0
  27. package/plugin/learnings/README.md +50 -0
  28. package/plugin/learnings/ado.md +45 -0
  29. package/plugin/learnings/crm.md +96 -0
  30. package/plugin/learnings/cross-cutting.md +36 -0
  31. package/plugin/learnings/email.md +33 -0
  32. package/plugin/learnings/meetings.md +30 -0
  33. package/plugin/learnings/misc.md +46 -0
  34. package/plugin/learnings/onenote.md +215 -0
  35. package/plugin/learnings/sharepoint.md +5 -0
  36. package/plugin/learnings/teams.md +5 -0
  37. package/plugin/plugin.json +22 -2
  38. package/plugin/prompts/apply-ado.prompt.md +14 -0
  39. package/plugin/prompts/propose-ado.prompt.md +12 -0
  40. package/plugin/reference-packs/fde/crm-field-manifest.md +165 -0
  41. package/plugin/skills/apply-ado-update/SKILL.md +125 -0
  42. package/plugin/skills/ask-project/SKILL.md +2 -0
  43. package/plugin/skills/bootstrap-project/SKILL.md +81 -3
  44. package/plugin/skills/propose-ado-update/SKILL.md +108 -0
  45. package/plugin/skills/pull-ado/SKILL.md +173 -23
  46. package/plugin/skills/pull-crm/SKILL.md +168 -15
  47. package/plugin/skills/pull-email/SKILL.md +139 -22
  48. package/plugin/skills/pull-meetings/SKILL.md +109 -25
  49. package/plugin/skills/pull-misc/README.md +84 -0
  50. package/plugin/skills/pull-misc/SKILL.md +257 -0
  51. package/plugin/skills/pull-misc/runner.mjs +280 -0
  52. package/plugin/skills/pull-onenote/README.md +90 -0
  53. package/plugin/skills/pull-onenote/SKILL.md +400 -51
  54. package/plugin/skills/pull-onenote/runner.mjs +356 -0
  55. package/plugin/skills/pull-onenote/scripts/recapture-section-url.mjs +295 -0
  56. package/plugin/skills/pull-onenote/write-snapshot.mjs +271 -0
  57. package/plugin/skills/pull-sharepoint/SKILL.md +44 -12
  58. package/plugin/skills/pull-teams/SKILL.md +40 -11
  59. package/plugin/skills/refresh-project/SKILL.md +33 -2
  60. package/plugin/skills/self-check/run.ps1 +186 -4
  61. package/plugin/templates/ado-update/discussion-comment.template.md +26 -0
  62. package/plugin/templates/ado-update/integrations-ado-writes.example.yml +49 -0
  63. package/plugin/templates/ado-update/proposed.template.md +78 -0
  64. package/plugin/templates/init/external-links.template.txt +30 -0
  65. package/plugin/templates/init/project-integrations.template.yml +57 -2
  66. package/plugin/templates/snapshot/meeting-verbatim.template.md +110 -0
  67. package/plugin/templates/snapshot/meetings-series-index.template.md +3 -1
  68. package/plugin/templates/snapshot/onenote-page.template.md +92 -23
  69. package/plugin/templates/weekly/meetings-stream.template.md +11 -6
@@ -0,0 +1,165 @@
1
+ # FDE CRM (Dataverse) Field Manifest
2
+
3
+ > Canonical mapping of FDE engagement-submission long-text fields + annotation pull pattern. Consumed by `pull-crm` whenever the configured entity set is an FDE engagement-submission table.
4
+
5
+ Cite as: `[source: reference-packs/fde/crm-field-manifest.md · packaged]`.
6
+
7
+ ---
8
+
9
+ ## Why this manifest exists
10
+
11
+ The FDE engagement-submission record in Dataverse holds the strategic answers an FDE crew needs (business scenario, why current offers don't fit, success criteria, technology workloads, work done so far). These live in **long-text fields** (`Memo` / multi-line text) that must be captured **verbatim** — paraphrasing or summarizing them at pull time strips the context Kushi is supposed to preserve.
12
+
13
+ Pre-v3.7.2, `pull-crm` retrieved a CRM record with whatever fields the API returned by default, which often dropped or truncated the long-text answers. This manifest fixes that by giving `pull-crm` an explicit `$select` list and an explicit annotation fetch loop.
14
+
15
+ ---
16
+
17
+ ## Display-name → logical-name mapping
18
+
19
+ The user-facing labels (left) map to Dataverse logical names (right). Logical names vary per tenant; treat the right column as the **probable** logical name and do the discovery probe described below if a `$select` returns null.
20
+
21
+ | Display label (form question) | Probable logical name | Type |
22
+ |---|---|---|
23
+ | Engaged With | `msfre_engagedwith` | Memo (multi-line) |
24
+ | What is the business scenario or technical blocker that FDE would solve? | `msfre_businessscenario` | Memo |
25
+ | Why are the current offers or solutions not suitable for this customer's needs? | `msfre_currentofferinggap` | Memo |
26
+ | What does success look like for the customer? | `msfre_successcriteria` | Memo |
27
+ | Please list the relevant technology (1st party / 3rd party) workloads being used | `msfre_technologyworkloads` | Memo |
28
+ | Give a description of the work completed so far (if any) | `msfre_workcompletedsofar` | Memo |
29
+ | MSX Opportunity ID | `msfre_msxopportunityid` | Single line |
30
+ | Customer name | `msfre_customername` (or via lookup `_msfre_account_value`) | Lookup |
31
+ | Engagement title | `msfre_engagementtitle` (or `name`) | Single line |
32
+ | FDE crew / division | `msfre_division`, `msfre_crew` | OptionSet / Single line |
33
+ | Status / state | `statuscode`, `statecode` | OptionSet |
34
+ | Created on / by | `createdon`, `_createdby_value` | Datetime / Lookup |
35
+ | Modified on / by | `modifiedon`, `_modifiedby_value` | Datetime / Lookup |
36
+
37
+ ### Discovery probe (run once per project, persist to mutable)
38
+
39
+ If the configured `entitySetName` is `msfre_*` and a `$select` for any of the probable logical names above returns `null`, run a **metadata probe** to confirm the actual logical names:
40
+
41
+ ```http
42
+ GET /api/data/v9.2/EntityDefinitions(LogicalName='msfre_engagementsubmission')/Attributes?$select=LogicalName,DisplayName,AttributeType&$filter=AttributeType eq 'Memo'
43
+ ```
44
+
45
+ Persist the resolved mapping to `m365Mutable.knownSections.<project>.crm.fieldMap` so subsequent pulls skip the probe.
46
+
47
+ ---
48
+
49
+ ## REQUIRED $select for FDE engagement-submission records
50
+
51
+ Every snapshot pull MUST request these fields explicitly (no relying on default projection):
52
+
53
+ ```
54
+ $select=
55
+ msfre_engagementsubmissionid,
56
+ name,
57
+ msfre_engagedwith,
58
+ msfre_businessscenario,
59
+ msfre_currentofferinggap,
60
+ msfre_successcriteria,
61
+ msfre_technologyworkloads,
62
+ msfre_workcompletedsofar,
63
+ msfre_msxopportunityid,
64
+ statuscode,
65
+ statecode,
66
+ createdon,
67
+ createdby,
68
+ modifiedon,
69
+ modifiedby,
70
+ _ownerid_value,
71
+ _msfre_account_value
72
+ ```
73
+
74
+ Then `$expand=Annotations($select=annotationid,subject,notetext,createdon,_createdby_value,filename,mimetype)` to pull every note attached to the record.
75
+
76
+ If the discovery probe returned a different logical name, substitute it before issuing the request.
77
+
78
+ ---
79
+
80
+ ## Annotation (notes) pull pattern
81
+
82
+ CRM Notes are stored as `Annotation` records related to the parent record via `objectid`. They are NOT included by default — they must be expanded.
83
+
84
+ For each annotation returned:
85
+
86
+ 1. Capture **verbatim** the full `notetext` (do not summarize, do not truncate, do not strip newlines).
87
+ 2. Capture metadata: `subject`, `createdon`, `createdby` (resolved name, not GUID), `filename` + `mimetype` if attached.
88
+ 3. Write each annotation as a `### Note — <subject> (<createdon> by <createdby>)` block under a `## Notes (verbatim)` H2 section in the snapshot file.
89
+ 4. If the annotation has an attached file (`filename` non-null), record its filename + mimetype + size; do NOT download the binary unless the user explicitly asks.
90
+
91
+ ---
92
+
93
+ ## Snapshot file shape (FDE CRM record)
94
+
95
+ When the entity is FDE engagement-submission, the snapshot file MUST follow this shape:
96
+
97
+ ```markdown
98
+ # CRM — <customer-name> · <engagement-title>
99
+
100
+ **Record ID:** `<id>` · **MSX Opportunity:** `<msx-id>` · **Last fetched:** `<iso-ts>`
101
+ **Status:** `<statuscode label>` · **Owner:** `<owner display name>`
102
+
103
+ ## Source Basis
104
+
105
+ - Tool: <workiq | dataverse-rest | graph>
106
+ - Boundary: `boundaries.crm.record_ids = [<id>]`
107
+ - Field map: `m365Mutable.knownSections.<project>.crm.fieldMap` (probed <date>) | packaged (default)
108
+ - Annotations fetched: <N>
109
+
110
+ ## AI Narrative Summary
111
+
112
+ (3+ paragraphs — engagement story so far, current stage, what's at stake, latest direction. No paraphrase of the long-text answers below; summarize what they say collectively.)
113
+
114
+ ## Engagement context
115
+
116
+ ### Engaged With
117
+ > (verbatim msfre_engagedwith)
118
+
119
+ ### Business scenario / technical blocker
120
+ > (verbatim msfre_businessscenario)
121
+
122
+ ### Why current offers / solutions not suitable
123
+ > (verbatim msfre_currentofferinggap)
124
+
125
+ ### What success looks like
126
+ > (verbatim msfre_successcriteria)
127
+
128
+ ### Technology workloads (1st / 3rd party)
129
+ > (verbatim msfre_technologyworkloads)
130
+
131
+ ### Work completed so far
132
+ > (verbatim msfre_workcompletedsofar)
133
+
134
+ ## All other fields
135
+
136
+ (Every other field returned by the $select, in a 2-column table: field | value. Empty fields shown as `_(empty)_` so absence is visible.)
137
+
138
+ ## Notes (verbatim)
139
+
140
+ ### Note — <subject> (<createdon> by <createdby>)
141
+ > (verbatim notetext, no truncation)
142
+
143
+ ### Note — <subject> (<createdon> by <createdby>)
144
+ > (verbatim notetext)
145
+
146
+ (... one block per annotation, oldest first ...)
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Anti-patterns (defects)
152
+
153
+ - ❌ Paraphrasing the long-text fields — they MUST be verbatim.
154
+ - ❌ Omitting empty fields — write `_(empty)_` so the reader can see we asked.
155
+ - ❌ Skipping annotations because they look like noise — every annotation goes in.
156
+ - ❌ Truncating long annotations with `...` — record the full text even if it's pages.
157
+ - ❌ Falling back to "narrate from email" when CRM is unreachable — see `pull-crm/SKILL.md` Hard prerequisites; refuse instead.
158
+
159
+ ---
160
+
161
+ ## See also
162
+
163
+ - `intake-questions.md` — the FDE Intake question set this manifest backs.
164
+ - `pull-crm/SKILL.md` — the skill that must apply this manifest.
165
+ - `core-fde-reference.md` — broader FDE operating model.
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: "apply-ado-update"
3
+ version: "0.1.0-preview"
4
+ status: "preview-stub"
5
+ description: "Gated write skill: reads <engagement-root>/<project>/ado-updates/<date>/proposed.md, presents the diff for approval, applies approved items to ADO (PATCH field + POST comment), and appends to the per-project update ledger. v0.1.0-preview is a STUB — runs in dry-mode only and writes a planned-writes log; no real ADO PATCH/POST yet."
6
+ ---
7
+
8
+ # Skill: apply-ado-update
9
+
10
+ Run this when the user says any of: "apply ado update for `<X>`", "@Kushi apply ado `<X>`", "write to ado for `<X>`".
11
+
12
+ This skill is the **only** code path in Kushi authorized to write to ADO. It implements the doctrine in `update-ledger.instructions.md`.
13
+
14
+ ## Status: preview-stub (v0.1.0-preview)
15
+
16
+ In v0.1.0-preview this skill **runs in dry-mode only**. It:
17
+
18
+ - Reads `proposed.md`.
19
+ - Validates the proposal shape and citations.
20
+ - Re-fetches the current ADO Initiative state and re-computes the diff (in case it drifted since `propose-ado-update` ran).
21
+ - Asks the user to approve all / select / none.
22
+ - Writes a **planned-writes log** to `<project>/ado-updates/<YYYY-MM-DD>/planned.jsonl` recording what *would* have been written.
23
+ - Does **not** call any ADO `PATCH` or `POST` endpoint yet.
24
+
25
+ The real write path (PATCH field + POST comment + ledger append) lands in v0.1.x once the proposed.md format, the apply UX, and the ledger schema have been validated against real projects for at least one full week. See `docs/concepts/roadmap.md`.
26
+
27
+ ## Profile
28
+
29
+ Belongs to the **`preview`** profile. Opt in via `npx kushi-agents --clawpilot --profile preview`.
30
+
31
+ ## Deterministic config — do not invent paths
32
+
33
+ Same as `propose-ado-update`. Reads ADO connection from `<engagement-root>/.project-evidence/ado/config.yml`, per-project `engagement_id` and `writes:` block from `<engagement-root>/<project>/integrations.yml ado:`. Never asks for paths the bootstrap layer already resolved.
34
+
35
+ ## Pre-flight (HARD — do not bypass)
36
+
37
+ 1. **Resolve engagement root + project** per `engagement-root-resolution.instructions.md`.
38
+ 2. Confirm `<project>/integrations.yml ado.engagement_id > 0`. If 0 → abort with the same message `propose-ado-update` uses ("ADO Initiative not yet linked").
39
+ 3. Confirm `<project>/ado-updates/<YYYY-MM-DD>/proposed.md` exists. If not → tell user to run `@Kushi propose ado <project>` first. Never fabricate a proposal.
40
+ 4. Per `azure-auth-patterns.instructions.md` — Section 1 (session pre-check) + Section 3 (ADO tenant validation, using `<engagement-root>/.project-evidence/ado/config.yml`) **must** complete green before any further step.
41
+
42
+ ## Steps (current preview-stub behavior)
43
+
44
+ 1. **Load proposed.md** and parse the field-update + comment-update sections (Markdown headings + fenced blocks).
45
+ 2. **Re-fetch current ADO state** (read-only GET) and compare against the `current` value embedded in `proposed.md`. If they differ → warn `proposal-drift`, show the live current value, and require explicit re-approval.
46
+ 3. **Duplicate detection** — list the latest 5 Discussion comments via ADO API; if any contain the Kushi fingerprint line for this same week → mark `duplicate-detected`, skip the comment write, still proceed with field update if not duplicate.
47
+ 4. **Allowlist gate** — every item in `proposed.md` whose `fieldRefName` is NOT in `integrations.yml ado.writes.allowlist.fields` is rejected before approval is even offered. This is the last-line guard against a malformed proposal.
48
+ 5. **Approval gate**:
49
+ - Default: prompt user with the diff and `[a]ll · [s]elect · [n]one`.
50
+ - Auto-apply: if `ado.writes.statusSummary.autoApply: true` AND the field-update item has `confidence: high` AND the new line matches the configured `<MMM YYYY>: ...` pattern → mark approver `auto:append-month-high-conf`. Same for `discussionComment.autoApply` (rare; off by default).
51
+ - All other items → require interactive approval.
52
+ 6. **(Stub)** Instead of calling ADO writes, append to `<project>/ado-updates/<YYYY-MM-DD>/planned.jsonl` one record per approved item:
53
+ ```json
54
+ {
55
+ "timestamp": "2026-05-18T16:30:00Z",
56
+ "engagementId": 12345,
57
+ "kind": "field|comment",
58
+ "fieldRefName": "Custom.FDEStatusSummary",
59
+ "currentValue": "...",
60
+ "proposedValue": "...",
61
+ "approver": "ushak | auto:append-month-high-conf",
62
+ "confidence": "high",
63
+ "evidenceCitations": ["ushak/onenote/snapshot/architecture-decisions.md · 2026-05-12"],
64
+ "fingerprint": "kushi-weekly-2026-05-18-12345-field",
65
+ "executed": false,
66
+ "stubReason": "v0.1.0-preview: write path not yet enabled"
67
+ }
68
+ ```
69
+ 7. **Echo summary** to user: how many items would be written, path to `planned.jsonl`, and the line "No ADO calls were made (preview-stub)."
70
+
71
+ ## Steps (planned for v0.1.x — when write path lands)
72
+
73
+ After step 5 (approval), instead of step 6:
74
+
75
+ 6. **Apply field update** (one PATCH per approved field):
76
+ ```http
77
+ PATCH https://dev.azure.com/{org}/{project}/_apis/wit/workitems/{engagement_id}?api-version=7.1
78
+ Content-Type: application/json-patch+json
79
+
80
+ [
81
+ { "op": "test", "path": "/rev", "value": <currentRev> },
82
+ { "op": "add", "path": "/fields/Custom.FDEStatusSummary", "value": "<new value>" }
83
+ ]
84
+ ```
85
+ The `test` on `/rev` is the optimistic-lock guard. If it fails → ledger entry `error: rev-mismatch`, do NOT retry silently; surface to user.
86
+
87
+ 7. **Apply Discussion comment** (one POST per approved comment):
88
+ ```http
89
+ POST https://dev.azure.com/{org}/{project}/_apis/wit/workItems/{engagement_id}/comments?api-version=7.1-preview.4
90
+ Content-Type: application/json
91
+ { "text": "<rendered HTML>" }
92
+ ```
93
+
94
+ 8. **Append to ledger** at `<project>/ado-updates/<YYYY-MM-DD>/ledger.jsonl` per `update-ledger.instructions.md` §Schema, including the **reverse op** (so a later `revert` skill can roll back).
95
+
96
+ 9. **Optional notify** — if `ado.writes.approvals.notifyOnApply: teams`, post a one-line summary via `m_send_teams_message` to the user (never to others).
97
+
98
+ ## Failure modes (preview-stub)
99
+
100
+ | Symptom | Recovery |
101
+ |---|---|
102
+ | `proposed.md` missing | Stop. Tell user to run `@Kushi propose ado <project>` first. |
103
+ | `integrations.yml` missing or `ado.engagement_id == 0` | Stop with same message `propose-ado-update` uses; do not prompt for an ID. |
104
+ | `ado.writes:` block missing | Stop. Tell user to run `@Kushi propose ado <project>` first (it scaffolds the block). |
105
+ | ADO 401 on the read-only re-fetch in step 2 | Re-acquire token once per `azure-auth-patterns.instructions.md` §4; if still 401, abort `auth-failed`. |
106
+ | Tenant mismatch | Per `azure-auth-patterns.instructions.md` §3 — abort with the exact `az login --tenant <id>` command. |
107
+ | `proposal-drift` (current ADO value differs from `proposed.md` snapshot) | Show diff between live and proposed; require user to re-confirm or re-run `propose-ado-update`. |
108
+ | `duplicate-detected` (comment fingerprint already on the work item) | Skip comment portion; continue with field if not also duplicate. |
109
+ | Allowlist rejection | Refuse the item before approval. Tell user the field reference name is not in `integrations.yml ado.writes.allowlist.fields`. |
110
+
111
+ ## What this skill does NOT do (ever — not even in v0.1.x)
112
+
113
+ - Does NOT auto-apply any item with `confidence < high`.
114
+ - Does NOT auto-apply any item not on the per-project allowlist (`ado.writes.<x>.autoApply: true`).
115
+ - Does NOT write to fields not listed in `ado.writes.allowlist.fields` of `<project>/integrations.yml`.
116
+ - Does NOT post comments other than the single rendered Discussion comment from `proposed.md`.
117
+ - Does NOT bulk-apply across projects in a single call (one project per invocation).
118
+ - Does NOT delete or close work items, change parent links, change area path, or touch any field outside the configured allowlist.
119
+
120
+ ## References
121
+
122
+ - `update-ledger.instructions.md` — ledger schema, reverse-op format, write-path safety doctrine.
123
+ - `azure-auth-patterns.instructions.md` — pre-flight, tenant validation, token reuse, 401 recovery.
124
+ - `propose-ado-update` SKILL.md — produces the `proposed.md` consumed by this skill.
125
+ - `engagement-root-resolution.instructions.md` — resolving `<engagement-root>` and `<project>`.
@@ -20,6 +20,8 @@ The user does NOT need to type `/ask-project` or `@Kushi ask`. If the message:
20
20
  - **Read-only.** No `pull-*`, no Graph writes, no WorkIQ calls during answering. Source pulls are a separate user-initiated step.
21
21
  - **No cross-project bleed.** Answer only from the resolved project's own folders. If the question requires comparing two projects, ask the user to confirm and run `ask-project` per project, then merge in the answer.
22
22
  - **Citation Ledger applies.** Every fact, decision, person, date, $ figure carries inline `[source: <alias>/<folder>/<file> · YYYY-MM-DD]` per `instructions/citation-ledger.instructions.md` and `instructions/answer-from-evidence.instructions.md`. If the corpus does not support an answer, say so explicitly — never invent.
23
+ - **Full-view gate applies.** Walk the standard 7-source set per `instructions/full-view-gate.instructions.md` before answering and render the Source Basis disposition table. Do not call the answer a "full view" if any applicable source is `cached-stale`, `attempted-but-blocked`, or `unknown`.
24
+ - **Confidence ladder applies.** Tag every claim about decisions/status/funding/scope/owner/commitment with `internal-only` / `communicated` / `confirmed` per `instructions/evidence-confidence-ladder.instructions.md`. Never paraphrase a CRM/ADO field flip as a settled fact without a customer-facing confirmation dated AFTER the flip.
23
25
  - **Privacy posture.** Same as Kushi global: no outbound messages, no leaking attendee emails into anything visible to others. Answer goes to chat only.
24
26
  - **Freshness gate, not freshness auto-fix.** If the freshest source relevant to the question is older than `chat.freshness_warn_days` (default 14), warn the user and offer `@Kushi refresh <project>` — but NEVER auto-refresh.
25
27
  - **Reference packs may be consulted for domain doctrine.** When the question maps to a known reference-pack domain (currently only `fde/` — FDE stages, fitness, CRM status meanings, intake gates, risk categories, "MACC", "is this FDE-fit"), ALSO load the matching reference pack as additional grounding using the 3-layer override order (project → user → packaged). Cite reference-pack assertions with `[source: reference-packs/<pack>/<file>.md · <layer>]` where layer is `packaged` / `user-override` / `project-override`. Reference-pack content NEVER overrides project Evidence/ for facts about *this* project; it only provides definitions, gates, and rubrics.
@@ -1,11 +1,21 @@
1
1
  ---
2
2
  name: "bootstrap-project"
3
- version: "2.1.0"
4
- description: "First-time setup for a project: machine preflight (WorkIQ check, optional az login), side-by-side config (templates -> live filled), engagement-root + project resolution, initial 30d snapshot+stream pull across all enabled sources. Builds State/ only on the `full` profile (skipped on `standard`). Idempotent safe to re-run."
3
+ version: "2.3.1"
4
+ description: "First-time setup for a project: machine preflight, side-by-side config, engagement-root + project resolution, initial 30d snapshot+stream pull across all enabled sources. Verbatim-by-default per `verbatim-by-default.instructions.md` every enabled source dispatched, no silent skips. CRM bootstrap discovery REQUIRED to run live Dataverse 4-step resolution before declaring disabled per `crm-bootstrap-discovery.instructions.md` (v2.3.0). Writes per-user refresh report per `run-reports.instructions.md`. Cleans stale no-match notes on resolution per `cleanup-on-resolution.instructions.md`. Builds State/ only on `full` profile. Idempotent."
5
5
  ---
6
6
 
7
7
  # Skill: bootstrap-project
8
8
 
9
+ > **Verbatim-by-default**: every `pull-<source>` whose boundary is satisfied MUST be dispatched. Silent skips are defects. See `verbatim-by-default.instructions.md`.
10
+ >
11
+ > **Per-user bootstrap report REQUIRED**: at end of run, write `<project>/Evidence/<alias>/refresh-reports/<YYYY-MM-DD-HHmm>_bootstrap.md` per `run-reports.instructions.md`. Distinct from `<project>/bootstrap-status.md` (durable state) — this is per-user run narrative.
12
+ >
13
+ > **Cleanup on resolution**: when this run resolves an ID/folder/section, prune stale `no-match` / probe-trail notes per `cleanup-on-resolution.instructions.md`.
14
+ >
15
+ > **Capture learnings**: any quirk / fix discovered mid-run is appended to `<KUSHI_ROOT>/plugin/learnings/<source>.md` in the same turn per `capture-learnings.instructions.md`.
16
+ >
17
+ > **Canonical evidence layout** (HARD, kushi v3.12.1+): every per-source artifact lands under `<project>/Evidence/<alias>/<source>/{snapshot,stream,...}/` and **nowhere else** under `<project>/`. Sibling folders like `<project>/email-context/`, `<project>/notes/`, `<project>/_Weekly Summaries/` are FORBIDDEN. Bootstrap MUST (a) scaffold the canonical tree, and (b) before pulling, scan `<project>/` for non-canonical source-output folders and migrate each to `Evidence/<alias>/<source>/_legacy_<original-name>_pre-bootstrap/` (move, do not delete; log under `## Layout migrations` in the bootstrap report; add a `runs:` entry with `type: layout-migration`). See `evidence-layout-canonical.instructions.md`.
18
+
9
19
  Run this when the user says any of: "bootstrap a new project", "set up project evidence for `<X>`", "add me to project `<X>`", "I'm new to `<X>`", "do it all for `<X>`" (and the project has no Evidence/ folder yet).
10
20
 
11
21
  ## Profile-aware behavior
@@ -17,6 +27,10 @@ This skill is **profile-aware** as of Kushi v3.3.0:
17
27
 
18
28
  The active profile is read from `kushi-install.json#profile` next to this agent file. If absent, default to `standard`.
19
29
 
30
+ ## Bootstrap-status artifact
31
+
32
+ After every run (success or coverage-gaps), write `<project>/bootstrap-status.md` per the format contract in `instructions/bootstrap-status-format.instructions.md`. This is the project's fast-orientation artifact — required tables, normalized status vocabulary (`resolved`, `populated`, `unsynced`, `degraded-list-only`, `throttled-tooManyRequests`, `ado-not-complete`, `completed-with-coverage-gaps`), one-line final status. Do NOT inline run history here; that goes in `update-status.md`.
33
+
20
34
  ## Inputs
21
35
 
22
36
  - `<project>` — engagement name (fuzzy-matched per `engagement-root-resolution.instructions.md`).
@@ -62,6 +76,8 @@ Optional (only if user enables CRM/ADO):
62
76
  | `<engagement-root>/.project-evidence/crm/config.yml` | `templates/init/crm-config.template.yml` |
63
77
  | `<engagement-root>/.project-evidence/ado/config.yml` | `templates/init/ado-config.template.yml` |
64
78
 
79
+ **Boundaries upgrade for existing projects (v3.7.0+):** If `<engagement-root>/<project>/integrations.yml` already exists but has no top-level `boundaries:` key, append the scaffolded `boundaries:` block from `templates/init/project-integrations.template.yml` (preserving every existing key). Then proceed to Step 4 to populate it.
80
+
65
81
  ### Step 3 — Project folder scaffold
66
82
 
67
83
  Create the project folder structure (per `engagement-root-resolution.instructions.md`):
@@ -85,7 +101,66 @@ The `State/` subtree is created **only on `full` profile**. On `standard`, only
85
101
 
86
102
  ### Step 4 — Initial pull (last 30 days)
87
103
 
88
- Dispatch to each enabled per-source skill with `--window last 30 days`:
104
+ **Boundaries gate** (kushi v3.7.0+, per `scope-boundaries.instructions.md`): before dispatching any `pull-*`, read `<engagement-root>/<project>/integrations.yml#boundaries` and verify each enabled source has its required boundary key populated. For sources where bootstrap can auto-populate from existing `m365-mutable.json` discovery hints (e.g. a previously-discovered `section_file_id` lands in `boundaries.onenote.section_file_ids`), do so and continue. For sources where the boundary cannot be auto-populated, write the source as **disabled** in `integrations.yml` and add a one-liner to `<project>/OPEN-QUESTIONS-DRAFT.md` (or `State/09_open-questions.md` on `full` profile) asking the user to fill the boundary and re-enable.
105
+
106
+ For CRM and ADO additionally verify the global config files exist (`<engagement-root>/.project-evidence/{crm,ado}/config.yml`) with non-placeholder values; if missing, scaffold from `templates/init/{crm,ado}-config.template.yml` and park in Open Questions with the path and template reference. **Do NOT auto-improvise** by inferring a tenant/org or by narrating CRM evidence from email — both are explicit anti-patterns in v3.7.0.
107
+
108
+ **CRM discovery is REQUIRED before declaring `disabled` (kushi v3.11.0+, per `crm-bootstrap-discovery.instructions.md`).** If `<engagement-root>/.project-evidence/crm/config.yml` exists and `az` auth succeeds, bootstrap MUST run the full 4-step Dataverse REST resolution sequence from `pull-crm/SKILL.md#resolution-order-when-crmrecordid-is-unset` (title-first → all matching accounts → wide-text → recent-slice → ask user) against the live endpoint before writing `boundaries.crm.disabled: true`. Any other path that sets `disabled: true` is a defect. If steps 1–4 all return 0, present the top 5 candidates from step 4 to the user before final disposition. Log the full attempt trail (queries + counts + outcome) to the bootstrap refresh-report under `## CRM resolution attempts`. If auth fails or Dataverse is unreachable, leave the boundary empty with `reason: 'crm-auth-unavailable-<date>'` — NOT `disabled: true` — so the next refresh retries.
109
+
110
+ #### Step 4a — Discovery & registry persistence (REQUIRED, kushi v3.7.8+, per `m365-id-registry.instructions.md`)
111
+
112
+ **Doctrine: bootstrap discovers, refresh consumes.** Bootstrap is the ONLY phase that probes WorkIQ to resolve canonical M365 identifiers. Refresh runs MUST read these from `m365-mutable.json#knownSections.<project>` and pass them into the index extractor verbatim. Refresh must NEVER re-discover — that is the source of "OneNote works for me sometimes" non-determinism.
113
+
114
+ For each enabled source, resolve and persist the canonical lookup keys into `<engagement-root>/.project-evidence/m365/m365-mutable.json#knownSections.<projectKey>`. The schema is fixed — populate every key the source supports:
115
+
116
+ ```jsonc
117
+ "knownSections": {
118
+ "<projectKey>": {
119
+ // OneNote (pull-onenote uses these as Step A inputs)
120
+ "one_sectionName": "<displayName>.one",
121
+ "one_sectionFileId": "<wdsectionfileid GUID>", // PRIMARY — verbatim into wdsectionfileid = <id>
122
+ "one_sectionGroupId": "<wdsectiongroupid GUID>", // when boundary is a section group
123
+ "one_sectionOneNoteGuid": "<wdsectiononenoteguid GUID>", // alternate identifier (older notebooks)
124
+ "one_sectionPath": "/<group>/<section>.one", // human-readable path for run-reports
125
+ "one_notebookSourceDoc": "<notebook sourceDoc GUID>", // parentReferenceId fallback
126
+ // Email
127
+ "emailContext": "Inbox/<folder-path>",
128
+ // Teams
129
+ "teamsChatContext": {
130
+ "chatHints": ["..."], // exact chat topics
131
+ "channelHints": ["..."], // exact channel display names
132
+ "participantHints": ["..."] // exact display names
133
+ },
134
+ // SharePoint (when boundary is a SP site/library/folder)
135
+ "sp_siteId": "<siteId>",
136
+ "sp_webId": "<webId>",
137
+ "sp_listId": "<listId>",
138
+ "sp_path": "/<site>/<library>/<folder>"
139
+ }
140
+ }
141
+ ```
142
+
143
+ **OneNote discovery procedure (deterministic, follow exactly):**
144
+
145
+ 1. From `boundaries.onenote.section_names[]` or user-provided section name (e.g. `HCA.one`), run:
146
+ ```
147
+ workiq ask -q "Search Microsoft 365 OneNote for sections matching the name <name>. For each match return: section display name, wdsectionfileid, wdsectiongroupid (parent group), wdsectiononenoteguid, parentReferenceId (notebook), sourceDoc URL. Flat table, no commentary, no truncation."
148
+ ```
149
+ 2. Extract the GUIDs from the table (the `wdsectionfileid={GUID}` and `wdsectionfileid={GUID}` markers appear inline in the cell text — parse them out; do NOT use prose summaries).
150
+ 3. Validate by re-issuing the Step A.1 enumerate query from `pull-onenote/SKILL.md` against the discovered `wdsectionfileid`. If the table has ≥ 1 page row, persist the IDs. If empty, try `wdsectiongroupid`, then `wdsectiononenoteguid`. If all three fail, write the section as `disabled` with `next_step: ask user for sourceDoc URL` and continue.
151
+ 4. Persist to `m365-mutable.json#knownSections.<projectKey>` and mirror the resolved IDs into `boundaries.onenote.section_file_ids[]` / `section_group_ids[]` in `integrations.yml`.
152
+ 5. Record one line in `bootstrap-status.md`: `OneNote: resolved wdsectionfileid=<id> via name "<name>" (N pages enumerated)`.
153
+ 6. **Browser-URL completeness gate (kushi v3.10.0+).** After persisting `one_sectionFileId`, the browser-required fields (`one_notebookSourceDoc`, `one_notebookSpoBaseUrl`, `one_sectionWebUrl`, `one_sectionName`) MUST also be present and valid. Run:
154
+ ```pwsh
155
+ node plugin/skills/pull-onenote/scripts/recapture-section-url.mjs --project <name> --engagement-root <engagement-root> --check
156
+ ```
157
+ If exit code = 1, dispatch the same script WITHOUT `--check` so it prompts the user to paste the section's address-bar URL from OneNote-for-Web. The script parses + persists all five fields. Re-run `--check` to confirm exit 0 before continuing to Step 4b. If the user declines to paste, mark `boundaries.onenote.disabled = true, reason = "section-url-not-captured"` in `integrations.yml`, park in Open Questions, and skip pull-onenote dispatch.
158
+
159
+ **SharePoint, Teams, Email, CRM, ADO** follow the same shape: bootstrap discovers and persists; refresh consumes. Per-source discovery procedures live in each `pull-*/SKILL.md`'s "Bootstrap discovery" section. Bootstrap MUST invoke each pull-*'s discovery probe with the user-supplied seed (folder name, channel name, request id, work item id), persist the resolved IDs, and only then dispatch the pull.
160
+
161
+ #### Step 4b — Dispatch
162
+
163
+ Then dispatch to each enabled per-source skill with `--window last 30 days` (each skill self-refuses if its boundary is still empty):
89
164
 
90
165
  1. `pull-email`
91
166
  2. `pull-teams`
@@ -94,9 +169,12 @@ Dispatch to each enabled per-source skill with `--window last 30 days`:
94
169
  5. `pull-sharepoint`
95
170
  6. `pull-crm` (if enabled)
96
171
  7. `pull-ado` (if enabled)
172
+ 8. `pull-misc` (if `<project>/external-links.txt` exists with ≥ 1 non-placeholder, non-delegated link)
97
173
 
98
174
  Each produces snapshot/ + stream/ output per `snapshot-vs-stream.instructions.md`.
99
175
 
176
+ **pull-misc bootstrap note:** if `<project>/external-links.txt` does NOT exist, scaffold it from `templates/init/external-links.template.txt` so the user has a place to paste links. Mark the source as `enabled: true, links: 0` in `integrations.yml#boundaries.misc` and skip the dispatch (nothing to fetch yet).
177
+
100
178
  ### Step 5 — Consolidate (single contributor = no-op)
101
179
 
102
180
  If multiple contributors already exist, dispatch `consolidate-evidence`. For first-time bootstrap (one user), skip.
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: "propose-ado-update"
3
+ version: "0.1.0-preview"
4
+ status: "preview"
5
+ description: "Read-only generator: reads the latest <project>/Evidence/_Consolidated/ and produces <project>/ado-updates/<YYYY-MM-DD>/proposed.md — a Markdown preview of the proposed ADO Initiative updates (FDE Status Summary field + Discussion comment). Performs NO writes to ADO. Safe to run unattended on the same Monday-9am schedule as refresh."
6
+ ---
7
+
8
+ # Skill: propose-ado-update
9
+
10
+ Run this when the user says any of: "propose ado update for `<X>`", "what would kushi write to ADO for `<X>`", "ado preview `<X>`", "draft ado update `<X>`".
11
+
12
+ This skill is **read-only**. It reads the most recent consolidated evidence and produces a Markdown file the user can review. It does **not** call ADO. Apply happens in the separate `apply-ado-update` skill, which is gated.
13
+
14
+ ## Profile
15
+
16
+ Belongs to the **`preview`** profile. Not present in `core` / `standard` / `full`. Opt in via `npx kushi-agents --clawpilot --profile preview`.
17
+
18
+ ## Deterministic config — do not invent paths
19
+
20
+ This skill does **NOT** create a new top-level config file. It reads from the configs Kushi already maintains:
21
+
22
+ | What | Where | Maintained by |
23
+ |---|---|---|
24
+ | ADO tenant + org + apiVersion + auth strategy | `<engagement-root>/.project-evidence/ado/config.yml` | `bootstrap-project` (global, one-time) |
25
+ | Per-project Initiative ID (`engagement_id`), area, title filter, discovery hints | `<engagement-root>/<project>/integrations.yml` under `ado:` | `bootstrap-project` + `pull-ado` (auto-discovers and persists) |
26
+ | Per-project **writes block** (allowlist, autoApply per field, strategy, fieldRefName) | `<engagement-root>/<project>/integrations.yml` under `ado.writes:` | First run of this skill scaffolds the block from the template, then user edits |
27
+
28
+ **Resolution is fully deterministic** — never ask the user for paths the bootstrap layer already resolved:
29
+
30
+ 1. `<engagement-root>` ← `~/.copilot/project-evidence.yml engagement_root` (per `engagement-root-resolution.instructions.md`).
31
+ 2. `<project>` folder ← fuzzy-match per `engagement-root-resolution.instructions.md` (knownSections → active_projects → subfolders).
32
+ 3. `<project>/integrations.yml ado.engagement_id` — REQUIRED. If `0` or missing → see "Prerequisites" below; never invent an ID.
33
+ 4. `<project>/integrations.yml ado.writes` — if missing, append the block from `<KUSHI_ROOT>/plugin/templates/ado-update/integrations-ado-writes.example.yml` and stop for user confirmation of `fieldRefName`.
34
+ 5. `<project>/Evidence/_Consolidated/<latest>_consolidated.md` — REQUIRED input. Never re-aggregate.
35
+
36
+ ## Prerequisites (HARD — do not bypass)
37
+
38
+ Refuse to produce `proposed.md` and tell the user exactly what's missing if any of these fail:
39
+
40
+ | Prereq | Failure message |
41
+ |---|---|
42
+ | `<project>/integrations.yml` exists | "Project not bootstrapped. Run `@Kushi bootstrap <project>` first." |
43
+ | `ado.engagement_id` > 0 | "ADO Initiative not yet linked for `<project>` (engagement_id is 0). pull-ado will auto-discover on next refresh; once `engagement_id` is set in `integrations.yml`, retry." |
44
+ | `<engagement-root>/.project-evidence/ado/config.yml` exists with non-placeholder `organization` | "Global ADO config missing or has placeholder org. Run `@Kushi bootstrap <project>` to scaffold, then fill `.project-evidence/ado/config.yml`." |
45
+ | At least one `Evidence/_Consolidated/<date>_consolidated.md` exists | "No consolidated evidence yet for `<project>`. Run `@Kushi refresh <project>` then `consolidate` first." |
46
+ | Latest consolidated file ≤ 8 days old | Continue but flag `stale-evidence` at top of `proposed.md`. |
47
+
48
+ ## Steps
49
+
50
+ 1. **Resolve config (deterministic)** — load global ADO config (tenant/org/apiVersion) + per-project `integrations.yml` (engagement_id + writes block). All from known paths above. No prompts unless `writes:` is missing.
51
+ 2. **First-run scaffold of `ado.writes:`** — if missing, append the template block to `integrations.yml ado:` (preserving every existing key). Stop. Tell user to confirm `fieldRefName` matches their tenant's process template. (Honors `side-by-side-config.instructions.md`: template stays generic, live filled file holds the real value.)
52
+ 3. **Pick the consolidated file** — most recent `<project>/Evidence/_Consolidated/<YYYY-MM-DD>_consolidated.md`. Optionally chase referenced per-source files for citations.
53
+ 4. **Read current ADO field value** (read-only GET, per `azure-auth-patterns.instructions.md` — pre-flight + tenant validation + token reuse + 401 retry):
54
+ ```
55
+ GET https://dev.azure.com/{org}/{project}/_apis/wit/workitems/{engagement_id}?api-version=7.1&fields={ado.writes.statusSummary.fieldRefName},System.Rev
56
+ ```
57
+ If field reference name not on the work item → record `field-not-found` in `proposed.md` and skip the field portion. Don't fail the run.
58
+ 5. **Distill the field update**:
59
+ - Format: `<MMM YYYY>: <one-liner ≤ 140 chars>`. Source: TL;DR / first-paragraph / explicit "summary" line in the consolidated file.
60
+ - Apply `strategy` (`append-month` default, `replace`, or `rolling-6`) to the value fetched in step 4.
61
+ - Compute the proposed new value locally; record `currentValue`, `proposedValue`, `revFetched` for the apply step's optimistic-lock guard.
62
+ 6. **Distill the Discussion comment**:
63
+ - Render `<KUSHI_ROOT>/plugin/templates/ado-update/discussion-comment.template.md` with sections: TL;DR, Decisions this week, Action items (owner + due), Risks/blockers, Asks, Evidence pack.
64
+ - Every bullet **must** carry a citation from the consolidated file (`[source: <path> · <date>]`). No bullet without a citation.
65
+ - End with the Kushi fingerprint line (used by `apply-ado-update` to detect duplicates):
66
+ ```
67
+ — Generated by Kushi v<version> · proposed <YYYY-MM-DD> · ledger:ado-updates/<YYYY-MM-DD>/ledger.jsonl
68
+ ```
69
+ 7. **Score confidence** per item (`high` / `medium` / `low`):
70
+ - `high` — explicit verbatim source quote, single source, recent (≤ this consolidated window).
71
+ - `medium` — paraphrased or aggregated from 2–3 sources.
72
+ - `low` — inferred, conflicting sources, or older than this window.
73
+ 8. **Write `proposed.md`** to `<engagement-root>/<project>/ado-updates/<YYYY-MM-DD>/proposed.md` from `<KUSHI_ROOT>/plugin/templates/ado-update/proposed.template.md`.
74
+ 9. **Echo summary** to user with path to `proposed.md` and one-line stats footer (`1 field, 1 comment, 7 cited bullets, 5 high / 2 medium / 0 low confidence`).
75
+
76
+ ## What this skill does NOT do
77
+
78
+ - Does NOT call any ADO `PATCH` or `POST` endpoint.
79
+ - Does NOT create or modify the global `.project-evidence/ado/config.yml`.
80
+ - Does NOT touch `<project>/integrations.yml` other than appending the `ado.writes:` sub-block on first run (preserving every existing key).
81
+ - Does NOT re-pull evidence (uses the most recent `_Consolidated/` file as-is).
82
+ - Does NOT write to the ledger (the ledger is written only by `apply-ado-update`).
83
+
84
+ ## Outputs
85
+
86
+ - `<engagement-root>/<project>/ado-updates/<YYYY-MM-DD>/proposed.md` — the human-reviewable proposal.
87
+ - (No state file changes, no ledger writes, no ADO writes.)
88
+
89
+ ## Failure modes
90
+
91
+ | Symptom | Recovery |
92
+ |---|---|
93
+ | `integrations.yml` missing | Refuse. Tell user to run `@Kushi bootstrap <project>` first. |
94
+ | `ado.engagement_id == 0` (Initiative not linked yet) | Refuse with the message in Prerequisites table. Do NOT prompt for an ID. |
95
+ | `ado.writes:` block missing | Scaffold from template, stop, ask user to confirm `fieldRefName`. |
96
+ | ADO 401 on fetch | Per `azure-auth-patterns.instructions.md` §4 — re-acquire token once, retry. If still 401, abort and report `auth-failed`. |
97
+ | ADO 404 on Initiative ID | Abort, report `initiative-not-found`. The `engagement_id` in integrations.yml is wrong; tell user to re-run pull-ado discovery or fix manually. |
98
+ | Field reference name not present on work item type | Skip the field portion of `proposed.md`; still produce the comment portion. |
99
+ | Latest consolidated > 8 days old | Continue but flag `stale-evidence` at top of `proposed.md`. |
100
+ | No `_Consolidated/` files at all | Refuse. Tell user to run `@Kushi refresh <project>` then `consolidate` first. |
101
+
102
+ ## References
103
+
104
+ - `update-ledger.instructions.md` — write-path doctrine and ledger schema (used by `apply-ado-update`; this skill produces the `proposed.md` shape `apply-ado-update` consumes).
105
+ - `azure-auth-patterns.instructions.md` — token acquisition, tenant validation, retry-on-401.
106
+ - `side-by-side-config.instructions.md` — config template vs live filled file (here: `integrations.yml ado.writes:` block).
107
+ - `engagement-root-resolution.instructions.md` — resolving `<engagement-root>` and `<project>`.
108
+ - `evidence-thoroughness.instructions.md` — what counts as a citable bullet.