kushi-agents 4.3.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -4
- package/plugin/agents/kushi.agent.md +2 -2
- package/plugin/instructions/azure-auth-patterns.instructions.md +2 -2
- package/plugin/instructions/bootstrap-status-format.instructions.md +24 -0
- package/plugin/instructions/engagement-root-resolution.instructions.md +3 -3
- package/plugin/instructions/identity-resolution.instructions.md +4 -4
- package/plugin/instructions/multi-user-shared-files.instructions.md +87 -0
- package/plugin/instructions/run-reports.instructions.md +1 -1
- 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 +2 -2
- package/plugin/lib/Get-KushiConfig.ps1 +109 -0
- package/plugin/prompts/bootstrap.prompt.md +15 -1
- package/plugin/reference-packs/README.md +1 -1
- package/plugin/skills/ask-project/SKILL.md +1 -1
- package/plugin/skills/bootstrap-project/SKILL.md +8 -6
- package/plugin/skills/intro/SKILL.md +2 -2
- package/plugin/skills/propose-ado-update/SKILL.md +1 -1
- package/plugin/templates/init/azuredevops.template.json +159 -0
- package/plugin/templates/init/dynamics365.template.json +412 -0
- package/{.github/config/m365-mutable.json.example → plugin/templates/init/m365-mutable.example.json} +1 -1
- package/plugin/templates/init/rsi-program-catalog.template.json +107 -0
- package/src/config-loader.mjs +69 -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/{.github/config/m365-auth.json.example → plugin/templates/init/m365-auth.example.json} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kushi-agents",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "Install Kushi — multi-source project evidence agent with snapshot+stream capture across Email, Teams, OneNote, SharePoint, Meetings, CRM, ADO. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,8 +10,6 @@
|
|
|
10
10
|
"bin/",
|
|
11
11
|
"src/",
|
|
12
12
|
"plugin/",
|
|
13
|
-
".github/config/m365-auth.json.example",
|
|
14
|
-
".github/config/m365-mutable.json.example",
|
|
15
13
|
".github/copilot-instructions.kushi.md"
|
|
16
14
|
],
|
|
17
15
|
"engines": {
|
|
@@ -43,7 +41,7 @@
|
|
|
43
41
|
},
|
|
44
42
|
"license": "MIT",
|
|
45
43
|
"scripts": {
|
|
46
|
-
"test": "node --test src/check-workiq.test.mjs",
|
|
44
|
+
"test": "node --test src/check-workiq.test.mjs src/seed-config.test.mjs",
|
|
47
45
|
"smoke": "node scripts/smoke.mjs",
|
|
48
46
|
"prepublishOnly": "npm test && npm run smoke"
|
|
49
47
|
},
|
|
@@ -98,8 +98,8 @@ When a user message arrives:
|
|
|
98
98
|
## Configuration layout
|
|
99
99
|
|
|
100
100
|
```
|
|
101
|
-
<workspace>/.kushi/config/project-evidence.yml ← personal: alias, engagement_root, active_projects (seeded by installer; never overwritten)
|
|
102
|
-
<workspace>/.kushi/config/integrations.yml ← optional global CRM/ADO defaults (seeded by installer; never overwritten)
|
|
101
|
+
<workspace>/.kushi/config/user/project-evidence.yml ← personal: alias, engagement_root, active_projects (seeded by installer; never overwritten)
|
|
102
|
+
<workspace>/.kushi/config/shared/integrations.yml ← optional global CRM/ADO defaults (seeded by installer; never overwritten)
|
|
103
103
|
<engagement-root>/.project-evidence/ ← per-machine, per-user M365 + CRM + ADO config (OneDrive-synced)
|
|
104
104
|
m365/m365-auth.json
|
|
105
105
|
m365/m365-mutable.json
|
|
@@ -227,7 +227,7 @@ Maintained alongside `auth-and-retry §3` (canonical) — quick lookup:
|
|
|
227
227
|
| Dynamics 365 / CRM | `<engagement-root>/.project-evidence/crm/config.yml` |
|
|
228
228
|
| Azure DevOps | `<engagement-root>/.project-evidence/ado/config.yml` |
|
|
229
229
|
| Microsoft Graph / M365 / OneNote | `<engagement-root>/.project-evidence/m365/m365-mutable.json` + `<engagement-root>/.project-evidence/m365/m365-auth.json` |
|
|
230
|
-
| WorkIQ CLI path | `<workspace>/.kushi/config/project-evidence.yml` (workspace-scoped) |
|
|
231
|
-
| Global integrations (optional) | `<workspace>/.kushi/config/integrations.yml` |
|
|
230
|
+
| WorkIQ CLI path | `<workspace>/.kushi/config/user/project-evidence.yml` (workspace-scoped) |
|
|
231
|
+
| Global integrations (optional) | `<workspace>/.kushi/config/shared/integrations.yml` |
|
|
232
232
|
|
|
233
233
|
Always read tenant IDs, resource URLs, org URLs, and allowed-tenant lists from these files at the start of each run. **Never hardcode them in skills or prompts.** The only acceptable literal in instructions/prompts is the public Microsoft tenant ID `72f988bf-86f1-41af-91ab-2d7cd011db47` in the user-facing `az login --tenant ...` suggestion text.
|
|
@@ -79,6 +79,30 @@ Use these exact strings everywhere (table cells, run-log, narrative):
|
|
|
79
79
|
- `ado-not-complete` — engagement record not found yet OR ADO linkage missing
|
|
80
80
|
- `completed-with-coverage-gaps` — final outcome with explicit gaps recorded
|
|
81
81
|
|
|
82
|
+
## Multi-contributor safety (kushi v4.4.0+)
|
|
83
|
+
|
|
84
|
+
`<project>/bootstrap-status.md` is shared across all contributors via OneDrive. Per `multi-user-shared-files.instructions.md`:
|
|
85
|
+
|
|
86
|
+
1. **Before writing**, scan `<project>/` for sibling conflict copies (e.g. `bootstrap-status-conflict-<alias>-<host>.md` or OneDrive's `bootstrap-status (Stan's conflicted copy *)`). If any exist, merge their content into the canonical file (taking the most recent per-source row) and delete the conflict copies. Log this in the per-user bootstrap report under `## Conflict copies merged`.
|
|
87
|
+
2. **Preserve other contributors' attribution.** Read the existing file; the `## Contributors who have bootstrapped this project` section MUST keep one row per alias that has ever written it. Update only the row matching the current alias.
|
|
88
|
+
3. **Per-source rows** in `## Context Artifact Status` reflect the most recent discovery across all contributors. Add a trailing `Discovered by` column showing which alias performed the latest discovery (cross-referenced from each alias's `m365-mutable.json` via `Get-KushiConfig`).
|
|
89
|
+
4. **The final one-line status** is for the most recent run only and may be overwritten by any contributor.
|
|
90
|
+
|
|
91
|
+
### Required `## Contributors who have bootstrapped this project` section
|
|
92
|
+
|
|
93
|
+
Append this section immediately after `## Bootstrap Status`:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
## Contributors who have bootstrapped this project
|
|
97
|
+
|
|
98
|
+
| Alias | Display Name | Last Run | Mode | Outcome |
|
|
99
|
+
|---|---|---|---|---|
|
|
100
|
+
| ushak | Usha Kandregula | 2026-05-20 07:42 EDT | bootstrap | bootstrap-complete-with-coverage-gaps |
|
|
101
|
+
| stand | Stan Doe | 2026-05-18 16:01 EDT | refresh | refresh-complete |
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Preserve every existing row except the one matching your alias.
|
|
105
|
+
|
|
82
106
|
## Sections to AVOID in bootstrap-status
|
|
83
107
|
|
|
84
108
|
Do NOT keep these in `bootstrap-status.md` (they belong elsewhere or become stale):
|
|
@@ -11,9 +11,9 @@ The **engagement-root** is the parent folder that contains all of the user's eng
|
|
|
11
11
|
|
|
12
12
|
Resolve `<engagement-root>` in this order — first match wins:
|
|
13
13
|
|
|
14
|
-
1. **`<workspace>/.kushi/config/project-evidence.yml`** — read `engagement_root:` field (preferred).
|
|
14
|
+
1. **`<workspace>/.kushi/config/user/project-evidence.yml`** — read `engagement_root:` field (preferred).
|
|
15
15
|
2. **`customer_workspace/FDEDocs/`** — if the user's workspace has this symlink, follow it. Common in FDE-style installs.
|
|
16
|
-
3. **Ask the user** once and persist the answer to `<workspace>/.kushi/config/project-evidence.yml engagement_root`.
|
|
16
|
+
3. **Ask the user** once and persist the answer to `<workspace>/.kushi/config/user/project-evidence.yml engagement_root`.
|
|
17
17
|
|
|
18
18
|
## Live config location
|
|
19
19
|
|
|
@@ -43,7 +43,7 @@ Once `<engagement-root>` is known, individual projects are subfolders:
|
|
|
43
43
|
Project name resolution (always fuzzy):
|
|
44
44
|
|
|
45
45
|
1. Match against keys in `<engagement-root>/.project-evidence/m365/m365-mutable.json m365Mutable.knownSections`.
|
|
46
|
-
2. Match against `active_projects:` in `<workspace>/.kushi/config/project-evidence.yml`.
|
|
46
|
+
2. Match against `active_projects:` in `<workspace>/.kushi/config/user/project-evidence.yml`.
|
|
47
47
|
3. Match against actual subfolder names under `<engagement-root>`.
|
|
48
48
|
|
|
49
49
|
Case-insensitive; ranking `exact > prefix > contains`. Multiple plausible candidates → ask user to pick. Zero candidates AND verb is `bootstrap` → create the folder. Zero candidates AND verb is anything else → ask user.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
applyTo: "**"
|
|
3
|
-
description: "Identity auto-resolution — Kushi never asks the user for alias / email / display_name. On the first bootstrap (or whenever those fields are <auto> / placeholder in .kushi/config/project-evidence.yml), Kushi resolves them from WorkIQ in a single call, persists them, and continues. Skipped entirely if the user has set explicit values."
|
|
3
|
+
description: "Identity auto-resolution — Kushi never asks the user for alias / email / display_name. On the first bootstrap (or whenever those fields are <auto> / placeholder in .kushi/config/user/project-evidence.yml), Kushi resolves them from WorkIQ in a single call, persists them, and continues. Skipped entirely if the user has set explicit values."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Identity Resolution — Don't Ask, Probe
|
|
@@ -9,7 +9,7 @@ Kushi must not prompt the user for `alias`, `email`, or `display_name`. These ar
|
|
|
9
9
|
|
|
10
10
|
## When to resolve
|
|
11
11
|
|
|
12
|
-
On the **first step of every prompt** that reads contributor identity (bootstrap, refresh, aggregate, ask, fde-*, propose-ado, apply-ado), check `<workspace>/.kushi/config/project-evidence.yml`:
|
|
12
|
+
On the **first step of every prompt** that reads contributor identity (bootstrap, refresh, aggregate, ask, fde-*, propose-ado, apply-ado), check `<workspace>/.kushi/config/user/project-evidence.yml`:
|
|
13
13
|
|
|
14
14
|
* If `alias`, `email`, or `display_name` is **missing**, set to `<auto>`, or matches a placeholder pattern (`<your-alias>`, `<Your Full Name>`, `your.email@example.com`) → **resolve from WorkIQ**.
|
|
15
15
|
* If all three are explicit non-placeholder values → **skip**. Respect the user's override.
|
|
@@ -32,9 +32,9 @@ Map the response:
|
|
|
32
32
|
|
|
33
33
|
## After resolution
|
|
34
34
|
|
|
35
|
-
1. **Persist back** to `<workspace>/.kushi/config/project-evidence.yml` (preserving comments + indentation). The user sees the resolved values on next open; no surprise.
|
|
35
|
+
1. **Persist back** to `<workspace>/.kushi/config/user/project-evidence.yml` (preserving comments + indentation). The user sees the resolved values on next open; no surprise.
|
|
36
36
|
2. **Echo back** to the user, one line:
|
|
37
|
-
> ✓ Identity: `Alex Smith <alex@microsoft.com>` (alias=`alex`). Edit `.kushi/config/project-evidence.yml` to override.
|
|
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
40
|
## Failure modes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/SKILL.md,**/*.prompt.md,**/Evidence/run-log.yml,**/integrations.yml,**/bootstrap-status.md,**/OPEN-QUESTIONS-DRAFT.md,**/State/09_open-questions.md,**/Evidence/contributors.yml"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Multi-user shared-file safety
|
|
6
|
+
|
|
7
|
+
## Why this exists
|
|
8
|
+
|
|
9
|
+
A Kushi engagement folder (`<engagement-root>/<project>/`) is shared across all contributors via OneDrive. Several artifacts inside it are **logically shared** — every contributor reads and writes the same path:
|
|
10
|
+
|
|
11
|
+
| Shared artifact | Path | Writers |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| Per-project integrations | `<project>/integrations.yml` | `bootstrap-project`, `propose-ado-update`, `apply-ado-update`, every `pull-*` that discovers an ID |
|
|
14
|
+
| Bootstrap status snapshot | `<project>/bootstrap-status.md` | `bootstrap-project` (every run, any contributor) |
|
|
15
|
+
| Open questions draft | `<project>/OPEN-QUESTIONS-DRAFT.md` (or `State/09_open-questions.md` on full profile) | `bootstrap-project`, `consolidate-evidence`, `build-state`, `propose-ado-update` |
|
|
16
|
+
| Run log | `<project>/Evidence/run-log.yml` | every `pull-*`, `bootstrap-project`, `refresh-project`, `fde-*` |
|
|
17
|
+
| Contributors list | `<project>/Evidence/contributors.yml` | every `pull-*` (first time an alias touches the project) |
|
|
18
|
+
|
|
19
|
+
Without rules, two contributors running concurrently produce one of:
|
|
20
|
+
- OneDrive conflict-copy (`*-conflict-<alias>-<host>.yml`) — silent loss until manually merged.
|
|
21
|
+
- Last-writer-wins overwrite — silent loss of the other contributor's data.
|
|
22
|
+
|
|
23
|
+
This doctrine codifies the contract every writer must honor. It is **not** a substitute for proper locking, but it makes concurrent runs eventually consistent and recoverable.
|
|
24
|
+
|
|
25
|
+
## Universal rules (apply to every shared artifact)
|
|
26
|
+
|
|
27
|
+
1. **Read-modify-write, never blind-write.** Before writing any shared artifact, the skill MUST read the current file, merge its new contribution, and write the merged result. Blind overwrite is forbidden.
|
|
28
|
+
2. **Detect and absorb conflict-copies.** Before reading the canonical file, glob for sibling files matching `<basename>-conflict-*` or `<basename> (<host>'s conflicted copy *)`. If any exist, merge their contents into the canonical file, then delete the conflict copies. Log the merge in the run report.
|
|
29
|
+
3. **Stamp every contribution.** Every line / block / list-entry that a skill adds must carry its alias (from `project-evidence.yml`) and an ISO timestamp so future readers (and the merge logic above) can deterministically reconcile.
|
|
30
|
+
4. **Idempotent appends.** Re-running the same skill in the same window MUST NOT duplicate prior entries. Use a `(alias, source, window_key)` tuple as the dedupe key.
|
|
31
|
+
5. **Never delete another contributor's contribution.** A skill may only modify or remove entries it created (matched by alias). Cleanup of other aliases' entries is reserved for `consolidate-evidence`.
|
|
32
|
+
|
|
33
|
+
## Per-artifact contracts
|
|
34
|
+
|
|
35
|
+
### `<project>/integrations.yml`
|
|
36
|
+
|
|
37
|
+
- **Pattern**: read-modify-write with alias stamp on changed fields.
|
|
38
|
+
- Whenever a skill discovers a new ID (CRM `record_id`, ADO `engagement_id`, OneNote `section_file_id`, etc.), it MUST:
|
|
39
|
+
1. Read the current file.
|
|
40
|
+
2. If the target field is non-empty AND differs from the discovered value, write the discovered value into a sibling key `<field>_proposed_<alias>` and add a Q-row to `OPEN-QUESTIONS-DRAFT.md` for human reconciliation. Do not overwrite.
|
|
41
|
+
3. If the target field is empty (or matches), write the value and append a comment line: `# resolved by <alias> on <YYYY-MM-DD>` immediately above the changed key.
|
|
42
|
+
- The `last_discovery_attempt` / `last_discovery_result` keys MAY be overwritten by any alias (they are intentionally last-writer-wins; the value is "the most recent attempt by anyone").
|
|
43
|
+
|
|
44
|
+
### `<project>/bootstrap-status.md`
|
|
45
|
+
|
|
46
|
+
- **Pattern**: full rewrite is permitted, but the file MUST carry a `## Contributors who have bootstrapped this project` section listing every alias that has ever written it, with their last-run timestamp.
|
|
47
|
+
- Before rewriting, the skill MUST read the existing Contributors section and preserve every entry whose alias differs from the current alias. Update only its own alias row.
|
|
48
|
+
- The per-source status tables (`OneNote`, `Email`, `Teams`, etc.) reflect the **most recent** discovery across all contributors. Skills MUST cross-reference `m365-mutable.json` (which is per-user) — when a row shows discovered IDs, also note which alias performed the discovery in a trailing `(by <alias>)` cell.
|
|
49
|
+
|
|
50
|
+
### `<project>/OPEN-QUESTIONS-DRAFT.md` and `<project>/State/09_open-questions.md`
|
|
51
|
+
|
|
52
|
+
- **Pattern**: append-only with dedup.
|
|
53
|
+
- Every question row carries `[asked by <alias> on <YYYY-MM-DD>]` as the trailing column.
|
|
54
|
+
- Before appending a new question, the skill MUST scan existing rows for a question whose normalized text (lowercased, whitespace-collapsed) matches. If a match exists, do not append a duplicate; instead, append `, <alias> on <date>` to the existing row's attribution.
|
|
55
|
+
- Rows are removed only by an explicit `resolve-open-question` action (out of scope here) — never by another `bootstrap` / `refresh` run.
|
|
56
|
+
|
|
57
|
+
### `<project>/Evidence/run-log.yml`
|
|
58
|
+
|
|
59
|
+
- **Pattern**: structured append + max() merge.
|
|
60
|
+
- Run history (`runs:` list) is append-only. Every entry carries `alias:` and `run_at:`.
|
|
61
|
+
- Per-source watermarks (`sources.<source>.watermark`) use **max()** merge: when writing, the skill reads the current value and writes `max(current, new)`. Never overwrite with an older watermark.
|
|
62
|
+
- Per-source errors (`sources.<source>.errors[]`) are append-only with `alias` + `at` on every entry; dedup on `(alias, code, at)`.
|
|
63
|
+
|
|
64
|
+
### `<project>/Evidence/contributors.yml`
|
|
65
|
+
|
|
66
|
+
- **Pattern**: append-only, alias-keyed.
|
|
67
|
+
- The first time an alias runs against the project, append `{ alias, display_name, email, first_seen: <YYYY-MM-DD> }`. Subsequent runs MUST NOT modify the entry.
|
|
68
|
+
- `last_seen` MAY be updated by any run, max()-merged.
|
|
69
|
+
|
|
70
|
+
## Implementation guidance for skill authors
|
|
71
|
+
|
|
72
|
+
- Read `<workspace>/.kushi/config/user/project-evidence.yml` to get your alias via `Get-KushiConfig -Name 'project-evidence'`. Never hardcode aliases.
|
|
73
|
+
- For YAML merges, use `Get-Content -Raw | ConvertFrom-Yaml`, mutate, then `ConvertTo-Yaml`. Preserve comments where possible by line-based merging when structure permits.
|
|
74
|
+
- For Markdown table merges in `OPEN-QUESTIONS-DRAFT.md`, parse the body to a list of rows, dedup by normalized question text, re-emit.
|
|
75
|
+
- On any merge conflict the skill cannot resolve deterministically, write the alternative as a sibling-key `<field>_proposed_<alias>` (for YAML) or a `> Disagreement: <alias-A> says ..., <alias-B> says ...` callout (for Markdown) and add a Q-row to `OPEN-QUESTIONS-DRAFT.md`.
|
|
76
|
+
|
|
77
|
+
## Out of scope
|
|
78
|
+
|
|
79
|
+
- True file locking (filesystem advisory locks, OneDrive's checkout API) — relies on platform support Kushi can't assume.
|
|
80
|
+
- Server-side merge service — Kushi is local-only by design.
|
|
81
|
+
|
|
82
|
+
## Related doctrine
|
|
83
|
+
|
|
84
|
+
- `evidence-layout-canonical.instructions.md` — what lives where under `Evidence/`.
|
|
85
|
+
- `run-reports.instructions.md` — per-user run narrative (always under `Evidence/<alias>/`, no concurrency risk).
|
|
86
|
+
- `bootstrap-status-format.instructions.md` — format contract for the shared status artifact.
|
|
87
|
+
- `citation-ledger.instructions.md` — every assertion in shared artifacts must carry a citation; alias attribution is the citation for shared-file entries.
|
|
@@ -24,7 +24,7 @@ Critical for multi-user projects: each contributor's runs are independent, and e
|
|
|
24
24
|
YYYY-MM-DD-HHmm_<mode>.md
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
- `<alias>` — the contributor running the skill (from `<workspace>/.kushi/config/project-evidence.yml#alias`).
|
|
27
|
+
- `<alias>` — the contributor running the skill (from `<workspace>/.kushi/config/user/project-evidence.yml#alias`).
|
|
28
28
|
- `<mode>` — one of `bootstrap`, `refresh`, `force-refresh`, `consolidate`.
|
|
29
29
|
- Timestamp uses the **start time** of the run, in local time, format `YYYY-MM-DD-HHmm` (no seconds, no timezone — local-time prefix is enough for chronological sort).
|
|
30
30
|
|
|
@@ -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
|
|
|
@@ -48,7 +48,7 @@ For every M365 source in scope:
|
|
|
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
|
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
function Get-DefaultExtension([string] $name) {
|
|
57
|
+
if ($name -match '^(project-evidence|integrations)$') { return 'yml' }
|
|
58
|
+
return 'json'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
$ext = if ($PSBoundParameters.ContainsKey('Extension')) { $Extension } else { Get-DefaultExtension $Name }
|
|
62
|
+
$fileName = "$Name.$ext"
|
|
63
|
+
|
|
64
|
+
$configRoot = Join-Path $Workspace '.kushi/config'
|
|
65
|
+
$userPath = Join-Path $configRoot (Join-Path 'user' $fileName)
|
|
66
|
+
$sharedPath = Join-Path $configRoot (Join-Path 'shared' $fileName)
|
|
67
|
+
|
|
68
|
+
$resolved = $null
|
|
69
|
+
if (Test-Path -LiteralPath $userPath -PathType Leaf) { $resolved = $userPath }
|
|
70
|
+
elseif (Test-Path -LiteralPath $sharedPath -PathType Leaf) { $resolved = $sharedPath }
|
|
71
|
+
|
|
72
|
+
if (-not $resolved) {
|
|
73
|
+
throw @"
|
|
74
|
+
Kushi config '$Name' not found. Looked in:
|
|
75
|
+
- $userPath
|
|
76
|
+
- $sharedPath
|
|
77
|
+
Run `npx kushi-agents@latest` to (re)seed config files, then edit
|
|
78
|
+
$userPath with your values.
|
|
79
|
+
"@
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if ($Path) { return $resolved }
|
|
83
|
+
|
|
84
|
+
$raw = Get-Content -LiteralPath $resolved -Raw
|
|
85
|
+
|
|
86
|
+
if (-not $AllowPlaceholders) {
|
|
87
|
+
if ($raw -match '__FILL_ME_IN__' -or $raw -match '<auto>') {
|
|
88
|
+
throw @"
|
|
89
|
+
Kushi config '$resolved' still has template placeholders (__FILL_ME_IN__ or <auto>).
|
|
90
|
+
Edit the file with your actual values, or pass -AllowPlaceholders to bypass this check.
|
|
91
|
+
"@
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if ($Raw) { return $raw }
|
|
96
|
+
|
|
97
|
+
switch ($ext) {
|
|
98
|
+
'json' {
|
|
99
|
+
return ($raw | ConvertFrom-Json -Depth 100)
|
|
100
|
+
}
|
|
101
|
+
{ $_ -in 'yml','yaml' } {
|
|
102
|
+
if (Get-Module -ListAvailable -Name 'powershell-yaml') {
|
|
103
|
+
Import-Module powershell-yaml -ErrorAction Stop
|
|
104
|
+
return ConvertFrom-Yaml -Yaml $raw
|
|
105
|
+
}
|
|
106
|
+
Write-Warning "powershell-yaml not installed; returning raw YAML text. Install with: Install-Module powershell-yaml -Scope CurrentUser"
|
|
107
|
+
return $raw
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -22,7 +22,21 @@ Inputs the agent will resolve:
|
|
|
22
22
|
- `<window>` — defaults to 30 days. Override with `last 60 days`, `since 2026-04-01`, or `2026-04-01..2026-05-01`.
|
|
23
23
|
|
|
24
24
|
Reads:
|
|
25
|
-
- `<workspace>/.kushi/config/project-evidence.yml` for alias + engagement-root.
|
|
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
|
+
|
|
28
|
+
**Step 0 — verify per-user config is filled.** Before any pull, call:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
& "<install-dest>/lib/Get-KushiConfig.ps1" -Name 'project-evidence' -AllowPlaceholders | Out-Null # tolerates <auto>; identity-resolution fills it
|
|
32
|
+
& "<install-dest>/lib/Get-KushiConfig.ps1" -Name 'm365-auth' # hard-fails on placeholders
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If `Get-KushiConfig -Name 'm365-auth'` throws (file missing or still `__FILL_ME_IN__`), STOP and prompt the user:
|
|
36
|
+
|
|
37
|
+
> ⚠ `<workspace>/.kushi/config/user/m365-auth.json` still has template placeholders. Open it and fill in your tenant ID, default OneNote notebook ID, mailbox folder names, and SharePoint root before re-running `bootstrap`.
|
|
38
|
+
|
|
39
|
+
Continue only when both helper calls succeed.
|
|
26
40
|
|
|
27
41
|
Produces:
|
|
28
42
|
- `<engagement-root>/.project-evidence/m365/{m365-auth,m365-mutable}.json` (per-user filled)
|
|
@@ -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
|
|
|
@@ -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
69
|
3. **Conditional az login** — only if `<engagement-root>/.project-evidence/crm/config.yml` OR `<engagement-root>/.project-evidence/ado/config.yml` exists. Per `az-auth-conditional.instructions.md`. Soft warning on failure, never blocking.
|
|
68
|
-
4. **Engagement-root resolution** — per `engagement-root-resolution.instructions.md`. Persist to `<workspace>/.kushi/config/project-evidence.yml engagement_root` if newly resolved.
|
|
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,8 +79,8 @@ 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
|
+
| `<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) |
|
|
82
84
|
| `<engagement-root>/.project-evidence/m365/m365-auth.json` | `templates/init/m365-auth.template.json` |
|
|
83
85
|
| `<engagement-root>/.project-evidence/m365/m365-mutable.json` | `templates/init/m365-mutable.template.json` |
|
|
84
86
|
| `<engagement-root>/<project>/integrations.yml` | `templates/init/project-integrations.template.yml` |
|
|
@@ -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).
|
|
@@ -27,7 +27,7 @@ This skill does **NOT** create a new top-level config file. It reads from the co
|
|
|
27
27
|
|
|
28
28
|
**Resolution is fully deterministic** — never ask the user for paths the bootstrap layer already resolved:
|
|
29
29
|
|
|
30
|
-
1. `<engagement-root>` ← `<workspace>/.kushi/config/project-evidence.yml engagement_root` (per `engagement-root-resolution.instructions.md`).
|
|
30
|
+
1. `<engagement-root>` ← `<workspace>/.kushi/config/user/project-evidence.yml engagement_root` (per `engagement-root-resolution.instructions.md`).
|
|
31
31
|
2. `<project>` folder ← fuzzy-match per `engagement-root-resolution.instructions.md` (knownSections → active_projects → subfolders).
|
|
32
32
|
3. `<project>/integrations.yml ado.engagement_id` — REQUIRED. If `0` or missing → see "Prerequisites" below; never invent an ID.
|
|
33
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`.
|