kushi-agents 5.2.0 → 5.3.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/README.md +24 -0
- package/bin/cli.mjs +50 -1
- package/package.json +2 -2
- package/plugin/agents/kushi.agent.md +2 -0
- package/plugin/instructions/global-wiki.instructions.md +79 -0
- package/plugin/instructions/multi-wiki-routing.instructions.md +117 -0
- package/plugin/skills/ask-project/SKILL.md +14 -0
- package/plugin/skills/global-wiki/.created-by-skill-creator +1 -0
- package/plugin/skills/global-wiki/SKILL.md +87 -0
- package/plugin/skills/global-wiki/evals/evals.json +43 -0
- package/plugin/skills/promote/.created-by-skill-creator +1 -0
- package/plugin/skills/promote/SKILL.md +125 -0
- package/plugin/skills/promote/evals/evals.json +35 -0
- package/plugin/skills/self-check/SKILL.md +4 -1
- package/plugin/skills/self-check/run.ps1 +63 -0
- package/plugin/skills/teach/SKILL.md +2 -0
- package/plugin/skills/teach/evals/evals.json +22 -0
- package/src/global-wiki-cli.mjs +158 -0
- package/src/global-wiki.mjs +503 -0
- package/src/global-wiki.test.mjs +135 -0
- package/src/promote.test.mjs +161 -0
package/README.md
CHANGED
|
@@ -154,6 +154,30 @@ Rules stored in `Evidence/<alias>/State/CLAUDE.md`. Read by `build-state`, `ask-
|
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
|
+
## Global wiki (v5.3.0+)
|
|
158
|
+
|
|
159
|
+
A per-user **global wiki** at `~/.kushi-global/State/` for cross-engagement knowledge — same Karpathy shape as a project `State/`, marked `scope: global`.
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
kushi global init # scaffold ~/.kushi-global/State/
|
|
163
|
+
kushi global status # counts + last-modified summary
|
|
164
|
+
kushi global ask "what's our confidence ladder pattern?"
|
|
165
|
+
kushi global lint # privacy + structure pass
|
|
166
|
+
|
|
167
|
+
# Project → global is explicit-only:
|
|
168
|
+
kushi promote <project> <answer-page> # refuses if identifiers detected
|
|
169
|
+
kushi promote <project> <answer-page> --force # redacts + writes target + back-link
|
|
170
|
+
|
|
171
|
+
# Routing under ask-project:
|
|
172
|
+
kushi ask <project> "..." # project-first (default)
|
|
173
|
+
kushi ask <project> "..." --global # global-first
|
|
174
|
+
kushi ask <project> "..." --project-only # suppress global
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The global root honors `$KUSHI_GLOBAL_ROOT` (used by tests). There is no auto-promotion path — privacy is always your call. See `plugin/instructions/global-wiki.instructions.md` + `plugin/instructions/multi-wiki-routing.instructions.md`.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
157
181
|
## Three install profiles
|
|
158
182
|
|
|
159
183
|
Kushi ships in three tiers. Pick how much you take — the default (`standard`) matches v2.x behavior end-to-end.
|
package/bin/cli.mjs
CHANGED
|
@@ -17,15 +17,55 @@ if (args.length > 0 && SKILL_VERBS.has(args[0])) {
|
|
|
17
17
|
|
|
18
18
|
// ── lint verb (v5.1.0+) ──────────────────────────────────────────────────────
|
|
19
19
|
if (args.length > 0 && args[0] === 'lint') {
|
|
20
|
+
if (args.includes('--global')) {
|
|
21
|
+
const { runGlobalLint } = await import('../src/global-wiki-cli.mjs');
|
|
22
|
+
await runGlobalLint();
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
20
25
|
const project = args[1] || '';
|
|
21
26
|
if (!project) {
|
|
22
|
-
console.error('\n Usage: kushi lint <project>\n');
|
|
27
|
+
console.error('\n Usage: kushi lint <project>\n kushi lint --global\n');
|
|
23
28
|
process.exit(1);
|
|
24
29
|
}
|
|
25
30
|
await dispatchLint(project);
|
|
26
31
|
process.exit(0);
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
// ── global verb (v5.3.0+) ────────────────────────────────────────────────────
|
|
35
|
+
if (args.length > 0 && args[0] === 'global') {
|
|
36
|
+
const sub = args[1] || '';
|
|
37
|
+
const validSubs = ['init', 'status', 'ask', 'lint'];
|
|
38
|
+
if (!validSubs.includes(sub)) {
|
|
39
|
+
console.error('\n Usage: kushi global init Scaffold ~/.kushi-global/State/');
|
|
40
|
+
console.error(' kushi global status Show counts + freshness');
|
|
41
|
+
console.error(' kushi global ask <question> Ask the global wiki');
|
|
42
|
+
console.error(' kushi global lint Lint the global wiki\n');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const { runGlobalInit, runGlobalStatus, runGlobalAsk, runGlobalLint } = await import('../src/global-wiki-cli.mjs');
|
|
46
|
+
if (sub === 'init') await runGlobalInit();
|
|
47
|
+
else if (sub === 'status') await runGlobalStatus();
|
|
48
|
+
else if (sub === 'ask') await runGlobalAsk(args.slice(2).join(' '));
|
|
49
|
+
else if (sub === 'lint') await runGlobalLint();
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── promote verb (v5.3.0+) ───────────────────────────────────────────────────
|
|
54
|
+
if (args.length > 0 && args[0] === 'promote') {
|
|
55
|
+
const project = args[1] || '';
|
|
56
|
+
const page = args[2] || '';
|
|
57
|
+
if (!project || !page) {
|
|
58
|
+
console.error('\n Usage: kushi promote <project> <page-path>\n');
|
|
59
|
+
console.error(' Copies a project State page into the global wiki with provenance metadata.');
|
|
60
|
+
console.error(' Refuses by default if customer identifiers are detected; pass --force after review.\n');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
const force = args.includes('--force');
|
|
64
|
+
const { runPromote } = await import('../src/global-wiki-cli.mjs');
|
|
65
|
+
await runPromote(project, page, { force });
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
|
|
29
69
|
// ── hooks verb (v5.2.0+) ─────────────────────────────────────────────────────
|
|
30
70
|
if (args.length > 0 && args[0] === 'hooks') {
|
|
31
71
|
const sub = args[1] || '';
|
|
@@ -108,6 +148,7 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
108
148
|
|
|
109
149
|
Wiki maintenance (v5.1.0+):
|
|
110
150
|
lint <project> Run wiki-lint checks on State/ (contradictions, stale claims, orphans).
|
|
151
|
+
lint --global Lint the global wiki at ~/.kushi-global/State/.
|
|
111
152
|
|
|
112
153
|
Hooks & observability (v5.2.0+):
|
|
113
154
|
hooks list <project> List configured hooks for a project.
|
|
@@ -115,6 +156,14 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
115
156
|
explain <topic> Explain a kushi concept (pedagogical, read-only).
|
|
116
157
|
remember <rule> Persist a project convention to CLAUDE.md.
|
|
117
158
|
|
|
159
|
+
Global wiki (v5.3.0+):
|
|
160
|
+
global init Scaffold ~/.kushi-global/State/ (env: KUSHI_GLOBAL_ROOT)
|
|
161
|
+
global status Show page counts + freshness for the global wiki.
|
|
162
|
+
global ask <question> Search the global wiki specifically.
|
|
163
|
+
global lint Lint the global wiki (alias for 'lint --global').
|
|
164
|
+
promote <project> <page> Move a project State page into global with redaction + back-link.
|
|
165
|
+
Refuses if customer identifiers are detected; --force after review.
|
|
166
|
+
|
|
118
167
|
After install, talk to Kushi:
|
|
119
168
|
bootstrap <project> First-time setup
|
|
120
169
|
refresh <project> Incremental refresh + rebuild State/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kushi-agents",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Install Kushi — multi-source project evidence agent with Comprehensive Structured Capture (CSC) into weekly-only files across Email, Teams, OneNote, Loop, SharePoint, Meetings, CRM, ADO. Meetings retain a sibling verbatim/ audit folder. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"scripts": {
|
|
44
|
-
"test": "node --test src/check-workiq.test.mjs src/seed-config.test.mjs src/sanitize-workiq-input.test.mjs src/detect-vertex-repo.test.mjs src/vertex-validate.test.mjs src/emit-vertex.e2e.test.mjs src/config-root-resolve.test.mjs src/forbidden-workiq-phrasings.test.mjs src/multi-host-install.test.mjs src/eval-aggregator.test.mjs src/eval-runner.test.mjs src/skill-creator.test.mjs src/skill-checker.test.mjs src/hooks-dispatcher.test.mjs src/parallel-refresh.test.mjs src/otel-emit.test.mjs src/teach.test.mjs src/schema-evolve.test.mjs",
|
|
44
|
+
"test": "node --test src/check-workiq.test.mjs src/seed-config.test.mjs src/sanitize-workiq-input.test.mjs src/detect-vertex-repo.test.mjs src/vertex-validate.test.mjs src/emit-vertex.e2e.test.mjs src/config-root-resolve.test.mjs src/forbidden-workiq-phrasings.test.mjs src/multi-host-install.test.mjs src/eval-aggregator.test.mjs src/eval-runner.test.mjs src/skill-creator.test.mjs src/skill-checker.test.mjs src/hooks-dispatcher.test.mjs src/parallel-refresh.test.mjs src/otel-emit.test.mjs src/teach.test.mjs src/schema-evolve.test.mjs src/global-wiki.test.mjs src/promote.test.mjs",
|
|
45
45
|
"test:integration:bootstrap": "node src/bootstrap-dryrun.integration.test.mjs",
|
|
46
46
|
"smoke": "node scripts/smoke.mjs",
|
|
47
47
|
"eval": "pwsh plugin/skills/eval/run-evals.ps1 -Skill",
|
|
@@ -54,6 +54,8 @@ The Evidence/ folder produced by `aggregate` is the **public contract** between
|
|
|
54
54
|
| `@Kushi teach <topic>` | standard+ | n/a (write-only) | v5.2.0 — `teach` — persist a reusable fact/preference/pattern to `.kushi/learnings/`. Lookup via `explain`. |
|
|
55
55
|
| `@Kushi explain <topic>` | standard+ | n/a (read-only) | v5.2.0 — `teach` (explain mode) — retrieve a previously taught fact/preference/pattern from `.kushi/learnings/`. |
|
|
56
56
|
| `@Kushi schema-evolve <project>` | standard+ | n/a | v5.2.0 — `schema-evolve` — detect schema drift in Evidence/ layouts and propose safe migrations with rollback plans. |
|
|
57
|
+
| `@Kushi global init` / `status` / `ask <q>` / `lint` | standard+ | n/a | v5.3.0 — `global-wiki` — manage the per-user cross-engagement wiki at `~/.kushi-global/State/` (env `KUSHI_GLOBAL_ROOT` for tests). |
|
|
58
|
+
| `@Kushi promote <project> <page>` | standard+ | n/a | v5.3.0 — `promote` — copy a project State page into the global wiki with identifier redaction + back-link + dual log. Refuses without `--force` when identifiers detected. |
|
|
57
59
|
|
|
58
60
|
**Note on auto-routing**: `ask` does NOT require the `@Kushi ask` prefix. Any message that names a known project AND asks a question (what / who / when / status / summarize / etc.) auto-dispatches to `ask-project`. Producer verbs win in the unambiguous case.
|
|
59
61
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "global-wiki"
|
|
3
|
+
description: "v5.3.0 — Global wiki at ~/.kushi-global/State/ (env override KUSHI_GLOBAL_ROOT). Structurally identical to a project State/ wiki (Karpathy layout) but tagged scope: global in frontmatter. Holds cross-engagement patterns that don't belong in any one project. Never auto-populated — only explicit kushi promote moves content in. Linter checks for [!warning] potential-customer-leak callouts to enforce privacy posture."
|
|
4
|
+
applies_to: "global init/status/ask/lint, promote, ask-project routing, teach routing"
|
|
5
|
+
since: "kushi v5.3.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# global-wiki — doctrine
|
|
9
|
+
|
|
10
|
+
> **Authored to [agentskills.io](https://agentskills.io/skill-creation/best-practices) spec.**
|
|
11
|
+
> Deltas from source (living-wiki Karpathy pattern + Obsidian global-vault + Claude.md global-memory): adds a separate root, `scope: global` frontmatter marker, explicit-promotion-only contract, and a privacy linter (`potential-customer-leak`).
|
|
12
|
+
|
|
13
|
+
The global wiki is a personal, cross-engagement knowledge base that lives **outside** any single project's `Evidence/<alias>/State/`. Consultants accumulate cross-cutting patterns — "how I structure FDE intake", "my preferred Status taxonomy", "tools and snippets that work across all customers" — and those patterns belong in a single durable home, not re-derived per engagement and not silently bleeding between projects.
|
|
14
|
+
|
|
15
|
+
## Rules (HARD)
|
|
16
|
+
|
|
17
|
+
### 1. Location
|
|
18
|
+
|
|
19
|
+
- **Default:** `~/.kushi-global/State/` (`$HOME` on POSIX, `$env:USERPROFILE` on Windows).
|
|
20
|
+
- **Override:** `$KUSHI_GLOBAL_ROOT` environment variable (absolute path; tilde-expanded). Tests MUST set this to `.testtmp/.kushi-global/` — never touch the real path.
|
|
21
|
+
- The global root is **per-user**, never per-project, never per-host.
|
|
22
|
+
|
|
23
|
+
### 2. Shape
|
|
24
|
+
|
|
25
|
+
The global wiki MUST mirror the standard State/ layout (per `karpathy-state-layout.instructions.md` + `living-wiki.instructions.md`):
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
~/.kushi-global/State/
|
|
29
|
+
├── index.md # entry point, links to all pages
|
|
30
|
+
├── log.md # reverse-chronological op log (same format as project log.md)
|
|
31
|
+
├── tour.md # guided tour pointer (optional)
|
|
32
|
+
├── hot.md # hot-edits scratch (optional)
|
|
33
|
+
├── conventions.md # cross-engagement conventions / CLAUDE.md-shape rules
|
|
34
|
+
├── answers/ # promoted Q&A pages
|
|
35
|
+
├── reports/ # global lint reports, status snapshots
|
|
36
|
+
└── _review-queue.md # open privacy / contradiction items
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Every markdown page in the global wiki MUST carry frontmatter with `scope: global`:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
---
|
|
43
|
+
kushi_state_page: true
|
|
44
|
+
scope: global
|
|
45
|
+
---
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The `scope: global` marker distinguishes a true global page from a project page that was *copied* locally for reference.
|
|
49
|
+
|
|
50
|
+
### 3. Initialization
|
|
51
|
+
|
|
52
|
+
- `kushi global init` creates the scaffold idempotently — re-running NEVER overwrites existing content.
|
|
53
|
+
- Skips files that already exist; only adds missing scaffolding.
|
|
54
|
+
- Logs `global-init` entry to `~/.kushi-global/State/log.md` on every run (even no-op).
|
|
55
|
+
|
|
56
|
+
### 4. Privacy posture
|
|
57
|
+
|
|
58
|
+
The global wiki crosses engagements. **Customer identifiers MUST NOT leak in.**
|
|
59
|
+
|
|
60
|
+
- The promote operation runs an identifier scan and refuses unless explicit `--force` is given.
|
|
61
|
+
- `kushi global lint` (and `kushi lint --global`) scans `*.md` under the global root for `> [!warning] potential-customer-leak` callouts (left there by promote when it had to redact).
|
|
62
|
+
- The user is responsible for resolving those callouts before sharing the global wiki.
|
|
63
|
+
|
|
64
|
+
### 5. Promotion is explicit only
|
|
65
|
+
|
|
66
|
+
- Pages NEVER auto-promote from a project to global. The only path is `kushi promote <project> <page-path>`.
|
|
67
|
+
- See `multi-wiki-routing.instructions.md` for the promotion contract + back-link rule.
|
|
68
|
+
|
|
69
|
+
### 6. Storage outside engagement tree
|
|
70
|
+
|
|
71
|
+
The global wiki lives **outside** any engagement root. Self-check `D40.global-wiki-shape` checks the configured location (env-overridden in CI) and is warn-only — the absence of `~/.kushi-global/` is normal until the user runs `kushi global init`.
|
|
72
|
+
|
|
73
|
+
## References
|
|
74
|
+
|
|
75
|
+
- `multi-wiki-routing.instructions.md` — routing across project + global
|
|
76
|
+
- `living-wiki.instructions.md` — incremental + contradiction lifecycle (same rules apply)
|
|
77
|
+
- `karpathy-state-layout.instructions.md` — page shape
|
|
78
|
+
- `schema-evolve.instructions.md` — `global` scope was placeholdered here in v5.2.0; v5.3.0 honors it.
|
|
79
|
+
- `wiki-lint.instructions.md` — finding classes; v5.3.0 adds `potential-customer-leak`.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "multi-wiki-routing"
|
|
3
|
+
description: "v5.3.0 — Routing rules for project vs global wiki. ask-project: project-first; augment with global only if project confidence below threshold; --global forces global-first, --project-only suppresses global. build-state: project-only, never auto-promotes to global. lint-state: project-only; kushi lint --global lints global separately. teach: global-first for cross-cutting topics, project for project-specific. Promotion path: explicit kushi promote <project> <page>, never automatic."
|
|
4
|
+
applies_to: "ask-project, build-state, lint-state, teach, promote"
|
|
5
|
+
since: "kushi v5.3.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# multi-wiki-routing — doctrine
|
|
9
|
+
|
|
10
|
+
> **Authored to [agentskills.io](https://agentskills.io/skill-creation/best-practices) spec.**
|
|
11
|
+
> Deltas from source: kushi previously had a single wiki per project. This doctrine formalizes the project↔global routing rules introduced in v5.3.0.
|
|
12
|
+
|
|
13
|
+
Kushi maintains two kinds of wikis:
|
|
14
|
+
|
|
15
|
+
| Kind | Path | Scope |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| **Project** | `Evidence/<alias>/State/` | One engagement only. |
|
|
18
|
+
| **Global** | `$KUSHI_GLOBAL_ROOT` or `~/.kushi-global/State/` | Cross-engagement; per-user. |
|
|
19
|
+
|
|
20
|
+
Every reader/writer skill MUST be explicit about which it touches.
|
|
21
|
+
|
|
22
|
+
## Rules (HARD)
|
|
23
|
+
|
|
24
|
+
### 1. ask-project — project-first, global-augment
|
|
25
|
+
|
|
26
|
+
Default behavior (`kushi ask <project> <q>`):
|
|
27
|
+
|
|
28
|
+
1. Resolve the project and run the standard project-scoped answer chain (per `ask-project/SKILL.md`).
|
|
29
|
+
2. Compute the confidence (per `evidence-confidence-ladder.instructions.md`).
|
|
30
|
+
3. **If confidence is `low` (or `medium` with `--global-augment` set in config)** → also query `$KUSHI_GLOBAL_ROOT/State/answers/` for matching topics and append a `## From your global wiki` section, citing each hit with `[global: <page>]`.
|
|
31
|
+
4. **If confidence is `high`** → do NOT consult global (avoid noise).
|
|
32
|
+
|
|
33
|
+
Flags:
|
|
34
|
+
|
|
35
|
+
| Flag | Behavior |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `--global` | Reverse the order: search global first, project second. Show provenance `[global]` first, `[project: <alias>]` second. |
|
|
38
|
+
| `--project-only` | Hard-disable global consultation regardless of confidence. |
|
|
39
|
+
| (none) | Default project-first + augment-on-low-confidence. |
|
|
40
|
+
|
|
41
|
+
Source provenance MUST be visible per citation: `[project: <alias>]` vs `[global]`.
|
|
42
|
+
|
|
43
|
+
### 2. build-state — project-only
|
|
44
|
+
|
|
45
|
+
`build-state` writes to `Evidence/<alias>/State/` and **NEVER** writes to the global wiki. There is no auto-promotion path. Even if a fact has appeared in 10 projects, build-state does not move it to global — only the user, via `kushi promote`, does.
|
|
46
|
+
|
|
47
|
+
### 3. lint-state — project-only by default
|
|
48
|
+
|
|
49
|
+
- `kushi lint <project>` → lints the project State only. Unchanged from v5.1.0.
|
|
50
|
+
- `kushi lint --global` → lints the global wiki at `$KUSHI_GLOBAL_ROOT/State/` separately. Same finding classes plus `potential-customer-leak` (see `global-wiki.instructions.md`).
|
|
51
|
+
- Lint runs are independent; one does not implicitly run the other.
|
|
52
|
+
|
|
53
|
+
### 4. teach — global-first for cross-cutting topics
|
|
54
|
+
|
|
55
|
+
- For **cross-cutting topics** (kushi concepts, doctrines, releases — e.g. "explain confidence ladder", "how does CSC work"): `teach` consults the global wiki FIRST (if a matching page exists in `~/.kushi-global/State/answers/`), then falls back to in-repo doctrine, then to genealogy.
|
|
56
|
+
- For **project-specific topics** ("how did we structure intake for AGCO?"): `teach` declines and suggests `kushi ask <project> <q>` instead — that's an `ask-project` job.
|
|
57
|
+
- Citations distinguish `[global: <page>]` vs `[doctrine: <file>]` vs `[genealogy: <version>]`.
|
|
58
|
+
|
|
59
|
+
### 5. Promotion path — explicit only
|
|
60
|
+
|
|
61
|
+
`kushi promote <project> <page>` is the **only** way content moves project → global. See `Promote operation` below.
|
|
62
|
+
|
|
63
|
+
Auto-promotion is intentionally not supported because:
|
|
64
|
+
|
|
65
|
+
1. Customer-identifier detection is best-effort; the user must review.
|
|
66
|
+
2. What is "cross-cutting" depends on the consultant, not the machine.
|
|
67
|
+
3. Silent promotion would surprise the user — global is personal space.
|
|
68
|
+
|
|
69
|
+
### 6. Demotion / removal
|
|
70
|
+
|
|
71
|
+
There is no `kushi demote` in v5.3.0. To remove a global page the user deletes the file directly and appends a manual `log.md` entry. v6+ MAY add a managed demote verb.
|
|
72
|
+
|
|
73
|
+
## Promote operation
|
|
74
|
+
|
|
75
|
+
`kushi promote <project> <page-path>` performs the following, in order:
|
|
76
|
+
|
|
77
|
+
1. **Resolve source.** Find `<engagement-root>/<project>/Evidence/<alias>/State/<page-path>`. Must exist.
|
|
78
|
+
2. **Read source body + frontmatter.**
|
|
79
|
+
3. **Run identifier scan** against the body. Uses the same heuristics as `schema-evolve`-style detection:
|
|
80
|
+
- Known customer aliases registered in `.settings.yml` `discovery.project_aliases:` or the alias folder name itself.
|
|
81
|
+
- The literal project name.
|
|
82
|
+
- Email addresses with non-Microsoft domains.
|
|
83
|
+
- High-confidence proper-noun runs that match `<project>` aliases (case-insensitive, word boundaries).
|
|
84
|
+
4. **Build redaction list.** For each hit:
|
|
85
|
+
- Replace the literal string with `[REDACTED]` in the global copy.
|
|
86
|
+
- Record `{ pattern, count, line_numbers }` in the redactions list.
|
|
87
|
+
5. **Refuse without `--force`** if the redactions list is non-empty. Print the list with line numbers and the human-review prompt. The user is expected to inspect, then re-run with `--force` (which writes the redacted body and adds a `> [!warning] potential-customer-leak` callout near each redaction site for the lint pass to track).
|
|
88
|
+
6. **Write target.** Path: `$KUSHI_GLOBAL_ROOT/State/answers/<source-slug>.md` (slugify source filename; collisions append `-N`).
|
|
89
|
+
Frontmatter MUST contain:
|
|
90
|
+
```yaml
|
|
91
|
+
---
|
|
92
|
+
kushi_state_page: true
|
|
93
|
+
scope: global
|
|
94
|
+
promoted_from: "<project>/<alias>/<relative-source-path>"
|
|
95
|
+
promoted_at: "<ISO-8601 UTC>"
|
|
96
|
+
redactions: ["<pattern1>", "<pattern2>"]
|
|
97
|
+
---
|
|
98
|
+
```
|
|
99
|
+
7. **Add back-link to source.** Append (or update) a callout in the source page:
|
|
100
|
+
```markdown
|
|
101
|
+
> [!info] Promoted to global wiki
|
|
102
|
+
> <source-slug>.md @ <ISO-8601 UTC> · redactions: <N>
|
|
103
|
+
```
|
|
104
|
+
8. **Dual log.** Append a `promote` entry to BOTH:
|
|
105
|
+
- `<project>/Evidence/<alias>/State/log.md` (op = `promote`, title = `Promoted <slug> to global`).
|
|
106
|
+
- `$KUSHI_GLOBAL_ROOT/State/log.md` (op = `promote-in`, title = `Imported <slug> from <project>`).
|
|
107
|
+
9. **Print summary** with both file paths.
|
|
108
|
+
|
|
109
|
+
The operation is **atomic**: if any step fails (redaction refused, write denied, back-link fails), no writes are persisted. The implementation uses a stage-then-commit pattern.
|
|
110
|
+
|
|
111
|
+
## References
|
|
112
|
+
|
|
113
|
+
- `global-wiki.instructions.md` — global wiki location + privacy rules
|
|
114
|
+
- `evidence-confidence-ladder.instructions.md` — confidence threshold for routing
|
|
115
|
+
- `living-wiki.instructions.md` — same incremental + contradiction rules apply to both wikis
|
|
116
|
+
- `wiki-lint.instructions.md` — finding classes; v5.3.0 adds `potential-customer-leak`
|
|
117
|
+
- `schema-evolve.instructions.md` — identifier-detection heuristics reused here
|
|
@@ -72,6 +72,20 @@ When the user passes `--file-back` (or says "file this answer back", "save this
|
|
|
72
72
|
|
|
73
73
|
The `--file-back` flag is OPTIONAL. Without it, ask-project behaves exactly as before (read-only, no writes).
|
|
74
74
|
|
|
75
|
+
## --global / --project-only (v5.3.0+)
|
|
76
|
+
|
|
77
|
+
Multi-wiki routing flags governed by `multi-wiki-routing.instructions.md`:
|
|
78
|
+
|
|
79
|
+
| Flag | Behavior |
|
|
80
|
+
|------|----------|
|
|
81
|
+
| *(no flag)* | **Project-first.** Search project `Evidence/<alias>/State/` first; only fall back to the global wiki when project sources are missing/stale or no hit is found. Cite each hit with `[project: <alias>]` or `[global]`. |
|
|
82
|
+
| `--global` | **Global-first.** Search `$KUSHI_GLOBAL_ROOT/State/answers/` first; fall back to the project. Use when you trust the cross-engagement note more than project state. |
|
|
83
|
+
| `--project-only` | **Hard-suppress global.** Never read the global wiki for this question (privacy-sensitive or strictly project-internal). |
|
|
84
|
+
|
|
85
|
+
Provenance is never silent. Every citation tags `[project: <alias>]` or `[global]`. If the answer mixes both, list each source with its provenance.
|
|
86
|
+
|
|
87
|
+
The global wiki itself is opt-in (created via `kushi global init`). If it does not exist on disk, all three modes degrade silently to project-only.
|
|
88
|
+
|
|
75
89
|
## Inputs
|
|
76
90
|
|
|
77
91
|
- `<project>` — fuzzy-matched project name. If multiple plausible matches, ask the user.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global-wiki
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "global-wiki"
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
description: "USE WHEN the user says 'init global wiki', 'kushi global init/status/ask/lint', 'show me my global wiki', or wants to manage the cross-engagement knowledge base at ~/.kushi-global/State/. DO NOT USE for promoting individual pages (use promote) or for project-scoped Q&A (use ask-project). Capability: scaffold + status + ask + lint over the per-user global wiki; honors $KUSHI_GLOBAL_ROOT for tests."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: global-wiki
|
|
8
|
+
|
|
9
|
+
Manages the per-user global wiki at `$KUSHI_GLOBAL_ROOT` (default `~/.kushi-global/State/`). Structurally identical to a project `State/` wiki but tagged `scope: global` in every page's frontmatter. Holds cross-engagement patterns that consultants want to keep across projects.
|
|
10
|
+
|
|
11
|
+
See `plugin/instructions/global-wiki.instructions.md` for the full doctrine and `multi-wiki-routing.instructions.md` for how readers + writers route between project and global.
|
|
12
|
+
|
|
13
|
+
## Triggers
|
|
14
|
+
|
|
15
|
+
- `kushi global init`
|
|
16
|
+
- `kushi global status`
|
|
17
|
+
- `kushi global ask <question>`
|
|
18
|
+
- `kushi global lint`
|
|
19
|
+
- "init my global wiki"
|
|
20
|
+
- "what's in my global wiki"
|
|
21
|
+
- "lint global"
|
|
22
|
+
|
|
23
|
+
## Inputs
|
|
24
|
+
|
|
25
|
+
- `<subcommand>` — one of `init`, `status`, `ask`, `lint`.
|
|
26
|
+
- `<question>` — required for `ask`.
|
|
27
|
+
|
|
28
|
+
## Step checklist
|
|
29
|
+
|
|
30
|
+
- [ ] Step 1 — Resolve `$KUSHI_GLOBAL_ROOT` (env override) or fall back to `~/.kushi-global/`.
|
|
31
|
+
- [ ] Step 2 — Dispatch to the requested sub-operation.
|
|
32
|
+
- [ ] Step 3 — Print a one-line summary + paths.
|
|
33
|
+
- [ ] Step 4 — Append a `log.md` entry on init / lint / ask-fileback.
|
|
34
|
+
|
|
35
|
+
### Step 1 — Resolve global root
|
|
36
|
+
|
|
37
|
+
Read `$env:KUSHI_GLOBAL_ROOT`. If unset, default to `$env:USERPROFILE/.kushi-global/` on Windows or `$HOME/.kushi-global/` on POSIX. Tests MUST set `$env:KUSHI_GLOBAL_ROOT='.testtmp/.kushi-global'` and NEVER touch the real path.
|
|
38
|
+
|
|
39
|
+
### Step 2 — Sub-operations
|
|
40
|
+
|
|
41
|
+
| Sub | Behavior |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `init` | Idempotent scaffold of `State/` with `index.md`, `log.md`, `conventions.md`, `_review-queue.md`, `answers/`, `reports/`. Every file carries `scope: global` frontmatter. |
|
|
44
|
+
| `status` | Count pages by kind + report newest mtime + open review-queue items. |
|
|
45
|
+
| `ask` | Full-text scan of `State/answers/*.md` (case-insensitive, ≥3-char terms). Cite hits as `[global: <page>]`. |
|
|
46
|
+
| `lint` | Scan all `State/**/*.md` for `[!warning] potential-customer-leak` + `[!warning] Contradicted`. Severity = warning. |
|
|
47
|
+
|
|
48
|
+
### Step 3 — Output
|
|
49
|
+
|
|
50
|
+
Print resolved root, sub-operation result, and any actionable next steps.
|
|
51
|
+
|
|
52
|
+
### Step 4 — Log
|
|
53
|
+
|
|
54
|
+
- `init` → append `global-init` to `State/log.md`.
|
|
55
|
+
- `lint` → append `global-lint` if findings produced.
|
|
56
|
+
- `ask` with `--file-back` (future) → append `global-ask-fileback`.
|
|
57
|
+
|
|
58
|
+
## Hard rules
|
|
59
|
+
|
|
60
|
+
- **NEVER write to a project's Evidence/.** This skill is global-wiki only.
|
|
61
|
+
- **NEVER auto-promote.** Promotion is a separate `promote` skill, user-invoked.
|
|
62
|
+
- **Tests MUST use `$env:KUSHI_GLOBAL_ROOT='.testtmp/.kushi-global'`.** Real `~/.kushi-global/` is user data.
|
|
63
|
+
- **Privacy posture.** When ask returns hits, never silently mix them with project results — provenance `[global]` MUST be visible on every citation.
|
|
64
|
+
|
|
65
|
+
## Stop conditions
|
|
66
|
+
|
|
67
|
+
- Sub-command missing → print usage, exit 1.
|
|
68
|
+
- `ask` with no question → print usage, exit 1.
|
|
69
|
+
- `status` / `lint` against an uninitialized root → report `not initialized` + suggest `kushi global init`.
|
|
70
|
+
|
|
71
|
+
## Validation loop
|
|
72
|
+
|
|
73
|
+
1. Run `pwsh plugin/skills/self-check/run.ps1 -Targeted D40`.
|
|
74
|
+
2. Fix any findings, re-run.
|
|
75
|
+
3. Repeat until self-check exits 0.
|
|
76
|
+
|
|
77
|
+
## References
|
|
78
|
+
|
|
79
|
+
- `../../instructions/global-wiki.instructions.md`
|
|
80
|
+
- `../../instructions/multi-wiki-routing.instructions.md`
|
|
81
|
+
- `../../instructions/log-format.instructions.md`
|
|
82
|
+
- `../../instructions/karpathy-state-layout.instructions.md`
|
|
83
|
+
- `../promote/SKILL.md` — the promotion verb
|
|
84
|
+
|
|
85
|
+
## Issue Recovery
|
|
86
|
+
|
|
87
|
+
If this skill exposes a reusable defect (e.g. a scaffold file missing from the template, a privacy heuristic that misses a customer pattern), fix the smallest correct repo-owned artifact first (`src/global-wiki.mjs` or the scaffold) and re-run `self-check -Targeted D40`.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "global-wiki",
|
|
3
|
+
"cases": [
|
|
4
|
+
{
|
|
5
|
+
"id": "global-init-creates-scaffold",
|
|
6
|
+
"name": "kushi global init creates index/log/conventions/_review-queue and answers/+reports/",
|
|
7
|
+
"input": "kushi global init",
|
|
8
|
+
"expected_assertions": [
|
|
9
|
+
{ "type": "contains", "value": "State" },
|
|
10
|
+
{ "type": "contains", "value": "Created" }
|
|
11
|
+
],
|
|
12
|
+
"grader_type": "script"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "global-status-counts-pages",
|
|
16
|
+
"name": "kushi global status reports counts after init",
|
|
17
|
+
"input": "kushi global status",
|
|
18
|
+
"expected_assertions": [
|
|
19
|
+
{ "type": "contains", "value": "Pages" },
|
|
20
|
+
{ "type": "contains", "value": "Answers" }
|
|
21
|
+
],
|
|
22
|
+
"grader_type": "script"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "global-ask-finds-hit",
|
|
26
|
+
"name": "kushi global ask returns a citation with [global] provenance when a matching page exists",
|
|
27
|
+
"input": "kushi global ask confidence ladder",
|
|
28
|
+
"expected_assertions": [
|
|
29
|
+
{ "type": "contains", "value": "[global]" }
|
|
30
|
+
],
|
|
31
|
+
"grader_type": "script"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "global-lint-clean-on-fresh-init",
|
|
35
|
+
"name": "kushi global lint emits no findings on a freshly-initialized wiki",
|
|
36
|
+
"input": "kushi global lint",
|
|
37
|
+
"expected_assertions": [
|
|
38
|
+
{ "type": "contains", "value": "No findings" }
|
|
39
|
+
],
|
|
40
|
+
"grader_type": "script"
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
promote
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "promote"
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
description: "USE WHEN the user says 'kushi promote <project> <page>', 'promote this answer to global', 'move this page to my global wiki', or wants to copy a project State page into the cross-engagement global wiki at ~/.kushi-global/. DO NOT USE for project Q&A (use ask-project) or for initializing the global wiki itself (use global-wiki). Capability: identifier-scan + redact + write + back-link + dual-log. Refuses without --force when customer identifiers are detected."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: promote
|
|
8
|
+
|
|
9
|
+
Copies a single project State page into the global wiki (`$KUSHI_GLOBAL_ROOT/State/answers/`) with provenance metadata, an identifier-detection gate, and a back-link in the source page.
|
|
10
|
+
|
|
11
|
+
This is the **only** path from project → global. Auto-promotion is intentionally not supported. See `multi-wiki-routing.instructions.md` § Promote operation for the contract.
|
|
12
|
+
|
|
13
|
+
## Triggers
|
|
14
|
+
|
|
15
|
+
- `kushi promote <project> <page-path>`
|
|
16
|
+
- `kushi promote <project> <page-path> --force`
|
|
17
|
+
- "promote this answer to global"
|
|
18
|
+
- "move <page> into my global wiki"
|
|
19
|
+
|
|
20
|
+
## Inputs
|
|
21
|
+
|
|
22
|
+
- `<project>` — project name relative to cwd (or under `..`).
|
|
23
|
+
- `<page-path>` — path to the source page. Accepted forms:
|
|
24
|
+
- Absolute path.
|
|
25
|
+
- Path relative to the project root (e.g. `Evidence/<alias>/State/answers/2026-05-27_<slug>.md`).
|
|
26
|
+
- Path relative to a discovered `Evidence/<alias>/State/` (e.g. `answers/<slug>.md`).
|
|
27
|
+
- Path relative to a plain `<project>/State/` (e.g. `answers/<slug>.md`).
|
|
28
|
+
- `--force` — required when the identifier scan finds hits.
|
|
29
|
+
|
|
30
|
+
## Step checklist
|
|
31
|
+
|
|
32
|
+
- [ ] Step 1 — Resolve project root + source page.
|
|
33
|
+
- [ ] Step 2 — Read source + run identifier scan.
|
|
34
|
+
- [ ] Step 3 — Refuse without `--force` if hits detected; print review prompt.
|
|
35
|
+
- [ ] Step 4 — Write redacted target with `scope: global` frontmatter.
|
|
36
|
+
- [ ] Step 5 — Add `[!info] Promoted to global wiki` back-link in source.
|
|
37
|
+
- [ ] Step 6 — Append `promote` entry to project `State/log.md`.
|
|
38
|
+
- [ ] Step 7 — Append `promote-in` entry to global `State/log.md`.
|
|
39
|
+
- [ ] Step 8 — Print summary.
|
|
40
|
+
|
|
41
|
+
### Step 1 — Resolve
|
|
42
|
+
|
|
43
|
+
Find the source via `resolveProjectRoot` + `resolveSourcePage` in `src/global-wiki-cli.mjs`. Echo the resolved absolute path before any write.
|
|
44
|
+
|
|
45
|
+
### Step 2 — Identifier scan
|
|
46
|
+
|
|
47
|
+
Use `detectIdentifiers()` from `src/global-wiki.mjs`. Patterns checked:
|
|
48
|
+
|
|
49
|
+
- The literal project name (case-insensitive, word boundary).
|
|
50
|
+
- The alias folder name (inferred from `Evidence/<alias>/` in the path).
|
|
51
|
+
- Any extra aliases supplied (optional flag, future).
|
|
52
|
+
- Non-Microsoft email addresses (`@*` where domain does not end in `microsoft.com`).
|
|
53
|
+
|
|
54
|
+
Each hit records `{ pattern, kind, count, line_numbers }`.
|
|
55
|
+
|
|
56
|
+
### Step 3 — Refuse gate
|
|
57
|
+
|
|
58
|
+
If hits > 0 AND `--force` not supplied → refuse with exit code 2, print the hits with line numbers, suggest review. **No filesystem writes occur on refusal.**
|
|
59
|
+
|
|
60
|
+
### Step 4 — Write target
|
|
61
|
+
|
|
62
|
+
Target path: `$KUSHI_GLOBAL_ROOT/State/answers/<slug>.md` where `<slug>` = slugified source filename (lowercase, alnum + hyphens, ≤60 chars). Collisions append `-N`.
|
|
63
|
+
|
|
64
|
+
Frontmatter MUST include:
|
|
65
|
+
|
|
66
|
+
```yaml
|
|
67
|
+
---
|
|
68
|
+
kushi_state_page: true
|
|
69
|
+
scope: global
|
|
70
|
+
promoted_from: "<project>/<relative-source-path>"
|
|
71
|
+
promoted_at: "<ISO-8601 UTC>"
|
|
72
|
+
redactions: ["<pattern1>", "<pattern2>"]
|
|
73
|
+
---
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If any redactions occurred, append a `> [!warning] potential-customer-leak` callout listing the patterns so `global lint` tracks the open review item.
|
|
77
|
+
|
|
78
|
+
### Step 5 — Back-link
|
|
79
|
+
|
|
80
|
+
Append to the source page (idempotent — skip if the target slug is already linked):
|
|
81
|
+
|
|
82
|
+
```markdown
|
|
83
|
+
> [!info] Promoted to global wiki
|
|
84
|
+
> answers/<slug>.md @ <iso> · redactions: <N>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Step 6 / 7 — Dual log
|
|
88
|
+
|
|
89
|
+
- Project `State/log.md`: `promote | Promoted <slug> to global (redactions: N)`.
|
|
90
|
+
- Global `State/log.md`: `promote-in | Imported <slug> from <project> (redactions: N)`.
|
|
91
|
+
|
|
92
|
+
### Step 8 — Print summary
|
|
93
|
+
|
|
94
|
+
Echo `source`, `target`, `slug`, `redactions`, `promoted_at`.
|
|
95
|
+
|
|
96
|
+
## Hard rules
|
|
97
|
+
|
|
98
|
+
- **Atomic.** No partial state. If any step fails, no writes persist (stage-then-commit).
|
|
99
|
+
- **--force is mandatory** when identifiers are detected. Never auto-redact without it.
|
|
100
|
+
- **Tests use `$env:KUSHI_GLOBAL_ROOT='.testtmp/.kushi-global'`.** Real `~/.kushi-global/` is user data.
|
|
101
|
+
- **Never modify project Evidence beyond the back-link.** No edits to the redacted lines in the source — only the global copy is redacted.
|
|
102
|
+
- **Provenance frontmatter required.** `promoted_from`, `promoted_at`, `redactions` are MANDATORY on the global copy.
|
|
103
|
+
|
|
104
|
+
## Stop conditions
|
|
105
|
+
|
|
106
|
+
- Project unresolved → exit 1, ask the user to verify cwd.
|
|
107
|
+
- Source page unresolved → exit 1.
|
|
108
|
+
- Identifier hits without `--force` → exit 2, print hits.
|
|
109
|
+
|
|
110
|
+
## Validation loop
|
|
111
|
+
|
|
112
|
+
1. Run `pwsh plugin/skills/self-check/run.ps1 -Targeted D40`.
|
|
113
|
+
2. Run `node --test src/promote.test.mjs`.
|
|
114
|
+
3. Fix any findings + re-run.
|
|
115
|
+
|
|
116
|
+
## References
|
|
117
|
+
|
|
118
|
+
- `../../instructions/global-wiki.instructions.md`
|
|
119
|
+
- `../../instructions/multi-wiki-routing.instructions.md`
|
|
120
|
+
- `../../instructions/schema-evolve.instructions.md`
|
|
121
|
+
- `../global-wiki/SKILL.md`
|
|
122
|
+
|
|
123
|
+
## Issue Recovery
|
|
124
|
+
|
|
125
|
+
If the identifier scan misses a customer pattern (false negative) or flags a non-identifier (false positive), fix the heuristic in `src/global-wiki.mjs::detectIdentifiers` first, add a regression case to `src/promote.test.mjs`, then re-run.
|