kushi-agents 4.4.0 → 4.4.3
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/bin/cli.mjs +2 -4
- package/package.json +1 -1
- package/plugin/agents/kushi.agent.md +5 -1
- package/plugin/instructions/ado-engagement-tree.instructions.md +1 -1
- package/plugin/instructions/az-auth-conditional.instructions.md +2 -2
- package/plugin/instructions/azure-auth-patterns.instructions.md +6 -6
- package/plugin/instructions/bootstrap-status-format.instructions.md +15 -2
- package/plugin/instructions/cleanup-on-resolution.instructions.md +1 -1
- package/plugin/instructions/communication-guidelines.instructions.md +79 -0
- package/plugin/instructions/crm-bootstrap-discovery.instructions.md +1 -1
- package/plugin/instructions/deferred-retry-on-workiq-fail.instructions.md +155 -0
- package/plugin/instructions/engagement-root-resolution.instructions.md +13 -10
- package/plugin/instructions/evidence-layout-canonical.instructions.md +2 -2
- package/plugin/instructions/fallback-status-reporting.instructions.md +104 -0
- package/plugin/instructions/fde-grounding.instructions.md +146 -0
- package/plugin/instructions/identity-resolution.instructions.md +15 -8
- package/plugin/instructions/m365-id-registry.instructions.md +1 -1
- package/plugin/instructions/scope-boundaries.instructions.md +4 -4
- package/plugin/instructions/status-taxonomy.instructions.md +118 -0
- package/plugin/instructions/workiq-only.instructions.md +4 -2
- package/plugin/lib/Get-KushiConfig.ps1 +112 -7
- package/plugin/prompts/bootstrap.prompt.md +64 -49
- package/plugin/skills/apply-ado-update/SKILL.md +2 -2
- package/plugin/skills/bootstrap-project/SKILL.md +10 -10
- package/plugin/skills/propose-ado-update/SKILL.md +3 -3
- package/plugin/skills/pull-ado/SKILL.md +27 -13
- package/plugin/skills/pull-crm/SKILL.md +20 -9
- package/plugin/skills/pull-email/SKILL.md +2 -2
- package/plugin/skills/pull-meetings/SKILL.md +1 -1
- package/plugin/skills/pull-onenote/scripts/recapture-section-url.mjs +2 -1
- package/plugin/skills/pull-onenote/write-snapshot.mjs +2 -1
- package/plugin/skills/pull-sharepoint/SKILL.md +1 -1
- package/plugin/skills/pull-teams/SKILL.md +1 -1
- package/plugin/skills/refresh-project/SKILL.md +21 -1
- package/plugin/skills/self-check/run.ps1 +24 -1
- package/plugin/templates/ado-update/integrations-ado-writes.example.yml +1 -1
- package/plugin/templates/init/integrations.template.yml +32 -19
- package/plugin/templates/init/m365-auth.template.json +5 -5
- package/plugin/templates/init/project-integrations.template.yml +2 -2
- package/plugin/templates/snapshot/onenote-page.template.md +3 -3
- package/src/config-loader.mjs +92 -5
- package/src/main.mjs +2 -30
- package/plugin/templates/init/ado-config.template.yml +0 -21
- package/plugin/templates/init/crm-config.template.yml +0 -16
- package/src/prompt.mjs +0 -42
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**"
|
|
3
|
+
description: "Always-on: every kushi FDE-shaped output (fde-intake, fde-report, fde-triage, build-state, project-status, ask-project FDE answers) MUST ground in the FDE reference pack at reference-packs/fde/, apply recency precedence, and pair every CRM-recorded decision with the confidence ladder. This is the doctrinal companion to the reference pack itself."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# FDE Reference Grounding (HARD RULE)
|
|
7
|
+
|
|
8
|
+
Every kushi output that interprets engagement health, FDE stage, fitness, risks, readiness, status, or recommended next steps MUST be **grounded in the FDE reference pack** rather than inferred from intuition or model priors.
|
|
9
|
+
|
|
10
|
+
The reference pack lives at:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
plugin/reference-packs/fde/
|
|
14
|
+
README.md
|
|
15
|
+
core-fde-reference.md # operating model, fitness criteria, anti-patterns, stage gates, risk categories
|
|
16
|
+
crm-field-manifest.md # FDE-CRM field shape (FE-* triage entity)
|
|
17
|
+
intake-questions.md # the 10-question intake (used by fde-intake skill)
|
|
18
|
+
report-doctrine.md # report shape doctrine (used by fde-report skill)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Per `reference-packs` doctrine, the **effective** pack is the 3-layer override:
|
|
22
|
+
|
|
23
|
+
1. Project: `<engagement-root>/<project>/.kushi-reference/fde/<file>.md` (highest)
|
|
24
|
+
2. User: `~/.copilot/kushi-reference/fde/<file>.md` (override)
|
|
25
|
+
3. Packaged: `<install-dest>/reference-packs/fde/<file>.md` (default)
|
|
26
|
+
|
|
27
|
+
Citations MUST carry the layer marker: `[source: reference-packs/fde/<file>.md · packaged|user-override|project-override]`.
|
|
28
|
+
|
|
29
|
+
## Required behavior
|
|
30
|
+
|
|
31
|
+
### For every FDE-shaped output
|
|
32
|
+
|
|
33
|
+
1. **Read the pack first.** Before drafting any FDE-shaped artifact, read `reference-packs/fde/README.md` and enumerate the human-readable files. Treat the folder as ONE reference set; any file may contribute.
|
|
34
|
+
2. **Score against the 10-criterion FDE Fitness Checklist** from `core-fde-reference.md`:
|
|
35
|
+
- use case fit, platform commitment, C-level sponsor, hypervelocity culture, co-build commitment, funding clarity, measurable outcomes, contracting speed, business owner engagement, non-standard scope.
|
|
36
|
+
- Report which criteria are met, unclear, at risk — never just an overall thumbs-up.
|
|
37
|
+
3. **Map every risk to one of the eight FDE risk categories** (also from `core-fde-reference.md`):
|
|
38
|
+
- Competitive & Strategic Fit, Funding & Commercial, Contracting / Procurement, Sponsorship, Hypervelocity / Culture, Scope / Use Case Fit, Resourcing (MS side), Handover / Sustainability.
|
|
39
|
+
- Free-form risk taxonomies are a defect.
|
|
40
|
+
4. **Flag FDE anti-patterns explicitly** when evidence suggests drift toward what FDE is not: advisory-only, long governance cycles, platform-agnostic, staff-aug, out-of-box use case.
|
|
41
|
+
5. **Use CRM `Status` as a primary lifecycle signal** when available. Translate it via the CRM Triage Plan mapping in `core-fde-reference.md`. Distinguish carefully between `Completed`, `Withdrawn`, `On Hold`, discovery-stage, and active-delivery statuses.
|
|
42
|
+
6. **Call out mismatches explicitly** when structured system state, older notes, or older artifacts imply a different reality than newer evidence.
|
|
43
|
+
|
|
44
|
+
### Recency precedence (every conclusion, not just status)
|
|
45
|
+
|
|
46
|
+
When dated sources conflict, newer evidence has more authority — and not only for status, but also for **conclusions, risk posture, momentum, blockers, ownership assumptions, and recommended next steps**.
|
|
47
|
+
|
|
48
|
+
Default precedence order (unless the user explicitly asks otherwise):
|
|
49
|
+
|
|
50
|
+
1. latest CRM note entries
|
|
51
|
+
2. latest meeting transcripts
|
|
52
|
+
3. latest dated local project docs / assets in `<project>/Evidence/`
|
|
53
|
+
4. latest external linked notes / docs (OneNote, SharePoint)
|
|
54
|
+
5. older CRM notes and historical project artifacts
|
|
55
|
+
|
|
56
|
+
**When newer evidence supersedes an older conclusion or signal, say so directly** — do not blend the two into an averaged summary. If a recommendation from an older source is no longer appropriate because of newer evidence, state that it has been superseded; do not repeat it as active guidance.
|
|
57
|
+
|
|
58
|
+
Do not let stale evidence dominate synthesis. If an older source says a decision is open, a blocker is active, or a plan is current, but a newer dated source shows the issue was resolved or reversed, the newer source drives the narrative.
|
|
59
|
+
|
|
60
|
+
### CRM field values vs confirmed facts
|
|
61
|
+
|
|
62
|
+
This rule is the FDE-specific application of `evidence-confidence-ladder.instructions.md`. Every materially important FDE response (funding, owner, scope decision, timeline, legal / commercial gate, SI lane) MUST carry one of:
|
|
63
|
+
|
|
64
|
+
- `internal-only` — CRM/ADO field recorded; no customer-facing confirmation in evidence
|
|
65
|
+
- `communicated` — customer or external stakeholder acknowledged in transcript / email / Teams
|
|
66
|
+
- `confirmed` — signed / approved / executed artifact on record
|
|
67
|
+
|
|
68
|
+
A CRM-only signal is **not** a confirmed fact. Do not say "ECIF is the selected funding model" based on a `statuscode` flip alone. Say "Internal team decision favors ECIF (CRM field updated <date>, `internal-only`); latest customer-facing transcript predates the change; no `communicated` evidence yet."
|
|
69
|
+
|
|
70
|
+
For living triage reports (`fde-triage` output), every row that drives a decision (`FDE Fit First`, `ECIF Confirmation Gate`, `Verification Evidence`) MUST classify the response as one of `CRM-only` / `Cross-verified` / `Conflicting evidence` and cite the confirming source + date for the upgrade past `CRM-only`.
|
|
71
|
+
|
|
72
|
+
### Full customer view requires in-session source resolution
|
|
73
|
+
|
|
74
|
+
This grounding doctrine defines **how to interpret** evidence. It does NOT by itself satisfy the requirement to retrieve every applicable customer artifact.
|
|
75
|
+
|
|
76
|
+
Before drafting a "full view", "complete picture", or equivalent FDE-shaped output, the current session MUST attempt retrieval of every applicable source category that has a defined retrieval path:
|
|
77
|
+
|
|
78
|
+
1. CRM (Dataverse / FDE triage entity)
|
|
79
|
+
2. Meeting transcripts
|
|
80
|
+
3. Email
|
|
81
|
+
4. Teams chats
|
|
82
|
+
5. OneNote
|
|
83
|
+
6. SharePoint / external linked artifacts
|
|
84
|
+
7. ADO (when an engagement WI exists)
|
|
85
|
+
|
|
86
|
+
For each, record one of: `retrieved` / `not present for project` / `attempted but blocked` (with reason). Per `status-taxonomy.instructions.md`, use the closed-set Status values. Per `fallback-status-reporting.instructions.md`, mark fallback recoveries explicitly.
|
|
87
|
+
|
|
88
|
+
Do not describe an output as a `full view`, `complete picture`, `comprehensive`, or equivalent unless these source categories were retrieved or explicitly attempted+dispositioned in the current session.
|
|
89
|
+
|
|
90
|
+
### Workspace evidence boundary + source quotes
|
|
91
|
+
|
|
92
|
+
For every report, summary, recommendation, status response, or inferred conclusion:
|
|
93
|
+
|
|
94
|
+
1. Use workspace evidence only (this repository's context, with priority on `<project>/Evidence/` and the configured reference pack).
|
|
95
|
+
2. Do not invent or assume facts not present in retrieved evidence.
|
|
96
|
+
3. Do not fill gaps with unstated assumptions. If evidence is missing, state `insufficient evidence in workspace context`.
|
|
97
|
+
4. Quote sources for material claims using the kushi citation format: `[source: <relative-path> · <YYYY-MM-DD>]`. For reference-pack citations: `[source: reference-packs/fde/<file>.md · packaged|user-override|project-override]`.
|
|
98
|
+
5. For every key conclusion, include at least one source line.
|
|
99
|
+
6. If sources are ambiguous or conflicting, state so clearly and apply date-based recency precedence.
|
|
100
|
+
7. Living triage reports MUST include a complete `Sources Used (Complete Ledger)` section per `citation-ledger.instructions.md`.
|
|
101
|
+
|
|
102
|
+
### CRM notes integration
|
|
103
|
+
|
|
104
|
+
When kushi assists with CRM note authoring (manual today; `propose-crm-update` future), include a brief FDE fitness signal (1–2 sentences) whenever the note summarizes engagement status — e.g. "Funding model unconfirmed (criterion 6 at risk)" or "C-level sponsor accessible and engaged (criterion 3 met)."
|
|
105
|
+
|
|
106
|
+
### Engagement authoring artifacts
|
|
107
|
+
|
|
108
|
+
- `fde-intake` 10-question output MUST use `reference-packs/fde/intake-questions.md` as its prompt scaffold; do not paraphrase the question wording.
|
|
109
|
+
- `fde-report` shapes (weekly / short / long / fitness / stage-readiness) MUST cite `reference-packs/fde/report-doctrine.md` and `core-fde-reference.md` for stage gates and fitness mapping.
|
|
110
|
+
- `fde-triage` bundle MUST include the FDE Fitness Checklist (file 01) and map every risk to the eight categories (file 03).
|
|
111
|
+
|
|
112
|
+
### Status reports / readouts
|
|
113
|
+
|
|
114
|
+
- Treat CRM `Status` as one of the first facts established in the summary.
|
|
115
|
+
- Translate raw `statuscode` into plain-language stage meaning, not just the numeric label.
|
|
116
|
+
- Do not describe `Withdrawn` or `On Hold` engagements with active-delivery language.
|
|
117
|
+
- Do not describe `Technical Assessment` or `Assigned` as `In Progress` unless execution evidence supports the distinction and the mismatch is called out.
|
|
118
|
+
- Let the newer dated source drive the narrative; mark the older interpretation as superseded.
|
|
119
|
+
|
|
120
|
+
### Inferred conclusions / recommendations / summaries
|
|
121
|
+
|
|
122
|
+
Apply the same recency precedence to conclusions about health, urgency, readiness, commitment level, decision ownership, and likely next actions. Older plans and recommendations are historical context when newer evidence changes the picture.
|
|
123
|
+
|
|
124
|
+
## Anti-patterns (defects)
|
|
125
|
+
|
|
126
|
+
1. Drafting an FDE-shaped output without reading the reference pack.
|
|
127
|
+
2. Inventing risk categories beyond the eight defined.
|
|
128
|
+
3. Treating a CRM field flip as a confirmed customer-facing decision.
|
|
129
|
+
4. Blending older and newer dated evidence into an averaged summary instead of letting newer evidence supersede.
|
|
130
|
+
5. Calling the output "comprehensive" / "full view" without running the in-session source-resolution sweep.
|
|
131
|
+
6. Citing the FDE pack without the layer marker (`packaged | user-override | project-override`).
|
|
132
|
+
|
|
133
|
+
## Always-on
|
|
134
|
+
|
|
135
|
+
This instruction applies to every kushi agent invocation and to any external consumer rendering kushi evidence into an FDE-shaped artifact.
|
|
136
|
+
|
|
137
|
+
## References
|
|
138
|
+
|
|
139
|
+
- `reference-packs/fde/README.md` — the pack itself.
|
|
140
|
+
- `evidence-confidence-ladder.instructions.md` — the three-state confidence vocabulary used here.
|
|
141
|
+
- `citation-ledger.instructions.md` — citation format (Sources Used ledger).
|
|
142
|
+
- `evidence-thoroughness.instructions.md` — depth bar (orthogonal: depth applies inside scope).
|
|
143
|
+
- `scope-boundaries.instructions.md` — what's in scope (orthogonal: scope defines surface).
|
|
144
|
+
- `fallback-status-reporting.instructions.md` — how to report retrieval outcome.
|
|
145
|
+
- `status-taxonomy.instructions.md` — closed-set Status values.
|
|
146
|
+
- skills: `fde-intake`, `fde-report`, `fde-triage`, `build-state`, `project-status`, `ask-project` (FDE-shaped answers).
|
|
@@ -37,30 +37,37 @@ Map the response:
|
|
|
37
37
|
> ✓ Identity: `Alex Smith <alex@microsoft.com>` (alias=`alex`). Edit `.kushi/config/user/project-evidence.yml` to override.
|
|
38
38
|
3. **Continue** the prompt.
|
|
39
39
|
|
|
40
|
-
## Failure modes
|
|
40
|
+
## Failure modes (kushi v4.4.1+: never block, never fallback to Graph)
|
|
41
|
+
|
|
42
|
+
Per `deferred-retry-on-workiq-fail.instructions.md`, identity resolution NEVER blocks the orchestrator and NEVER calls `m365_get_*` / Graph as a fallback. On WorkIQ failure, the agent writes a deferred-retry marker and continues with a derived alias so evidence still lands somewhere it can later be re-keyed.
|
|
41
43
|
|
|
42
44
|
| Scenario | Behavior |
|
|
43
45
|
|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
|
|
44
|
-
| WorkIQ returns auth error |
|
|
45
|
-
| WorkIQ returns empty / NO_RESULTS |
|
|
46
|
-
| WorkIQ binary missing |
|
|
47
|
-
| User has explicit non-placeholder values | Skip resolution entirely. Never overwrite user-set values.
|
|
46
|
+
| WorkIQ returns auth error | Write deferred-retry marker (`source: identity`, `error_class: auth-error`). Echo: *"⚠ Identity unresolved (WorkIQ auth). Using alias=`<from-config-or-env>`; will retry on next refresh. Sign in with `workiq accept-eula && workiq ask -q ping` and re-run."* Continue. **Do NOT call `m365_get_my_profile` or Graph `/me`.** |
|
|
47
|
+
| WorkIQ returns empty / NO_RESULTS | Write marker (`error_class: empty`). Echo: *"⚠ Identity unresolved (WorkIQ empty). Using alias=`<env-user>`; will retry on next refresh."* Continue. |
|
|
48
|
+
| WorkIQ binary missing | Installer pre-flight should catch this. If reached at skill-time, write marker (`error_class: cli-missing`), echo the install hint, continue with alias=`<env-user>`. |
|
|
49
|
+
| User has explicit non-placeholder values | Skip resolution entirely. Never overwrite user-set values. No marker needed. |
|
|
48
50
|
| Alias collision with another contributor | Bootstrap detects existing `Evidence/<alias>/` whose `contributors.yml` records a different email → ask the user to disambiguate (suggest `<alias>-<tenant-prefix>` e.g. `alex-ms`). |
|
|
49
51
|
|
|
52
|
+
**Derived alias fallback (when WorkIQ unavailable):** use `$env:USERNAME` (Windows) or `$env:USER` (POSIX) lowercased. Persist provisionally with `alias_resolved_from: env-fallback-pending-workiq`. The next refresh's deferred-retry drain will re-issue the WorkIQ probe and rename `Evidence/<env-alias>/` → `Evidence/<workiq-alias>/` if they differ.
|
|
53
|
+
|
|
50
54
|
## What NOT to do
|
|
51
55
|
|
|
52
56
|
* Do NOT ask the user `What alias should Kushi use?`. The legacy onboarding prompt is gone.
|
|
53
|
-
* Do NOT call `m365_
|
|
57
|
+
* Do NOT call `m365_get_my_profile`, `m365_*`, or Graph `/me` as a fallback. WorkIQ is the single source of identity truth. On failure, write a marker and use the env-fallback. See `workiq-only.instructions.md` and `deferred-retry-on-workiq-fail.instructions.md`.
|
|
58
|
+
* Do NOT block the bootstrap orchestrator on identity failure. Continue with the env-fallback alias; the marker drives the eventual reconciliation.
|
|
54
59
|
* Do NOT resolve on every run. Once persisted, the config values are authoritative.
|
|
55
60
|
|
|
56
61
|
## Integration with other doctrine
|
|
57
62
|
|
|
58
|
-
* `workiq-
|
|
63
|
+
* `workiq-only.instructions.md` — identity resolution is the canonical example of WorkIQ-only. M365 fallbacks are forbidden.
|
|
64
|
+
* `deferred-retry-on-workiq-fail.instructions.md` — on WorkIQ failure, mark + continue + inform; never block.
|
|
59
65
|
* `bootstrap-project` SKILL — Step 0 is identity resolution. Step 1 is project context.
|
|
60
66
|
* `tracking.instructions.md` — the resolved identity goes into the tracking artifact's frontmatter under `actor:`.
|
|
61
67
|
|
|
62
68
|
## References
|
|
63
69
|
|
|
64
|
-
* `workiq-
|
|
70
|
+
* `workiq-only.instructions.md` — the parent doctrine (supersedes legacy `workiq-first`).
|
|
71
|
+
* `deferred-retry-on-workiq-fail.instructions.md` — failure-mode contract.
|
|
65
72
|
* `engagement-root-resolution.instructions.md` — `projects_root` resolution (separate from identity).
|
|
66
73
|
* `templates/init/project-evidence.template.yml` — defaults to `<auto>` for these three fields.
|
|
@@ -12,7 +12,7 @@ priority: HARD
|
|
|
12
12
|
|
|
13
13
|
## The registry
|
|
14
14
|
|
|
15
|
-
`<
|
|
15
|
+
`<workspace>/.kushi/config/user/m365-mutable.json#knownSections.<projectKey>` is the **single source of truth** for canonical M365 identifiers per project.
|
|
16
16
|
|
|
17
17
|
Schema (populate every key the source supports):
|
|
18
18
|
|
|
@@ -21,7 +21,7 @@ host-fallback Graph call, and every CRM/ADO probe MUST honor.
|
|
|
21
21
|
Before issuing **any** WorkIQ query, `m365_*` host call, Graph REST call, or CRM/ADO
|
|
22
22
|
REST call, the skill MUST resolve the boundary it is operating inside from
|
|
23
23
|
`<engagement-root>/<project>/integrations.yml boundaries:` (per-source) or the
|
|
24
|
-
global `<
|
|
24
|
+
global `<workspace>/.kushi/config/shared/integrations.yml` (auth +
|
|
25
25
|
tenant + org). The resolved boundary MUST be recorded in the evidence file's
|
|
26
26
|
`## Source Basis` block, e.g.:
|
|
27
27
|
|
|
@@ -57,8 +57,8 @@ returns evidence over the same surface — no run-to-run drift.
|
|
|
57
57
|
|
|
58
58
|
| Skill | Hard prerequisite | Failure message (verbatim) |
|
|
59
59
|
|---|---|---|
|
|
60
|
-
| `pull-crm` | `<
|
|
61
|
-
| `pull-ado` | `<
|
|
60
|
+
| `pull-crm` | `<workspace>/.kushi/config/shared/integrations.yml` exists with non-placeholder `crm.environmentUrl` | `crm-config-missing — fill the crm: block in <workspace>/.kushi/config/shared/integrations.yml. See plugin/templates/init/integrations.template.yml.` |
|
|
61
|
+
| `pull-ado` | `<workspace>/.kushi/config/shared/integrations.yml` exists with non-placeholder `ado.organization` AND `ado.defaultProject` | `ado-config-missing — fill the ado: block in <workspace>/.kushi/config/shared/integrations.yml. See plugin/templates/init/integrations.template.yml.` |
|
|
62
62
|
| `propose-ado-update` | both above + `integrations.yml ado.engagement_id > 0` | per `propose-ado-update/SKILL.md` Prerequisites table |
|
|
63
63
|
|
|
64
64
|
Pre-v3.7.0 behavior allowed `pull-crm` to "narrate from email" when the live
|
|
@@ -172,7 +172,7 @@ On first run for a new project, bootstrap MUST:
|
|
|
172
172
|
3. For sources where bootstrap cannot auto-populate, write the source as
|
|
173
173
|
**disabled** (`enabled: false`) with a one-liner in `OPEN-QUESTIONS-DRAFT.md`
|
|
174
174
|
asking the user to fill the boundary and re-enable.
|
|
175
|
-
4. For CRM and ADO, ALSO check that the global `<
|
|
175
|
+
4. For CRM and ADO, ALSO check that the global `<workspace>/.kushi/config/shared/integrations.yml`
|
|
176
176
|
exists and has non-placeholder values; if not, scaffold from
|
|
177
177
|
`plugin/templates/init/{crm,ado}-config.template.yml` and park in
|
|
178
178
|
`OPEN-QUESTIONS-DRAFT.md` with the path the user needs to fill.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**"
|
|
3
|
+
description: "The single normalized vocabulary for Status + Retry-Signal values used in every kushi status artifact (bootstrap-status.md, refresh reports, run-log.yml, ask-project footers, fde-report cover lines). Replaces the ad-hoc strings that drifted across skills."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Status Taxonomy (HARD RULE)
|
|
7
|
+
|
|
8
|
+
Every place a kushi skill renders a per-source or per-task status MUST use a value from the closed taxonomy below. Pre-v4.4.2 skills used ad-hoc strings (`populated`, `unsynced`, `degraded`, `partial-cap`, `blocked-sandbox`, `no stream`, `half done`, `waiting`) — those are now mapped onto the canonical values here.
|
|
9
|
+
|
|
10
|
+
## 1. Status values (closed set)
|
|
11
|
+
|
|
12
|
+
| Status | Meaning | Use when |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `completed` | Direct path succeeded; full coverage. | Preferred path returned everything in scope. |
|
|
15
|
+
| `completed-via-fallback` | Alternate path recovered the result; full coverage. | Direct path failed but a documented fallback delivered the requested scope. See `fallback-status-reporting.instructions.md`. |
|
|
16
|
+
| `completed-with-coverage-gaps` | Result was produced but specific known gaps remain. | Some items in scope were not retrievable; gaps are enumerated. |
|
|
17
|
+
| `partial` | Less than the requested scope was delivered; rerun recommended. | Fewer items than the boundary called for; not all gaps are enumerable. |
|
|
18
|
+
| `failed` | Both primary and fallback paths failed; no usable evidence written. | Every documented path returned no usable result. |
|
|
19
|
+
| `blocked-auth` | Pre-flight or token acquisition failed; the source could not be queried. | `az account show` non-zero, `m365_status` not signed in, tenant mismatch, WorkIQ EULA pending, etc. |
|
|
20
|
+
| `blocked-config` | A required configuration value (per-project + global both empty) prevented querying. | `<source>-config-missing` or `<source>-boundary-missing` per `scope-boundaries.instructions.md` Rule 3. |
|
|
21
|
+
| `blocked-permission` | Auth succeeded but the principal lacks access to the target. | HTTP 403 / `accessDenied` / SharePoint `UnauthorizedAccessException` on the canonical API. |
|
|
22
|
+
| `blocked-throttled` | Service throttled the request; no narrower query succeeded. | `tooManyRequests`, `More than 3 retries performed`, `high demand` per `auth-and-retry §3`. |
|
|
23
|
+
| `unresolved` | Discovery returned no matches inside the configured boundary. | All resolution-order steps returned 0 candidates; user has not yet picked or widened. |
|
|
24
|
+
| `deferred` | WorkIQ failed after doubled-strict retry; deferred-retry marker written. | Per `deferred-retry-on-workiq-fail.instructions.md`. Next refresh drains the queue. |
|
|
25
|
+
| `not-applicable` | Source is not configured for this project. | Source enabled=false or boundary list empty by design (e.g. SharePoint when project has no team site). |
|
|
26
|
+
| `no-run-history` | Source has never been pulled for this project. | Used in backfill rows when creating status artifacts retroactively. |
|
|
27
|
+
|
|
28
|
+
### Mapping from legacy strings
|
|
29
|
+
|
|
30
|
+
| Legacy ad-hoc string | Canonical value |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `populated` | `completed` (or `completed-with-coverage-gaps` if `## Coverage Notes` flags gaps) |
|
|
33
|
+
| `unsynced` | `partial` (rerun recommended) OR `not-applicable` (if intentionally deferred) — pick by intent |
|
|
34
|
+
| `degraded` | `completed-with-coverage-gaps` |
|
|
35
|
+
| `degraded-list-only` | `completed-with-coverage-gaps` (note: bodies missing, index present) |
|
|
36
|
+
| `partial-cap` | `partial` |
|
|
37
|
+
| `partial-template` | `completed-with-coverage-gaps` |
|
|
38
|
+
| `blocked-sandbox` | `blocked-permission` (with reason: agent sandbox) |
|
|
39
|
+
| `throttled-tooManyRequests` | `blocked-throttled` |
|
|
40
|
+
| `cli-available` (preflight pass) | `completed` (preflight row only) |
|
|
41
|
+
| `resolved` (preflight pass) | `completed` (preflight row only) |
|
|
42
|
+
| `missing` (preflight) | `blocked-config` |
|
|
43
|
+
| `ado-not-complete` | `partial` (with reason) |
|
|
44
|
+
| `no-match` | `unresolved` |
|
|
45
|
+
| `❌ all paths failed` | `failed` |
|
|
46
|
+
| `❌ workiq-empty-after-retry` | `deferred` (marker written) OR `failed` (if no marker for permanent reasons) |
|
|
47
|
+
|
|
48
|
+
## 2. Retry-Signal values (closed set)
|
|
49
|
+
|
|
50
|
+
| Retry Signal | Meaning |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `none` | No retry needed; result is settled. |
|
|
53
|
+
| `watch` | Usable result exists but direct-path gaps are worth reviewing later. |
|
|
54
|
+
| `retry` | Rerun is recommended; the next `refresh <project>` should pick this up. |
|
|
55
|
+
| `user-action` | Retry requires a user step first (paste verbatim, widen boundary, `az login`, install workiq, sign in to m365). |
|
|
56
|
+
|
|
57
|
+
### Default mapping (Status → Retry Signal)
|
|
58
|
+
|
|
59
|
+
| Status | Default Retry Signal |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `completed` | `none` |
|
|
62
|
+
| `completed-via-fallback` | `watch` |
|
|
63
|
+
| `completed-with-coverage-gaps` | `watch` |
|
|
64
|
+
| `partial` | `retry` |
|
|
65
|
+
| `failed` | `retry` |
|
|
66
|
+
| `blocked-auth` | `user-action` |
|
|
67
|
+
| `blocked-config` | `user-action` |
|
|
68
|
+
| `blocked-permission` | `user-action` |
|
|
69
|
+
| `blocked-throttled` | `retry` (next run, after backoff) |
|
|
70
|
+
| `unresolved` | `user-action` (pick a candidate or widen boundary) |
|
|
71
|
+
| `deferred` | `retry` (auto-drained by refresh Step 2a) |
|
|
72
|
+
| `not-applicable` | `none` |
|
|
73
|
+
| `no-run-history` | `none` |
|
|
74
|
+
|
|
75
|
+
A skill MAY override the default — but it must include the override reason in the `notes` column.
|
|
76
|
+
|
|
77
|
+
## 3. Required usage
|
|
78
|
+
|
|
79
|
+
1. `bootstrap-status.md` Context Artifact Status table — `Status` column values MUST come from §1. A new `Retry` column (added v4.4.2) MUST contain a §2 value.
|
|
80
|
+
2. `Evidence/run-log.yml#sources.<source>.last_status` — MUST be a §1 value.
|
|
81
|
+
3. `Evidence/run-log.yml#sources.<source>.retry_signal` (new v4.4.2 field) — MUST be a §2 value.
|
|
82
|
+
4. Refresh report (`Evidence/<alias>/refresh-reports/<ts>_refresh.md`) per-source summary table — same columns + same vocabulary.
|
|
83
|
+
5. `fde-report` cover line — when summarizing source coverage, use these values; do not invent new ones.
|
|
84
|
+
6. `ask-project` answer footer — when surfacing coverage caveats (`Source basis: completed-via-fallback`), use these values.
|
|
85
|
+
|
|
86
|
+
## 4. Retry review behavior
|
|
87
|
+
|
|
88
|
+
When the user asks "what failed?", "anything to retry?", "redo errors", or "/refresh failed" (`refresh-project` accepts this argument variant):
|
|
89
|
+
|
|
90
|
+
1. Read every `<project>/Evidence/<alias>/run-log.yml` and every `<project>/bootstrap-status.md` newest-first.
|
|
91
|
+
2. Filter to rows where `retry_signal` is `retry` or `deferred` is the status.
|
|
92
|
+
3. If the user named a time window (e.g. "past 2 days"), filter by run timestamp first.
|
|
93
|
+
4. Offer or execute the per-source `pull-*` again — scoped to the original boundary + window (no scope widening).
|
|
94
|
+
5. After retry, update the per-source row with the new Status + Retry Signal. Never delete history; append a new row newest-first.
|
|
95
|
+
|
|
96
|
+
## 5. Backfill rule
|
|
97
|
+
|
|
98
|
+
If a project has artifacts (`bootstrap-status.md`, snapshots) but no normalized status row yet (pre-v4.4.2 history):
|
|
99
|
+
|
|
100
|
+
- Create a backfill row using the best available evidence.
|
|
101
|
+
- Set `Status` from the legacy-string mapping in §1.
|
|
102
|
+
- Set `Retry Signal` from §2 default mapping.
|
|
103
|
+
- Note `(backfill)` in the row's `Notes` column.
|
|
104
|
+
- Do not invent precision: if exact timestamps are unavailable, write the date and note `(time inferred)`.
|
|
105
|
+
|
|
106
|
+
## 6. Non-destructive rule
|
|
107
|
+
|
|
108
|
+
- Status artifacts are append-only at the row level. Never delete a historical row to "clean up".
|
|
109
|
+
- Newest rows go at the top of every status table.
|
|
110
|
+
- When a status changes between runs, write a new row; do not edit the old row in place.
|
|
111
|
+
|
|
112
|
+
## References
|
|
113
|
+
|
|
114
|
+
- `fallback-status-reporting.instructions.md` — when `completed-via-fallback` applies.
|
|
115
|
+
- `auth-and-retry.instructions.md §4` — `errors[]` schema (signatures map to Status via the legacy table above).
|
|
116
|
+
- `bootstrap-status-format.instructions.md` — the artifact that uses this vocabulary most prominently.
|
|
117
|
+
- `deferred-retry-on-workiq-fail.instructions.md` — `deferred` status semantics.
|
|
118
|
+
- `scope-boundaries.instructions.md` — `blocked-config` rules.
|
|
@@ -42,8 +42,8 @@ For every M365 source in scope:
|
|
|
42
42
|
|
|
43
43
|
1. **WorkIQ FIRST and ONLY.** Issue the canonical query from the table below.
|
|
44
44
|
2. **If WorkIQ returns insufficient content** (empty, truncated, or only a summary when the query asked for verbatim): retry ONCE with the doubled-strict prompt from the same row.
|
|
45
|
-
3. **If WorkIQ still fails or is unavailable**:
|
|
46
|
-
4. **DO NOT attempt** `m365_get_transcript`, `m365_get_facilitator_notes`, `m365_list_meetings`, `m365_list_events`, `m365_search_files` (for content), `m365_download_file` (for transcript/notes), or any Graph REST URL for the in-scope sources above. These are FORBIDDEN. Calling them is a defect; coverage.md must NOT show them in the attempt trail.
|
|
45
|
+
3. **If WorkIQ still fails or is unavailable**: follow `deferred-retry-on-workiq-fail.instructions.md` — write a deferred-retry marker under `<project>/Evidence/<alias>/_deferred-retries/`, surface a one-liner in coverage.md and the run report, and **continue the run** for the remaining sources. The next `refresh-project` drains the queue. User-paste remains available as a manual recovery the user MAY do later by populating the artifact directly and deleting the marker — it is NOT the agent's recovery flow.
|
|
46
|
+
4. **DO NOT attempt** `m365_get_transcript`, `m365_get_facilitator_notes`, `m365_list_meetings`, `m365_list_events`, `m365_search_files` (for content), `m365_download_file` (for transcript/notes), or any Graph REST URL for the in-scope sources above. These are FORBIDDEN — **including as a "last-resort" fallback after WorkIQ fails** (kushi v4.4.1+). Calling them is a defect; coverage.md must NOT show them in the attempt trail. The deferred-retry marker IS the audit trail for WorkIQ failures.
|
|
47
47
|
5. **Allowed alongside WorkIQ** (structured-data dumps only): `m365_list_chat_messages` for chat-id'd threads → `chat-messages.json`. These run in parallel with the WorkIQ pull, not as a substitute.
|
|
48
48
|
|
|
49
49
|
## Canonical WorkIQ commands (CODIFIED — do not re-discover)
|
|
@@ -174,6 +174,7 @@ If `Result: SUMMARY-ONLY` after doubled-strict retry: the artifact is acceptable
|
|
|
174
174
|
|
|
175
175
|
## Anti-patterns (defects)
|
|
176
176
|
|
|
177
|
+
0. **Falling back to `m365_get_*` / Graph after a WorkIQ failure (kushi v4.4.1+).** FORBIDDEN. Even framed as "a last-resort partial," "just to try," or "we already have a WorkIQ marker so this is harmless." The doctrine is: WorkIQ fail → deferred-retry marker → continue → next refresh retries. Never a Graph escape hatch. See `deferred-retry-on-workiq-fail.instructions.md`.
|
|
177
178
|
1. **Calling `m365_get_transcript`, `m365_get_facilitator_notes`, `m365_list_meetings`, `m365_list_events` from a kushi pull-* skill.** FORBIDDEN. These tools have a near-100% failure rate in this workspace. Use WorkIQ.
|
|
178
179
|
2. **Using Graph REST URLs directly** (e.g. `https://graph.microsoft.com/v1.0/me/onlineMeetings/...`) from a kushi pull-* skill. FORBIDDEN for the in-scope M365 sources. Use WorkIQ.
|
|
179
180
|
3. **Re-discovering the right WorkIQ prompt every run.** FORBIDDEN. Use the codified prompts from the table above. If a new source variant is needed, add a row to the table, do not improvise.
|
|
@@ -192,3 +193,4 @@ If `Result: SUMMARY-ONLY` after doubled-strict retry: the artifact is acceptable
|
|
|
192
193
|
- `plugin/instructions/ado-bootstrap-discovery.instructions.md` — ADO is OUT of WorkIQ scope; it uses ADO REST.
|
|
193
194
|
- `plugin/instructions/scope-boundaries.instructions.md` — every pull-* still respects integrations.yml#boundaries.
|
|
194
195
|
- `plugin/instructions/evidence-thoroughness.instructions.md` — verbatim is the bar; this rule operationalizes how to hit it.
|
|
196
|
+
- `plugin/instructions/deferred-retry-on-workiq-fail.instructions.md` (kushi v4.4.1+) — defines exactly what happens when WorkIQ fails. NO Graph fallback. Marker + continue + inform.
|
|
@@ -53,6 +53,92 @@ param(
|
|
|
53
53
|
|
|
54
54
|
$ErrorActionPreference = 'Stop'
|
|
55
55
|
|
|
56
|
+
# Schema-aware required-field map (kushi v4.4.1+).
|
|
57
|
+
# For each logical config name, list the dot-paths that MUST be populated
|
|
58
|
+
# (non-empty, non-sentinel) before the config is considered usable. The check
|
|
59
|
+
# runs IN ADDITION to the substring sentinel check.
|
|
60
|
+
$script:RequiredFields = @{
|
|
61
|
+
'm365-auth' = @(
|
|
62
|
+
'm365Auth.defaultTenantId',
|
|
63
|
+
'm365Auth.oneNote.defaultNotebookName',
|
|
64
|
+
'm365Auth.oneNote.defaultNotebookId',
|
|
65
|
+
'm365Auth.oneNote.defaultLinkOwner',
|
|
66
|
+
'm365Auth.emailContext.folders',
|
|
67
|
+
'm365Auth.sharePointContext.localProjectsRoot'
|
|
68
|
+
)
|
|
69
|
+
'project-evidence' = @(
|
|
70
|
+
'identity.alias',
|
|
71
|
+
'identity.email',
|
|
72
|
+
'engagement_root'
|
|
73
|
+
)
|
|
74
|
+
# integrations.yml is shared and per-project — required-field check is
|
|
75
|
+
# the consumer skill's job (it knows which sources are enabled).
|
|
76
|
+
'integrations' = @()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Sentinel substrings that indicate "still a placeholder."
|
|
80
|
+
$script:Sentinels = @(
|
|
81
|
+
'__FILL_ME_IN__',
|
|
82
|
+
'<auto>',
|
|
83
|
+
'<TENANT_ID>',
|
|
84
|
+
'<NOTEBOOK_ID>',
|
|
85
|
+
'<NOTEBOOK_NAME>',
|
|
86
|
+
'<LINK_OWNER>',
|
|
87
|
+
'<SP_LOCAL_ROOT>',
|
|
88
|
+
'<your-alias>',
|
|
89
|
+
'<Your Full Name>',
|
|
90
|
+
'your.email@example.com'
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
function Test-Sentinel {
|
|
94
|
+
param([string] $Value)
|
|
95
|
+
if ([string]::IsNullOrWhiteSpace($Value)) { return $true }
|
|
96
|
+
foreach ($s in $script:Sentinels) {
|
|
97
|
+
if ($Value -like "*$s*") { return $true }
|
|
98
|
+
}
|
|
99
|
+
return $false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function Get-DotPath {
|
|
103
|
+
param([object] $Obj, [string] $DotPath)
|
|
104
|
+
$cur = $Obj
|
|
105
|
+
foreach ($seg in $DotPath -split '\.') {
|
|
106
|
+
if ($null -eq $cur) { return $null }
|
|
107
|
+
if ($cur -is [System.Collections.IDictionary]) {
|
|
108
|
+
$cur = $cur[$seg]
|
|
109
|
+
} else {
|
|
110
|
+
$cur = $cur.$seg
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return $cur
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function Test-RequiredFields {
|
|
117
|
+
param([string] $Name, [object] $Parsed)
|
|
118
|
+
$required = $script:RequiredFields[$Name]
|
|
119
|
+
if (-not $required) { return @() }
|
|
120
|
+
$missing = @()
|
|
121
|
+
foreach ($field in $required) {
|
|
122
|
+
$val = Get-DotPath -Obj $Parsed -DotPath $field
|
|
123
|
+
if ($null -eq $val) { $missing += $field; continue }
|
|
124
|
+
# Arrays: must have at least one non-sentinel element.
|
|
125
|
+
if ($val -is [System.Collections.IEnumerable] -and -not ($val -is [string])) {
|
|
126
|
+
$arr = @($val)
|
|
127
|
+
if ($arr.Count -eq 0) { $missing += $field; continue }
|
|
128
|
+
$allBlank = $true
|
|
129
|
+
foreach ($item in $arr) {
|
|
130
|
+
if ($item -is [string]) {
|
|
131
|
+
if (-not (Test-Sentinel $item)) { $allBlank = $false; break }
|
|
132
|
+
} else { $allBlank = $false; break }
|
|
133
|
+
}
|
|
134
|
+
if ($allBlank) { $missing += $field }
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
if ($val -is [string] -and (Test-Sentinel $val)) { $missing += $field }
|
|
138
|
+
}
|
|
139
|
+
return ,$missing
|
|
140
|
+
}
|
|
141
|
+
|
|
56
142
|
function Get-DefaultExtension([string] $name) {
|
|
57
143
|
if ($name -match '^(project-evidence|integrations)$') { return 'yml' }
|
|
58
144
|
return 'json'
|
|
@@ -84,9 +170,13 @@ if ($Path) { return $resolved }
|
|
|
84
170
|
$raw = Get-Content -LiteralPath $resolved -Raw
|
|
85
171
|
|
|
86
172
|
if (-not $AllowPlaceholders) {
|
|
87
|
-
|
|
173
|
+
$sentinelHit = $false
|
|
174
|
+
foreach ($s in $script:Sentinels) {
|
|
175
|
+
if ($raw -like "*$s*") { $sentinelHit = $true; break }
|
|
176
|
+
}
|
|
177
|
+
if ($sentinelHit) {
|
|
88
178
|
throw @"
|
|
89
|
-
Kushi config '$resolved' still has template placeholders (__FILL_ME_IN__
|
|
179
|
+
Kushi config '$resolved' still has template placeholders (e.g. __FILL_ME_IN__, <auto>, <TENANT_ID>).
|
|
90
180
|
Edit the file with your actual values, or pass -AllowPlaceholders to bypass this check.
|
|
91
181
|
"@
|
|
92
182
|
}
|
|
@@ -94,16 +184,31 @@ Edit the file with your actual values, or pass -AllowPlaceholders to bypass this
|
|
|
94
184
|
|
|
95
185
|
if ($Raw) { return $raw }
|
|
96
186
|
|
|
97
|
-
switch ($ext) {
|
|
187
|
+
$parsed = switch ($ext) {
|
|
98
188
|
'json' {
|
|
99
|
-
|
|
189
|
+
$raw | ConvertFrom-Json -Depth 100
|
|
100
190
|
}
|
|
101
191
|
{ $_ -in 'yml','yaml' } {
|
|
102
192
|
if (Get-Module -ListAvailable -Name 'powershell-yaml') {
|
|
103
193
|
Import-Module powershell-yaml -ErrorAction Stop
|
|
104
|
-
|
|
194
|
+
ConvertFrom-Yaml -Yaml $raw
|
|
195
|
+
} else {
|
|
196
|
+
Write-Warning "powershell-yaml not installed; required-field validation skipped. Install with: Install-Module powershell-yaml -Scope CurrentUser"
|
|
197
|
+
$null
|
|
105
198
|
}
|
|
106
|
-
Write-Warning "powershell-yaml not installed; returning raw YAML text. Install with: Install-Module powershell-yaml -Scope CurrentUser"
|
|
107
|
-
return $raw
|
|
108
199
|
}
|
|
109
200
|
}
|
|
201
|
+
|
|
202
|
+
if (-not $AllowPlaceholders -and $null -ne $parsed) {
|
|
203
|
+
$missing = Test-RequiredFields -Name $Name -Parsed $parsed
|
|
204
|
+
if ($missing.Count -gt 0) {
|
|
205
|
+
throw @"
|
|
206
|
+
Kushi config '$resolved' is missing required fields:
|
|
207
|
+
$(($missing | ForEach-Object { " - $_" }) -join "`n")
|
|
208
|
+
Edit the file with your actual values, or pass -AllowPlaceholders to bypass this check.
|
|
209
|
+
"@
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if ($null -eq $parsed) { return $raw }
|
|
214
|
+
return $parsed
|