kushi-agents 4.3.0 → 4.4.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.
- package/package.json +2 -4
- package/plugin/agents/kushi.agent.md +3 -3
- 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 +8 -8
- package/plugin/instructions/bootstrap-status-format.instructions.md +37 -2
- package/plugin/instructions/cleanup-on-resolution.instructions.md +1 -1
- 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 +16 -13
- package/plugin/instructions/evidence-layout-canonical.instructions.md +2 -2
- package/plugin/instructions/identity-resolution.instructions.md +19 -12
- package/plugin/instructions/m365-id-registry.instructions.md +1 -1
- package/plugin/instructions/multi-user-shared-files.instructions.md +87 -0
- package/plugin/instructions/run-reports.instructions.md +1 -1
- package/plugin/instructions/scope-boundaries.instructions.md +4 -4
- package/plugin/instructions/side-by-side-config.instructions.md +23 -17
- package/plugin/instructions/tracking.instructions.md +1 -1
- package/plugin/instructions/workiq-only.instructions.md +6 -4
- package/plugin/lib/Get-KushiConfig.ps1 +214 -0
- package/plugin/prompts/bootstrap.prompt.md +64 -35
- package/plugin/reference-packs/README.md +1 -1
- package/plugin/skills/apply-ado-update/SKILL.md +2 -2
- package/plugin/skills/ask-project/SKILL.md +1 -1
- package/plugin/skills/bootstrap-project/SKILL.md +18 -16
- package/plugin/skills/intro/SKILL.md +2 -2
- package/plugin/skills/propose-ado-update/SKILL.md +4 -4
- package/plugin/skills/pull-ado/SKILL.md +6 -6
- package/plugin/skills/pull-crm/SKILL.md +5 -5
- 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/azuredevops.template.json +159 -0
- package/plugin/templates/init/dynamics365.template.json +412 -0
- package/plugin/templates/init/m365-auth.template.json +5 -5
- package/{.github/config/m365-mutable.json.example → plugin/templates/init/m365-mutable.example.json} +1 -1
- package/plugin/templates/init/project-integrations.template.yml +2 -2
- package/plugin/templates/init/rsi-program-catalog.template.json +107 -0
- package/plugin/templates/snapshot/onenote-page.template.md +3 -3
- package/src/config-loader.mjs +156 -0
- package/src/constants.mjs +54 -18
- package/src/copy-assets.mjs +0 -76
- package/src/main.mjs +30 -26
- package/src/seed-config.mjs +88 -23
- package/src/seed-config.test.mjs +150 -0
- package/plugin/templates/init/ado-config.template.yml +0 -21
- package/plugin/templates/init/crm-config.template.yml +0 -16
- /package/{.github/config/m365-auth.json.example → plugin/templates/init/m365-auth.example.json} +0 -0
|
@@ -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.
|
|
@@ -5,20 +5,23 @@ description: "Side-by-side config rule — whenever the skill creates or changes
|
|
|
5
5
|
|
|
6
6
|
# Side-by-side config rule (HARD RULE)
|
|
7
7
|
|
|
8
|
-
Whenever the skill creates, changes, or extends any template in `<KUSHI_ROOT>/plugin/templates/init/`, it MUST also write the corresponding live file under `<
|
|
8
|
+
Whenever the skill creates, changes, or extends any template in `<KUSHI_ROOT>/plugin/templates/init/`, it MUST also write the corresponding live file in the workspace under `<workspace>/.kushi/config/user/` (for per-contributor identity + paths) or `<workspace>/.kushi/config/shared/` (for team-owned config the team commits).
|
|
9
9
|
|
|
10
10
|
Templates stay generic; the live file gets the actual filled-in fact. Never leave the user with only the template — that's a half-done config.
|
|
11
11
|
|
|
12
|
-
## The
|
|
12
|
+
## The three layers
|
|
13
13
|
|
|
14
14
|
| Layer | Where | Lifecycle |
|
|
15
15
|
|---|---|---|
|
|
16
16
|
| Template (generic) | `<KUSHI_ROOT>/plugin/templates/init/*.template.{json,yml}` | Ships with kushi, never edited per-user |
|
|
17
|
-
| Live
|
|
17
|
+
| Live shared | `<workspace>/.kushi/config/shared/*.{json,yml}` | Team-owned, committed; doctrine files overwrite on install, others seed-once |
|
|
18
|
+
| Live user | `<workspace>/.kushi/config/user/*.{json,yml}` | Per-contributor, gitignored; seed-once and preserved across upgrades |
|
|
19
|
+
|
|
20
|
+
Skills read configs via `<install-dest>/lib/Get-KushiConfig.ps1` which resolves `user/` first, then `shared/`.
|
|
18
21
|
|
|
19
22
|
## Discover → upsert immediately
|
|
20
23
|
|
|
21
|
-
Any time the skill discovers a high-confidence fact about a project (folder id, chat id, OneNote section id, CRM record id, ADO WI id, stakeholder hint, alias) — upsert it into the live mutable file (`<
|
|
24
|
+
Any time the skill discovers a high-confidence fact about a project (folder id, chat id, OneNote section id, CRM record id, ADO WI id, stakeholder hint, alias) — upsert it into the live mutable file (`<workspace>/.kushi/config/user/m365-mutable.json` under `m365Mutable.knownSections.<project>.<source>`) **in the same turn it was discovered**, with `discoveredOn: <today>` and `confidence: high|medium|low`.
|
|
22
25
|
|
|
23
26
|
Don't wait until the end of the run.
|
|
24
27
|
|
|
@@ -38,19 +41,22 @@ End every bootstrap / fix-up turn by listing the live config files (path + size
|
|
|
38
41
|
## Live config locations
|
|
39
42
|
|
|
40
43
|
```
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
<workspace>/.kushi/config/
|
|
45
|
+
shared/ ← committed; doctrine + team defaults
|
|
46
|
+
azuredevops.json ← ADO org/project/field-map doctrine (overwritten on install)
|
|
47
|
+
dynamics365.json ← CRM env/schema doctrine (overwritten on install)
|
|
48
|
+
rsi-program-catalog.json ← RSI segment reference (overwritten on install)
|
|
49
|
+
integrations.yml ← optional team CRM/ADO defaults (seed-once)
|
|
50
|
+
*.example ← reference scaffolds (overwritten on install)
|
|
51
|
+
user/ ← gitignored; per-contributor
|
|
52
|
+
project-evidence.yml ← your alias, engagement-root, active projects (seed-once)
|
|
53
|
+
m365-auth.json ← your tenant, default notebook, mailbox folders (seed-once)
|
|
54
|
+
m365-mutable.json ← discovered hints, auto-updated by skill (seed-once)
|
|
50
55
|
```
|
|
51
56
|
|
|
52
|
-
## Why
|
|
57
|
+
## Why side-by-side
|
|
53
58
|
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
59
|
+
- **Self-contained** — everything Kushi needs to run lives under `.kushi/`. No `.github/config/` split, no `~/.copilot/` scatter.
|
|
60
|
+
- **Multi-user safe** — the `user/` tier is per-contributor and gitignored; `shared/` is committed once and stays in sync via git.
|
|
61
|
+
- **Discoverable** — visible in VS Code's file tree, not buried in an OS-hidden home directory.
|
|
62
|
+
- **Repo-safe** — `<workspace>/.kushi/.gitignore` (auto-written by installer) excludes `config/user/` so personal IDs never leak.
|
|
@@ -77,7 +77,7 @@ kushi_version: 4.1.0
|
|
|
77
77
|
- Engagement root: `C:/.../Engagement Assets`
|
|
78
78
|
- Project folder: `HCA Healthcare`
|
|
79
79
|
- Alias: `ushak`
|
|
80
|
-
- Config: `<workspace>/.kushi/config/project-evidence.yml`
|
|
80
|
+
- Config: `<workspace>/.kushi/config/user/project-evidence.yml`
|
|
81
81
|
|
|
82
82
|
## Steps taken
|
|
83
83
|
|
|
@@ -42,13 +42,13 @@ 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)
|
|
50
50
|
|
|
51
|
-
The CLI is at `<USER_HOME>\.kushi\bin\workiq.cmd` (resolved from `<workspace>/.kushi/config/project-evidence.yml workiq.cli_path`; fall back to PATH; fall back to `~/.kushi/bin/workiq.cmd`).
|
|
51
|
+
The CLI is at `<USER_HOME>\.kushi\bin\workiq.cmd` (resolved from `<workspace>/.kushi/config/user/project-evidence.yml workiq.cli_path`; fall back to PATH; fall back to `~/.kushi/bin/workiq.cmd`).
|
|
52
52
|
|
|
53
53
|
Invocation shape:
|
|
54
54
|
|
|
@@ -153,7 +153,7 @@ List my Teams meetings between <YYYY-MM-DD> and <YYYY-MM-DD> where the subject c
|
|
|
153
153
|
|
|
154
154
|
Before the first WorkIQ query in a run:
|
|
155
155
|
|
|
156
|
-
1. Resolve CLI path: `<workspace>/.kushi/config/project-evidence.yml workiq.cli_path` → `Get-Command workiq` → `~/.kushi/bin/workiq.cmd`. If none resolves → log `workiq-not-on-path`, write evidence file pointing at install docs, STOP this source.
|
|
156
|
+
1. Resolve CLI path: `<workspace>/.kushi/config/user/project-evidence.yml workiq.cli_path` → `Get-Command workiq` → `~/.kushi/bin/workiq.cmd`. If none resolves → log `workiq-not-on-path`, write evidence file pointing at install docs, STOP this source.
|
|
157
157
|
2. Probe with `workiq ask -q "ping"`. If EULA prompt → `workiq accept-eula` once, retry.
|
|
158
158
|
3. Capture `--version` once into run-log for audit.
|
|
159
159
|
|
|
@@ -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.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Resolve and load a Kushi config file from the two-tier .kushi/config/ layout.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Kushi configs live in <workspace>/.kushi/config/ split across two subdirs:
|
|
7
|
+
- user/ per-contributor identity & local paths (gitignored)
|
|
8
|
+
- shared/ team-owned, safe to commit (doctrine + team defaults)
|
|
9
|
+
|
|
10
|
+
Lookup order (highest-priority first):
|
|
11
|
+
1. <workspace>/.kushi/config/user/<name>.<ext>
|
|
12
|
+
2. <workspace>/.kushi/config/shared/<name>.<ext>
|
|
13
|
+
|
|
14
|
+
By default the file is parsed (JSON or YAML inferred from extension) and
|
|
15
|
+
returned as a PowerShell object. Use -Raw for raw text, or -Path to only
|
|
16
|
+
resolve the path.
|
|
17
|
+
|
|
18
|
+
Throws if the file is missing or appears to still hold template
|
|
19
|
+
placeholder values (sentinel `__FILL_ME_IN__` or `<auto>`). Suppress with
|
|
20
|
+
-AllowPlaceholders (needed for the identity-resolution flow which fills
|
|
21
|
+
`<auto>` on first run).
|
|
22
|
+
|
|
23
|
+
.PARAMETER Name
|
|
24
|
+
Logical config name, e.g. `project-evidence`, `m365-auth`, `azuredevops`.
|
|
25
|
+
|
|
26
|
+
.PARAMETER Extension
|
|
27
|
+
Override extension. Defaults: yml for project-evidence/integrations; json otherwise.
|
|
28
|
+
|
|
29
|
+
.PARAMETER Workspace
|
|
30
|
+
Workspace root. Defaults to the current location.
|
|
31
|
+
|
|
32
|
+
.EXAMPLE
|
|
33
|
+
$auth = Get-KushiConfig -Name 'm365-auth'
|
|
34
|
+
$notebookId = $auth.m365Auth.oneNote.defaultNotebookId
|
|
35
|
+
|
|
36
|
+
.EXAMPLE
|
|
37
|
+
$cfgPath = Get-KushiConfig -Name 'project-evidence' -Path
|
|
38
|
+
#>
|
|
39
|
+
[CmdletBinding()]
|
|
40
|
+
param(
|
|
41
|
+
[Parameter(Mandatory = $true, Position = 0)]
|
|
42
|
+
[string] $Name,
|
|
43
|
+
|
|
44
|
+
[ValidateSet('json', 'yml', 'yaml')]
|
|
45
|
+
[string] $Extension,
|
|
46
|
+
|
|
47
|
+
[string] $Workspace = (Get-Location).Path,
|
|
48
|
+
|
|
49
|
+
[switch] $Raw,
|
|
50
|
+
[switch] $Path,
|
|
51
|
+
[switch] $AllowPlaceholders
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
$ErrorActionPreference = 'Stop'
|
|
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
|
+
|
|
142
|
+
function Get-DefaultExtension([string] $name) {
|
|
143
|
+
if ($name -match '^(project-evidence|integrations)$') { return 'yml' }
|
|
144
|
+
return 'json'
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
$ext = if ($PSBoundParameters.ContainsKey('Extension')) { $Extension } else { Get-DefaultExtension $Name }
|
|
148
|
+
$fileName = "$Name.$ext"
|
|
149
|
+
|
|
150
|
+
$configRoot = Join-Path $Workspace '.kushi/config'
|
|
151
|
+
$userPath = Join-Path $configRoot (Join-Path 'user' $fileName)
|
|
152
|
+
$sharedPath = Join-Path $configRoot (Join-Path 'shared' $fileName)
|
|
153
|
+
|
|
154
|
+
$resolved = $null
|
|
155
|
+
if (Test-Path -LiteralPath $userPath -PathType Leaf) { $resolved = $userPath }
|
|
156
|
+
elseif (Test-Path -LiteralPath $sharedPath -PathType Leaf) { $resolved = $sharedPath }
|
|
157
|
+
|
|
158
|
+
if (-not $resolved) {
|
|
159
|
+
throw @"
|
|
160
|
+
Kushi config '$Name' not found. Looked in:
|
|
161
|
+
- $userPath
|
|
162
|
+
- $sharedPath
|
|
163
|
+
Run `npx kushi-agents@latest` to (re)seed config files, then edit
|
|
164
|
+
$userPath with your values.
|
|
165
|
+
"@
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if ($Path) { return $resolved }
|
|
169
|
+
|
|
170
|
+
$raw = Get-Content -LiteralPath $resolved -Raw
|
|
171
|
+
|
|
172
|
+
if (-not $AllowPlaceholders) {
|
|
173
|
+
$sentinelHit = $false
|
|
174
|
+
foreach ($s in $script:Sentinels) {
|
|
175
|
+
if ($raw -like "*$s*") { $sentinelHit = $true; break }
|
|
176
|
+
}
|
|
177
|
+
if ($sentinelHit) {
|
|
178
|
+
throw @"
|
|
179
|
+
Kushi config '$resolved' still has template placeholders (e.g. __FILL_ME_IN__, <auto>, <TENANT_ID>).
|
|
180
|
+
Edit the file with your actual values, or pass -AllowPlaceholders to bypass this check.
|
|
181
|
+
"@
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if ($Raw) { return $raw }
|
|
186
|
+
|
|
187
|
+
$parsed = switch ($ext) {
|
|
188
|
+
'json' {
|
|
189
|
+
$raw | ConvertFrom-Json -Depth 100
|
|
190
|
+
}
|
|
191
|
+
{ $_ -in 'yml','yaml' } {
|
|
192
|
+
if (Get-Module -ListAvailable -Name 'powershell-yaml') {
|
|
193
|
+
Import-Module powershell-yaml -ErrorAction Stop
|
|
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
|
|
198
|
+
}
|
|
199
|
+
}
|
|
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
|
|
@@ -1,35 +1,64 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: bootstrap
|
|
3
|
-
description: "First-time setup for a new project — scaffold folders, lay configs side-by-side, do an initial 30-day pull, build State."
|
|
4
|
-
argument-hint: "Project name (fuzzy-matched under engagement-root); optional initial pull window"
|
|
5
|
-
agent: kushi
|
|
6
|
-
tools: [search, read/readFile, edit, agent, execute/runInTerminal, execute/getTerminalOutput, 'workiq/*']
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## User Input
|
|
10
|
-
|
|
11
|
-
```text
|
|
12
|
-
${input:project:Project name, e.g. HCA}
|
|
13
|
-
${input:window:Optional initial pull window — last N days, since YYYY-MM-DD, or YYYY-MM-DD..YYYY-MM-DD (default 30 days)}
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
# /bootstrap
|
|
17
|
-
|
|
18
|
-
Route to `@Kushi bootstrap <project>`.
|
|
19
|
-
|
|
20
|
-
Inputs the agent will resolve:
|
|
21
|
-
- `<project>` — the engagement folder name (fuzzy-match under engagement-root if needed).
|
|
22
|
-
- `<window>` — defaults to 30 days. Override with `last 60 days`, `since 2026-04-01`, or `2026-04-01..2026-05-01`.
|
|
23
|
-
|
|
24
|
-
Reads:
|
|
25
|
-
- `<workspace>/.kushi/config/project-evidence.yml` for alias + engagement-root.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
---
|
|
2
|
+
name: bootstrap
|
|
3
|
+
description: "First-time setup for a new project — scaffold folders, lay configs side-by-side, do an initial 30-day pull, build State."
|
|
4
|
+
argument-hint: "Project name (fuzzy-matched under engagement-root); optional initial pull window"
|
|
5
|
+
agent: kushi
|
|
6
|
+
tools: [search, read/readFile, edit, agent, execute/runInTerminal, execute/getTerminalOutput, 'workiq/*']
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## User Input
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
${input:project:Project name, e.g. HCA}
|
|
13
|
+
${input:window:Optional initial pull window — last N days, since YYYY-MM-DD, or YYYY-MM-DD..YYYY-MM-DD (default 30 days)}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
# /bootstrap
|
|
17
|
+
|
|
18
|
+
Route to `@Kushi bootstrap <project>`.
|
|
19
|
+
|
|
20
|
+
Inputs the agent will resolve:
|
|
21
|
+
- `<project>` — the engagement folder name (fuzzy-match under engagement-root if needed).
|
|
22
|
+
- `<window>` — defaults to 30 days. Override with `last 60 days`, `since 2026-04-01`, or `2026-04-01..2026-05-01`.
|
|
23
|
+
|
|
24
|
+
Reads:
|
|
25
|
+
- `<workspace>/.kushi/config/user/project-evidence.yml` for alias + engagement-root.
|
|
26
|
+
- `<workspace>/.kushi/config/user/m365-auth.json` for tenant + default notebook + mailbox-folder hints.
|
|
27
|
+
- `<workspace>/.kushi/config/shared/integrations.yml` for ADO/CRM org-level connections (shared per project).
|
|
28
|
+
|
|
29
|
+
**Step 0 — verify per-user config is filled** (the minimum the bootstrap skill needs before it can discover the rest). Before any pull, call:
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
& "<install-dest>/lib/Get-KushiConfig.ps1" -Name 'project-evidence' -AllowPlaceholders | Out-Null # tolerates <auto>; identity-resolution fills it
|
|
33
|
+
& "<install-dest>/lib/Get-KushiConfig.ps1" -Name 'm365-auth' # hard-fails on placeholders in required fields
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`Get-KushiConfig -Name 'm365-auth'` (kushi v4.4.1+) checks both: (a) no `__FILL_ME_IN__` / sentinel strings anywhere, AND (b) the required-field set is populated:
|
|
37
|
+
`defaultTenantId`, `oneNote.defaultNotebookName`, `oneNote.defaultNotebookId`, `oneNote.defaultLinkOwner`, `emailContext.folders[]` (≥ 1 entry), `sharePointContext.localProjectsRoot`.
|
|
38
|
+
|
|
39
|
+
If it throws, STOP and prompt the user with the exact missing-field list:
|
|
40
|
+
|
|
41
|
+
> ⚠ `<workspace>/.kushi/config/user/m365-auth.json` is missing required fields: `<list from the helper>`. Open it, fill in those values, then re-run `bootstrap`. Everything else (section IDs, calendar series, specific mailbox folder discovery, channel IDs, SharePoint site IDs, CRM `crmRecordId`, ADO work-item IDs) is the bootstrap skill's job to **discover via WorkIQ + per-source probes** — do NOT pre-fill those.
|
|
42
|
+
|
|
43
|
+
Continue only when both helper calls succeed (`project-evidence.yml` is allowed to still have `<auto>` for identity; identity-resolution.instructions.md fills it in Step 0 of the bootstrap skill).
|
|
44
|
+
|
|
45
|
+
**What the bootstrap SKILL discovers (you do NOT need to pre-fill any of this):**
|
|
46
|
+
- Identity (`alias`, `email`, `display_name`) — resolved via WorkIQ if `<auto>`.
|
|
47
|
+
- OneNote section identifiers (`one_sectionFileId`, `one_sectionGroupId`, `one_sectionOneNoteGuid`, `one_notebookSourceDoc`) — discovered from the user-provided section name.
|
|
48
|
+
- Calendar series, meeting `joinUrl`s, Teams chat/channel hints, SharePoint site/web/list IDs — discovered per source.
|
|
49
|
+
- CRM account `crmRecordId` — discovered via the 4-step Dataverse REST sequence.
|
|
50
|
+
- ADO area path / iteration / work-item IDs — discovered via ADO REST.
|
|
51
|
+
|
|
52
|
+
On WorkIQ failure during discovery, per `deferred-retry-on-workiq-fail.instructions.md`: the bootstrap skill writes a marker, surfaces it in the run report, and continues. **It does NOT call `m365_get_*` / Graph as a fallback.** The next `refresh` drains the queue.
|
|
53
|
+
|
|
54
|
+
Produces:
|
|
55
|
+
- `<workspace>/.kushi/config/user/{m365-auth,m365-mutable}.json` (per-user, hand-edited above + auto-populated by Step 4a)
|
|
56
|
+
- `<workspace>/.kushi/config/shared/integrations.yml` (shared, ADO/CRM connection blocks; per-project `boundaries:` lives in the project file below)
|
|
57
|
+
- `<engagement-root>/<project>/integrations.yml` (per-project boundaries + enabled-sources, shared via OneDrive)
|
|
58
|
+
- `<engagement-root>/<project>/Evidence/{contributors.yml, run-log.yml, <alias>/.settings.yml, <alias>/{email,teams,meetings,onenote,sharepoint,crm,ado}/{snapshot,stream}/, <alias>/_deferred-retries/}`
|
|
59
|
+
- `<engagement-root>/<project>/State/{00..09}_*.md` (full profile only)
|
|
60
|
+
- `<engagement-root>/<project>/bootstrap-status.md` (shared, multi-user safe)
|
|
61
|
+
|
|
62
|
+
Delegates to `bootstrap-project` skill. After scaffolding, calls each `pull-<source>` skill, then `build-state` (full profile only).
|
|
63
|
+
|
|
64
|
+
Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/runs/{{YYYY-MM-DD}}-<project>-bootstrap.md` as the final step.
|
|
@@ -33,7 +33,7 @@ Skills must always:
|
|
|
33
33
|
What does **not** go in a pack:
|
|
34
34
|
|
|
35
35
|
- Per-engagement data (lives under `<project>/Evidence/`)
|
|
36
|
-
- Per-user identity / configs (lives in `<workspace>/.kushi/config/project-evidence.yml`)
|
|
36
|
+
- Per-user identity / configs (lives in `<workspace>/.kushi/config/user/project-evidence.yml`)
|
|
37
37
|
- Skill behavior (lives in `plugin/skills/<skill>/SKILL.md`)
|
|
38
38
|
- Cross-cutting agent doctrine (lives in `plugin/instructions/*.instructions.md`)
|
|
39
39
|
|
|
@@ -30,14 +30,14 @@ Belongs to the **`preview`** profile. Opt in via `npx kushi-agents --clawpilot -
|
|
|
30
30
|
|
|
31
31
|
## Deterministic config — do not invent paths
|
|
32
32
|
|
|
33
|
-
Same as `propose-ado-update`. Reads ADO connection from `<
|
|
33
|
+
Same as `propose-ado-update`. Reads ADO connection from `<workspace>/.kushi/config/shared/integrations.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
34
|
|
|
35
35
|
## Pre-flight (HARD — do not bypass)
|
|
36
36
|
|
|
37
37
|
1. **Resolve engagement root + project** per `engagement-root-resolution.instructions.md`.
|
|
38
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
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 `<
|
|
40
|
+
4. Per `azure-auth-patterns.instructions.md` — Section 1 (session pre-check) + Section 3 (ADO tenant validation, using `<workspace>/.kushi/config/shared/integrations.yml`) **must** complete green before any further step.
|
|
41
41
|
|
|
42
42
|
## Steps (current preview-stub behavior)
|
|
43
43
|
|
|
@@ -40,7 +40,7 @@ In order, stop on first hit:
|
|
|
40
40
|
1. Exact `<engagement-root>/<project>/Evidence/` folder.
|
|
41
41
|
2. Fuzzy match against `discovery.project_aliases` in any `<engagement-root>/<project>/Evidence/<alias>/.settings.yml`.
|
|
42
42
|
3. `<engagement-root>/<project>/external-context/` (lighter-weight projects without full bootstrap).
|
|
43
|
-
4. `<workspace>/.kushi/config/project-evidence.yml` `active_projects` list.
|
|
43
|
+
4. `<workspace>/.kushi/config/user/project-evidence.yml` `active_projects` list.
|
|
44
44
|
|
|
45
45
|
If zero matches → ask user. If multiple → list candidates and ask user to pick. **Echo the resolved root path before answering** so the user can confirm.
|
|
46
46
|
|
|
@@ -31,6 +31,8 @@ The active profile is read from `kushi-install.json#profile` next to this agent
|
|
|
31
31
|
|
|
32
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
33
|
|
|
34
|
+
> **Multi-contributor safety (kushi v4.4.0+)**: this file is shared via OneDrive. Per `multi-user-shared-files.instructions.md`, every write MUST: (a) absorb sibling conflict copies, (b) preserve other aliases' rows in `## Contributors who have bootstrapped this project`, (c) cite the discovering alias in per-source rows. Same rules apply to `<project>/integrations.yml`, `<project>/OPEN-QUESTIONS-DRAFT.md`, `<project>/Evidence/run-log.yml`, `<project>/Evidence/contributors.yml`.
|
|
35
|
+
|
|
34
36
|
## Inputs
|
|
35
37
|
|
|
36
38
|
- `<project>` — engagement name (fuzzy-matched per `engagement-root-resolution.instructions.md`).
|
|
@@ -41,7 +43,7 @@ After every run (success or coverage-gaps), write `<project>/bootstrap-status.md
|
|
|
41
43
|
|
|
42
44
|
### Step 0 — Identity resolution (REQUIRED, never asks the user)
|
|
43
45
|
|
|
44
|
-
Per `identity-resolution.instructions.md`. Read `<workspace>/.kushi/config/project-evidence.yml`:
|
|
46
|
+
Per `identity-resolution.instructions.md`. Read `<workspace>/.kushi/config/user/project-evidence.yml`:
|
|
45
47
|
|
|
46
48
|
* If `alias`, `email`, or `display_name` is missing / `<auto>` / matches a placeholder → call WorkIQ once:
|
|
47
49
|
```
|
|
@@ -49,7 +51,7 @@ Per `identity-resolution.instructions.md`. Read `<workspace>/.kushi/config/proje
|
|
|
49
51
|
```
|
|
50
52
|
Map `upn → email`, `displayName → display_name`, `mailNickname → alias` (fallback `email.split('@')[0]`).
|
|
51
53
|
* Persist resolved values back to the YAML (preserve comments).
|
|
52
|
-
* Echo one line: `✓ Identity: <displayName> <<UPN>> (alias=<alias>). Edit .kushi/config/project-evidence.yml to override.`
|
|
54
|
+
* Echo one line: `✓ Identity: <displayName> <<UPN>> (alias=<alias>). Edit .kushi/config/user/project-evidence.yml to override.`
|
|
53
55
|
* If all three are already explicit non-placeholder values → skip silently.
|
|
54
56
|
|
|
55
57
|
Hard stop if WorkIQ returns auth error or empty — print the WorkIQ sign-in hint and exit. Never fall back to asking the user.
|
|
@@ -59,13 +61,13 @@ Hard stop if WorkIQ returns auth error or empty — print the WorkIQ sign-in hin
|
|
|
59
61
|
Verify in order. Stop on hard failures.
|
|
60
62
|
|
|
61
63
|
1. **OS + host runtime** — display OS + Node/PowerShell version. Informational.
|
|
62
|
-
2. **WorkIQ install (REQUIRED, hard stop)** — read `<workspace>/.kushi/config/project-evidence.yml workiq.cli_path`. If missing, probe known paths:
|
|
64
|
+
2. **WorkIQ install (REQUIRED, hard stop)** — read `<workspace>/.kushi/config/user/project-evidence.yml workiq.cli_path`. If missing, probe known paths:
|
|
63
65
|
- `$HOME\.kushi\bin\workiq.cmd`
|
|
64
66
|
- `$env:LOCALAPPDATA\Programs\WorkIQ\workiq.cmd`
|
|
65
67
|
- `$env:ProgramFiles\WorkIQ\workiq.cmd`
|
|
66
68
|
If found, persist path. If not found, ask user for path (or to install). Test with `<workiq.cli_path> --help`. Without WorkIQ, M365 sources will all fail — STOP.
|
|
67
|
-
3. **Conditional az login** — only if `<
|
|
68
|
-
4. **Engagement-root resolution** — per `engagement-root-resolution.instructions.md`. Persist to `<workspace>/.kushi/config/project-evidence.yml engagement_root` if newly resolved.
|
|
69
|
+
3. **Conditional az login** — only if `<workspace>/.kushi/config/shared/integrations.yml` OR `<workspace>/.kushi/config/shared/integrations.yml` exists. Per `az-auth-conditional.instructions.md`. Soft warning on failure, never blocking.
|
|
70
|
+
4. **Engagement-root resolution** — per `engagement-root-resolution.instructions.md`. Persist to `<workspace>/.kushi/config/user/project-evidence.yml engagement_root` if newly resolved.
|
|
69
71
|
|
|
70
72
|
Display SETUP summary table with ✅ / ⚙️ / ❌ / ⚠️ / ➖ markers.
|
|
71
73
|
|
|
@@ -77,20 +79,20 @@ Required live files:
|
|
|
77
79
|
|
|
78
80
|
| Live file | Template source |
|
|
79
81
|
|---|---|
|
|
80
|
-
| `<workspace>/.kushi/config/project-evidence.yml` | `templates/init/project-evidence.template.yml` (seeded by installer) |
|
|
81
|
-
| `<workspace>/.kushi/config/integrations.yml` | `templates/init/integrations.template.yml` (seeded by installer) |
|
|
82
|
-
| `<
|
|
83
|
-
| `<
|
|
82
|
+
| `<workspace>/.kushi/config/user/project-evidence.yml` | `templates/init/project-evidence.template.yml` (seeded by installer) |
|
|
83
|
+
| `<workspace>/.kushi/config/shared/integrations.yml` | `templates/init/integrations.template.yml` (seeded by installer) |
|
|
84
|
+
| `<workspace>/.kushi/config/user/m365-auth.json` | `templates/init/m365-auth.template.json` |
|
|
85
|
+
| `<workspace>/.kushi/config/user/m365-mutable.json` | `templates/init/m365-mutable.template.json` |
|
|
84
86
|
| `<engagement-root>/<project>/integrations.yml` | `templates/init/project-integrations.template.yml` |
|
|
85
87
|
| `<engagement-root>/<project>/Evidence/contributors.yml` | `templates/init/project-contributors.template.yml` |
|
|
86
88
|
| `<engagement-root>/<project>/Evidence/<alias>/.settings.yml` | `templates/init/project-user-settings.template.yml` |
|
|
87
89
|
|
|
88
|
-
Optional (only if user enables CRM/ADO):
|
|
90
|
+
Optional (only if user enables CRM/ADO — both go into `<workspace>/.kushi/config/shared/integrations.yml` `crm:` and `ado:` blocks, NOT separate files):
|
|
89
91
|
|
|
90
|
-
| Live
|
|
92
|
+
| Live destination | Source |
|
|
91
93
|
|---|---|
|
|
92
|
-
| `<
|
|
93
|
-
| `<
|
|
94
|
+
| `<workspace>/.kushi/config/shared/integrations.yml` `crm:` block | already seeded by `templates/init/integrations.template.yml` — fill in `crm.environmentUrl` + `crm.tenantId` |
|
|
95
|
+
| `<workspace>/.kushi/config/shared/integrations.yml` `ado:` block | already seeded by `templates/init/integrations.template.yml` — fill in `ado.organization` + `ado.project` |
|
|
94
96
|
|
|
95
97
|
**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.
|
|
96
98
|
|
|
@@ -119,15 +121,15 @@ The `State/` subtree is created **only on `full` profile**. On `standard`, only
|
|
|
119
121
|
|
|
120
122
|
**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.
|
|
121
123
|
|
|
122
|
-
For CRM and ADO additionally verify the
|
|
124
|
+
For CRM and ADO additionally verify the shared connection block exists in `<workspace>/.kushi/config/shared/integrations.yml` (`crm:` block with `environmentUrl` + `tenantId`, OR `ado:` block with `organization` + `project`) with non-placeholder values; if missing, prompt the user to fill those two/four fields directly (no separate template files — they live in `templates/init/integrations.template.yml`) and park in Open Questions with the path. **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.
|
|
123
125
|
|
|
124
|
-
**CRM discovery is REQUIRED before declaring `disabled` (kushi v3.11.0+, per `crm-bootstrap-discovery.instructions.md`).** If `<
|
|
126
|
+
**CRM discovery is REQUIRED before declaring `disabled` (kushi v3.11.0+, per `crm-bootstrap-discovery.instructions.md`).** If `<workspace>/.kushi/config/shared/integrations.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.
|
|
125
127
|
|
|
126
128
|
#### Step 4a — Discovery & registry persistence (REQUIRED, kushi v3.7.8+, per `m365-id-registry.instructions.md`)
|
|
127
129
|
|
|
128
130
|
**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.
|
|
129
131
|
|
|
130
|
-
For each enabled source, resolve and persist the canonical lookup keys into `<
|
|
132
|
+
For each enabled source, resolve and persist the canonical lookup keys into `<workspace>/.kushi/config/user/m365-mutable.json#knownSections.<projectKey>`. The schema is fixed — populate every key the source supports:
|
|
131
133
|
|
|
132
134
|
```jsonc
|
|
133
135
|
"knownSections": {
|
|
@@ -138,7 +138,7 @@ Present this verbatim:
|
|
|
138
138
|
|
|
139
139
|
Before opening, check whether any project is already bootstrapped:
|
|
140
140
|
|
|
141
|
-
1. Read `<workspace>/.kushi/config/project-evidence.yml` (personal config). If `active_projects` has entries, pick the most recent as the demo target — substitute that name into `{{active_project}}` placeholders below.
|
|
141
|
+
1. Read `<workspace>/.kushi/config/user/project-evidence.yml` (personal config). If `active_projects` has entries, pick the most recent as the demo target — substitute that name into `{{active_project}}` placeholders below.
|
|
142
142
|
2. If none, propose a fictional project named **Contoso Discovery** and tell the user that Try-it prompts will use that name; they can substitute their own at any time.
|
|
143
143
|
|
|
144
144
|
### Navigation Keywords
|
|
@@ -444,6 +444,6 @@ Reply `next` to see the closing cheat sheet, or `done` to exit.
|
|
|
444
444
|
- Rule 1.2: Mode selection must always present BOTH options — never auto-route to one mode.
|
|
445
445
|
- Rule 1.3: In walkthrough mode, each moment must wait for `next` / `skip` / `done` / `try` before advancing — never auto-advance.
|
|
446
446
|
- Rule 1.4: `done` must work at every moment — never trap the user.
|
|
447
|
-
- Rule 1.5: Try-it prompts must use the active project name from `<workspace>/.kushi/config/project-evidence.yml`, OR the placeholder `Contoso Discovery` if no projects are configured. Never invent a real-sounding project name.
|
|
447
|
+
- Rule 1.5: Try-it prompts must use the active project name from `<workspace>/.kushi/config/user/project-evidence.yml`, OR the placeholder `Contoso Discovery` if no projects are configured. Never invent a real-sounding project name.
|
|
448
448
|
- Rule 1.6: Skill descriptions in this file must match `kushi.agent.md` and the live `SKILL.md` files — `self-check` D-checks catch drift.
|
|
449
449
|
- Rule 1.7: Demo moments must reflect the actual verb count in `kushi.agent.md`. If a verb is added or removed, this file must be updated in the same commit (`self-check` warns on drift).
|