skillwiki 0.10.75 → 0.10.77

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.
@@ -3360,6 +3360,7 @@ function buildCliSurface() {
3360
3360
  program.command("project-page");
3361
3361
  program.command("write-preflight").option("--command <name>").option("--dirty-threshold <n>").option("--skip-dirty").option("--prior-artifact-file <path>").option("--prior-artifact-text <text>").option("--consecutive-no-decision <n>").option("--no-decision-threshold <n>").option("--human-allow").option("--mission-kind <kind>").option("--skip-mission").option("--project <slug>").option("--capture-day <date>").option("--capture-budget <n>").option("--severity <level>").option("--skip-budget").option("--checks <list>").option("--wiki <name>");
3362
3362
  program.command("mcp");
3363
+ program.command("mcp-auth");
3363
3364
  const graphCmd = program.commands.find((c) => c.name() === "graph");
3364
3365
  graphCmd.command("build").option("--out <path>").option("--wiki <name>");
3365
3366
  const vectorsCmd = program.commands.find((c) => c.name() === "vectors");
@@ -3436,6 +3437,8 @@ function buildCliSurface() {
3436
3437
  fleetCmd.command("validate");
3437
3438
  fleetCmd.command("context").option("--file <path>").option("--host-id <id>");
3438
3439
  fleetCmd.command("health").option("--file <path>").option("--host-id <id>").option("--json");
3440
+ const mcpAuth = program.commands.find((c) => c.name() === "mcp-auth");
3441
+ mcpAuth.command("issue-host").requiredOption("--host-id <id>").option("--map <path>").option("--write");
3439
3442
  const surface = /* @__PURE__ */ new Map();
3440
3443
  const rootFlags = new Set(program.options.map((o) => o.long ?? o.short).filter((f) => f != null));
3441
3444
  function walk(cmd, prefix, parentFlags) {
@@ -40,7 +40,7 @@ import {
40
40
  snapshotterAliasForLocalHost,
41
41
  toUndirectedWeighted,
42
42
  writeDotenv
43
- } from "./chunk-4XCBKPKD.js";
43
+ } from "./chunk-5XT6MBWA.js";
44
44
  import {
45
45
  atomicWriteText,
46
46
  prepareTypedPage
package/dist/cli.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  snapshotterHealthChecks,
51
51
  upsertIndexEntry,
52
52
  vectorIndexStatus
53
- } from "./chunk-WAUWBPIQ.js";
53
+ } from "./chunk-CLF6DZ6C.js";
54
54
  import {
55
55
  normalizeDistTag,
56
56
  readCache,
@@ -151,7 +151,7 @@ import {
151
151
  supersedeStaleReviewRequiredJournals,
152
152
  taxonomyCommentForPage,
153
153
  writeDotenv
154
- } from "./chunk-4XCBKPKD.js";
154
+ } from "./chunk-5XT6MBWA.js";
155
155
  import {
156
156
  assertTargetInsideVault,
157
157
  atomicWriteText,
@@ -10293,8 +10293,119 @@ async function postCommit(vault, exitCode) {
10293
10293
  clearLastOp(vault);
10294
10294
  }
10295
10295
 
10296
+ // src/commands/mcp-auth.ts
10297
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
10298
+
10299
+ // src/utils/mcp-token-map.ts
10300
+ import { createHash as createHash7, randomBytes } from "crypto";
10301
+ import yaml from "js-yaml";
10302
+ var HOST_ID_RE = /^[a-z][a-z0-9-]{1,62}$/;
10303
+ function parseMcpTokenMap(yamlText) {
10304
+ const parsed = yaml.load(yamlText);
10305
+ const map = /* @__PURE__ */ new Map();
10306
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
10307
+ return map;
10308
+ }
10309
+ const records = parsed;
10310
+ const nested = records.tokens;
10311
+ const source = nested && typeof nested === "object" && !Array.isArray(nested) ? nested : records;
10312
+ for (const [hash, hostId] of Object.entries(source)) {
10313
+ if (hash === "tokens") continue;
10314
+ if (typeof hostId !== "string" || hostId.length === 0) continue;
10315
+ const normalized = hash.trim().toLowerCase();
10316
+ if (!/^[0-9a-f]{64}$/.test(normalized)) continue;
10317
+ map.set(normalized, hostId);
10318
+ }
10319
+ return map;
10320
+ }
10321
+ function generateHostBearer(rng) {
10322
+ const bytes = (rng ?? (() => randomBytes(32)))();
10323
+ const raw = bytes.toString("base64url");
10324
+ const hashHex = createHash7("sha256").update(raw, "utf8").digest("hex");
10325
+ return { raw, hashHex };
10326
+ }
10327
+ function appendHostHash(yamlText, hashHex, hostId) {
10328
+ if (!HOST_ID_RE.test(hostId)) {
10329
+ return { error: "INVALID_HOST_ID" };
10330
+ }
10331
+ const map = parseMcpTokenMap(yamlText);
10332
+ const normalizedHash = hashHex.trim().toLowerCase();
10333
+ if ([...map.values()].includes(hostId)) {
10334
+ return { error: "DUPLICATE_HOST_ID" };
10335
+ }
10336
+ if (map.has(normalizedHash)) {
10337
+ return { error: "DUPLICATE_HASH" };
10338
+ }
10339
+ return { yaml: yamlText.replace(/\s*$/, "") + `
10340
+ ${normalizedHash}: ${hostId}
10341
+ ` };
10342
+ }
10343
+
10344
+ // src/commands/mcp-auth.ts
10345
+ function isEnoent(error) {
10346
+ return error.code === "ENOENT";
10347
+ }
10348
+ function preflight(error) {
10349
+ return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err(error) };
10350
+ }
10351
+ async function runMcpAuthIssueHost(input) {
10352
+ const isTty = input.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
10353
+ const readFile22 = input.readFile ?? readFileSync17;
10354
+ const writeFile10 = input.writeFile ?? writeFileSync8;
10355
+ const stderrWrite = input.stderrWrite ?? ((s) => {
10356
+ process.stderr.write(s);
10357
+ });
10358
+ const write = Boolean(input.write);
10359
+ const mapPath = input.mapPath;
10360
+ const hostId = input.hostId;
10361
+ if (!mapPath) return preflight("MAP_PATH_REQUIRED");
10362
+ if (!HOST_ID_RE.test(hostId)) return preflight("INVALID_HOST_ID");
10363
+ if (write && !isTty) return preflight("NO_TTY");
10364
+ let yamlText = "";
10365
+ try {
10366
+ yamlText = readFile22(mapPath, "utf8");
10367
+ } catch (error) {
10368
+ if (!isEnoent(error)) throw error;
10369
+ }
10370
+ const map = parseMcpTokenMap(yamlText);
10371
+ if ([...map.values()].includes(hostId)) return preflight("DUPLICATE_HOST_ID");
10372
+ if (!write) {
10373
+ return {
10374
+ exitCode: ExitCode.OK,
10375
+ result: ok({
10376
+ host_id: hostId,
10377
+ hash_prefix: "",
10378
+ map_path: mapPath,
10379
+ wrote: false
10380
+ })
10381
+ };
10382
+ }
10383
+ const { raw, hashHex } = generateHostBearer(input.rng);
10384
+ const appended = appendHostHash(yamlText, hashHex, hostId);
10385
+ if ("error" in appended) return preflight(appended.error);
10386
+ try {
10387
+ writeFile10(mapPath, appended.yaml, { encoding: "utf8", mode: 416 });
10388
+ } catch (error) {
10389
+ if (isEnoent(error)) {
10390
+ return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND") };
10391
+ }
10392
+ throw error;
10393
+ }
10394
+ stderrWrite(`issued host_id=${hostId} copy once: ${raw}
10395
+ `);
10396
+ return {
10397
+ exitCode: ExitCode.OK,
10398
+ result: ok({
10399
+ host_id: hostId,
10400
+ hash_prefix: hashHex.slice(0, 8),
10401
+ map_path: mapPath,
10402
+ wrote: true
10403
+ })
10404
+ };
10405
+ }
10406
+
10296
10407
  // src/commands/write-preflight.ts
10297
- import { existsSync as existsSync15, readFileSync as readFileSync17, statSync as statSync5 } from "fs";
10408
+ import { existsSync as existsSync15, readFileSync as readFileSync18, statSync as statSync5 } from "fs";
10298
10409
  async function runWritePreflightCommand(input) {
10299
10410
  if (!existsSync15(input.vault) || !statSync5(input.vault).isDirectory()) {
10300
10411
  return {
@@ -10310,7 +10421,7 @@ async function runWritePreflightCommand(input) {
10310
10421
  result: err("FILE_NOT_FOUND", { path: input.priorArtifactFile })
10311
10422
  };
10312
10423
  }
10313
- priorText = readFileSync17(input.priorArtifactFile, "utf8");
10424
+ priorText = readFileSync18(input.priorArtifactFile, "utf8");
10314
10425
  }
10315
10426
  const checkList = input.checks ? input.checks.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
10316
10427
  const result = runWritePreflight({
@@ -10431,7 +10542,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
10431
10542
  if (dirty) {
10432
10543
  return emit(dirty, void 0, { postCommit: false });
10433
10544
  }
10434
- const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-KCFPPZNF.js");
10545
+ const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-LSG2Y24X.js");
10435
10546
  const run = await runManagedWriteTransaction2({
10436
10547
  vault,
10437
10548
  command,
@@ -11656,6 +11767,15 @@ vectorsCmd.command("prune-page [vault]").description("prune deleted pages from t
11656
11767
  program.command("mcp").description("start stdio Model Context Protocol server (read-only vault tools)").action(async () => {
11657
11768
  await runSkillwikiMcpStdio();
11658
11769
  });
11770
+ var mcpAuthCmd = program.command("mcp-auth").description("attended HTTP MCP host-id bearer issuance (metal)");
11771
+ mcpAuthCmd.command("issue-host").description("append a host-id hash to the metal map; print raw once on a TTY").requiredOption("--host-id <id>", "host identity to bind").option("--map <path>", "hash map file (defaults to SKILLWIKI_MCP_TOKEN_MAP)").option("--write", "append the hash (default is dry-run)", false).action(async (opts) => {
11772
+ const mapPath = opts.map || process.env.SKILLWIKI_MCP_TOKEN_MAP || "";
11773
+ emit(await runMcpAuthIssueHost({
11774
+ hostId: String(opts.hostId),
11775
+ mapPath,
11776
+ write: !!opts.write
11777
+ }));
11778
+ });
11659
11779
  for (const w of getDeprecatedWarnings(process.env.HOME ?? "")) {
11660
11780
  process.stderr.write(w + "\n");
11661
11781
  }
@@ -6,7 +6,7 @@ import {
6
6
  runManagedWritePeerGate,
7
7
  runManagedWritePreflight,
8
8
  runManagedWriteTransaction
9
- } from "./chunk-4XCBKPKD.js";
9
+ } from "./chunk-5XT6MBWA.js";
10
10
  import "./chunk-BPJ5KWIT.js";
11
11
  import "./chunk-OMO45AHI.js";
12
12
  import "./chunk-HJ4ALQG6.js";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runSkillwikiMcpStdio
4
- } from "./chunk-WAUWBPIQ.js";
4
+ } from "./chunk-CLF6DZ6C.js";
5
5
  import "./chunk-7I2TPIV5.js";
6
6
  import "./chunk-KFEOMMWK.js";
7
- import "./chunk-4XCBKPKD.js";
7
+ import "./chunk-5XT6MBWA.js";
8
8
  import "./chunk-BPJ5KWIT.js";
9
9
  import "./chunk-NPTIYO2S.js";
10
10
  import "./chunk-OMO45AHI.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.75",
3
+ "version": "0.10.77",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "skillwiki": "dist/cli.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.75",
3
+ "version": "0.10.77",
4
4
  "skills": "./",
5
5
  "description": "Project-aware Karpathy-style knowledge base for Claude Code: 21 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp) backed by the deterministic `skillwiki` CLI.",
6
6
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.75",
3
+ "version": "0.10.77",
4
4
  "description": "Project-aware Karpathy-style knowledge base for Codex with 21 prompt-only skills backed by the deterministic skillwiki CLI.",
5
5
  "author": {
6
6
  "name": "karlorz",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.75",
3
+ "version": "0.10.77",
4
4
  "description": "Project-aware Karpathy-style knowledge base: 21 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp) backed by HTTP MCP wiki_capture.",
5
5
  "author": {
6
6
  "name": "karlorz"
@@ -20,6 +20,8 @@ You are a project workspace bootstrapper specializing in creating the `projects/
20
20
  3. Render README.md from template
21
21
  4. Update vault index.md and log.md
22
22
 
23
+ **Leaf-host rule (HTTP MCP):** If `$VAULT/.WIKI_GIT_FROZEN` exists, do not local-write. Bootstrap via MCP `wiki_workitem_write` (workspace families: `projects/{slug}/README.md`, `architecture/**`, `requirements/**`, `compound/**` — `.md` only; omit `base_sha256` on create). Use at most `wiki_log_append` for the log entry; never edit `index.md` locally on a leaf. If `wiki_workitem_write` is absent or the deployed server predates the workspace-family allowlist (`PATH_DENIED`), STOP — never rclone/wiki-push.
24
+
23
25
  **Execution Process:**
24
26
 
25
27
  1. **Resolve vault.** Run `skillwiki path`. If NO_VAULT_CONFIGURED, report failure and STOP.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.10.75",
3
+ "version": "0.10.77",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",
@@ -22,8 +22,15 @@ Standard four reads (vault SCHEMA, index, log) — no project context yet.
22
22
  4. Update vault `index.md` "Projects" section: add `- [[projects/{slug}]]`.
23
23
  5. Append vault `log.md` entry: "Project {slug} initialized."
24
24
 
25
+ ## Leaf hosts (HTTP MCP)
26
+ On a leaf host (vault has `.WIKI_GIT_FROZEN` or the HTTP MCP server is the writer), bootstrap goes through MCP instead of local file creation:
27
+ - Write `projects/{slug}/README.md` and any initial `requirements/` or `architecture/` markdown via `wiki_workitem_write` (CAS: omit `base_sha256` on create). Directories materialize implicitly with the first file.
28
+ - The `index.md` "Projects" line and the structural log stay projection/snapshotter-owned: use at most `wiki_log_append` for the init entry. Never edit `index.md` locally on a leaf.
29
+ - If `wiki_workitem_write` is absent from the live tool list or the deployed server predates the workspace-family allowlist (`PATH_DENIED`), STOP — do not local-write, rclone, or wiki-push.
30
+
25
31
  ## Stop conditions
26
32
  - `projects/{slug}/` already exists.
33
+ - Leaf host without a usable `wiki_workitem_write` (fail closed; capture the intent via `wiki_capture` instead).
27
34
 
28
35
  ## Forbidden
29
36
  - Modifying any other project's files.
@@ -22,8 +22,15 @@ Standard four reads (vault SCHEMA, index, log) — no project context yet.
22
22
  4. Update vault `index.md` "Projects" section: add `- [[projects/{slug}]]`.
23
23
  5. Append vault `log.md` entry: "Project {slug} initialized."
24
24
 
25
+ ## Leaf hosts (HTTP MCP)
26
+ On a leaf host (vault has `.WIKI_GIT_FROZEN` or the HTTP MCP server is the writer), bootstrap goes through MCP instead of local file creation:
27
+ - Write `projects/{slug}/README.md` and any initial `requirements/` or `architecture/` markdown via `wiki_workitem_write` (CAS: omit `base_sha256` on create). Directories materialize implicitly with the first file.
28
+ - The `index.md` "Projects" line and the structural log stay projection/snapshotter-owned: use at most `wiki_log_append` for the init entry. Never edit `index.md` locally on a leaf.
29
+ - If `wiki_workitem_write` is absent from the live tool list or the deployed server predates the workspace-family allowlist (`PATH_DENIED`), STOP — do not local-write, rclone, or wiki-push.
30
+
25
31
  ## Stop conditions
26
32
  - `projects/{slug}/` already exists.
33
+ - Leaf host without a usable `wiki_workitem_write` (fail closed; capture the intent via `wiki_capture` instead).
27
34
 
28
35
  ## Forbidden
29
36
  - Modifying any other project's files.
@@ -16,6 +16,8 @@ SkillWiki captures are HTTP MCP only (`type: http`). Claude/Grok use `SKILLWIKI_
16
16
  - Resolve the installed plugin root from `GROK_PLUGIN_ROOT`, falling back to `CLAUDE_PLUGIN_ROOT`, and run `python3 "$PLUGIN_ROOT/scripts/check_readiness.py" --apply --json` before the first SkillWiki MCP call.
17
17
  - **Cursor / Grok Bot:** the Cursor-native plugin requires `SKILLWIKI_MCP_TOKEN` under **Plugins → Configure**. It pins `https://wiki.karldigi.dev/mcp`. Grok Bot does not inherit Mac process env or `~/.cursor/mcp.json`. `failed_to_load` with no token box means this package is missing; after this package is installed, Configure is the token field (same pattern as grok-search).
18
18
  - `missing_prereq` means `SKILLWIKI_MCP_TOKEN` is absent from process environment; stop and ask for a bearer. Do not invent a stdio MCP.
19
+ - A new host (a machine that should write the wiki for the first time) needs an issued host-id bearer before handshake can pass. The operator runs `skillwiki mcp-auth issue-host --host-id <id> --write` on metal (TTY required). The client pastes the printed value into process env or host Configure. Do not auto-write `mcp.env`, `mcp.json`, or Grok `config.toml`. Do not invent a second admin skill. A local vault/FUSE mirror is optional.
20
+ - First-run order: install plugin/CLI → operator issues on metal → paste into process env or Configure → **new session** → `skillwiki doctor --check-mcp` → one write (`wiki_capture`, work-item write, or page publish).
19
21
  - `in_sync` means the probe has a usable URL/token decision.
20
22
  - A 401 is an MCP handshake failure, not a readiness-probe status. Report that the token is missing or rejected and stop.
21
23
  - Grok SessionStart cannot inject the parent MCP environment. A restart cannot supply a missing token.
@@ -33,9 +35,10 @@ On leaf hosts, wiki captures go through MCP. Do **not** write `raw/transcripts/`
33
35
  1. Call MCP `wiki_capture` with `kind` (`task` | `idea` | `bug` | `note`), `project`, `title`, and `content`. Optional `agent_note`.
34
36
  2. Call MCP `wiki_log_append` when a structural `log.md` line is needed. Pass append-only `content`. Do not rewrite log history.
35
37
  3. **Feature-detect work-item and page-publish tools**:
36
- - When the server advertises `wiki_workitem_write`: use it to create, mutate, or close work items under `projects/<slug>/work/**` or update `projects/<slug>/knowledge.md`. Pass `path`, `content`, and `base_sha256` of existing bytes (from `wiki_read_page` or local mirror). On `FILE_CHANGED`, re-read and retry once.
38
+ - When the server advertises `wiki_workitem_write`: use it to create, mutate, or close work items under `projects/<slug>/work/**` or update `projects/<slug>/knowledge.md`, and to save Layer-3 workspace markdown: `projects/<slug>/README.md`, `projects/<slug>/architecture/**/*.md`, `projects/<slug>/requirements/**/*.md`, `projects/<slug>/compound/**/*.md`. Pass `path`, `content`, and `base_sha256` of existing bytes (from `wiki_read_page` or local mirror). On `FILE_CHANGED`, re-read and retry once. Deployed servers that predate the workspace-family allowlist deny those paths — treat that `PATH_DENIED` as "server predates this release"; STOP, do not fall back.
37
39
  - When the server advertises `wiki_page_publish`: use it to publish typed Layer-2 pages (`entities/`, `concepts/`, `comparisons/`, `queries/`, `meta/`) using the same CAS protocol.
38
40
  - When those tools are **absent** from the live tool list (e.g. server is captures-only): do not call them or claim they exist. If `$VAULT/.WIKI_GIT_FROZEN` exists, fall back to capturing a close note via `wiki_capture` or STOP. Work-item close remains unavailable on the frozen leaf without `wiki_workitem_write`. Do not `git commit` / `wiki-push` against `~/wiki`.
41
+ 4. **`PATH_DENIED` means STOP.** Paths outside the allowlist (`projects/<slug>/history/**`, non-`.md` files such as `fleet.yaml` or `.canvas`, `AGENTS.md`/`CLAUDE.md`, raw edits, index/projection rebuilds) have no agent write path over MCP. wiki-push / `rclone copy` is **not** an agent writer: it bypasses the daemon working copy, so `wiki_read_page` cannot see those bytes until the sg01 snapshot. Never report an S3-only copy as "saved to wiki". Capture the blocked intent via `wiki_capture` and report the denial instead.
39
42
 
40
43
  ## Reads
41
44
 
@@ -171,6 +171,7 @@ If the vault has `.WIKI_GIT_FROZEN`:
171
171
  |---|---|---|
172
172
  | Capture note/idea/bug/task | Yes | HTTP MCP `wiki_capture` / `wiki_log_append` |
173
173
  | Close or mutate a work item (`projects/*/work/**`, `knowledge.md`) | Conditional | If live MCP tools include `wiki_workitem_write`, mutate/close via MCP CAS; if absent, capture a close note via MCP `wiki_capture` or STOP. Never local-write. |
174
+ | Save project workspace file (`architecture/`, `README.md`, `requirements/`, `compound/` — `.md` only) | Conditional | Via `wiki_workitem_write` CAS. Feature-detect: if the tool is absent or the deployed server predates the workspace-family allowlist (`PATH_DENIED`), STOP. Never rclone/wiki-push as a fallback writer. |
174
175
  | Publish typed Layer-2 page (`concepts/`, `queries/`, etc.) | Conditional | If live MCP tools include `wiki_page_publish`, publish via MCP CAS; if absent, STOP. Do not run local `skillwiki page publish`. |
175
176
  | `wiki-sync` push/commit | **No** | Git fail-closed. GitHub is sg01 `wiki-snapshot`. |
176
177
  | Read local `~/wiki` | Yes | Mirror reads only |
@@ -242,11 +243,11 @@ for code changes.
242
243
 
243
244
  ## CLI Backbone
244
245
  All skills are backed by the `skillwiki` CLI — a deterministic tool with no LLM calls. It handles path resolution, config management, validation, health reporting, and linting. Skills invoke it via Bash for the mechanical parts and use the active agent for the creative parts.
245
- Key CLI subcommands: `init`, `health`, `lint`, `config`, `doctor`, `path`, `lang`, `install`, `fleet context`, `fleet validate`, `graph build`, `query`, `vectors rebuild`, `vectors status`, `sources pending`, `sources compile`, `sources review`, `sources reviews`, `sources disposition`, `sources dispose`, `archive`, `remove`, `drift`, `dedup`, `compound`, `tag-sync`, `tag reconcile`, `page publish`, `sync status`, `seed`, `stale`, `claim`, `claims audit`, `observe`, `canvas generate`, `mcp`.
246
+ Key CLI subcommands: `init`, `health`, `lint`, `config`, `doctor`, `path`, `lang`, `install`, `fleet context`, `fleet validate`, `graph build`, `query`, `vectors rebuild`, `vectors status`, `sources pending`, `sources compile`, `sources review`, `sources reviews`, `sources disposition`, `sources dispose`, `archive`, `remove`, `drift`, `dedup`, `compound`, `tag-sync`, `tag reconcile`, `page publish`, `sync status`, `seed`, `stale`, `claim`, `claims audit`, `observe`, `canvas generate`, `mcp`, `mcp-auth`.
246
247
  Optional read-only MCP (`skillwiki mcp`) exposes pending/compile/review list tools. Do not use MCP for compile claim, publish, or review writes.
247
248
  `skillwiki claim` binds a transcript to a work item only through an exact `raw/transcripts/...` path in `source:` / `sources:` / `closes:`. A `--project` that contradicts the capture's explicit project is rejected. `skillwiki stale --project` uses exact normalized slugs, not substring matching. `skillwiki claims audit` is the read-only integrity report for duplicate, malformed, dangling, cross-project, and unbacked claims; it never rewrites captures or work items.
248
249
 
249
- Run `skillwiki health <vault> --out /tmp/skillwiki-health.json --no-fail` for a bounded whole-system report that includes the nonblocking source-lifecycle backlog. Pending captures are informational and do not make health fail. Run `skillwiki lint <vault> --summary` for lint-only bucket counts with capped examples and details commands. Run `skillwiki doctor` to diagnose setup/runtime issues only, including HTTP MCP URL/auth presence and the frozen-leaf write path. Pass `--check-mcp` for a live initialize handshake and pin/tool-list lag; the default doctor path does not contact HTTP MCP. There is no second MCP admin skill. Run `skillwiki config list` to see current configuration.
250
+ Run `skillwiki health <vault> --out /tmp/skillwiki-health.json --no-fail` for a bounded whole-system report that includes the nonblocking source-lifecycle backlog. Pending captures are informational and do not make health fail. Run `skillwiki lint <vault> --summary` for lint-only bucket counts with capped examples and details commands. Run `skillwiki doctor` to diagnose setup/runtime issues only, including HTTP MCP URL/auth presence and the frozen-leaf write path. Pass `--check-mcp` for a live initialize handshake and pin/tool-list lag; the default doctor path does not contact HTTP MCP. New hosts need an issued host-id bearer from metal `skillwiki mcp-auth issue-host` before handshake can pass. There is no second MCP admin skill. Run `skillwiki config list` to see current configuration.
250
251
 
251
252
  ## Runtime Host Context and Fleet Freshness
252
253
  Resolve the active project vault with `skillwiki path` first. Then pass that exact path to `skillwiki --human fleet context <vault>` for host identity and safety guidance. `fleet context` is authoritative for host identity. It overrides stale injected SessionStart context, remembered workspace context, and prior conversation summaries. `fleet context` is local and network-free; it reports `identity_status`, resolver trace, warnings, and the fact that remote freshness was not checked.
@@ -55,7 +55,7 @@ separate concerns.
55
55
 
56
56
  ## Fail-Closed Boundary
57
57
 
58
- Never write typed pages, `index.md`, or `log.md` directly. On leaf hosts, captures use HTTP MCP (`wiki_capture`), never local `raw/transcripts` or `log.md` writes. Never bare `rm` or `git rm` as a fleet delete (snapshot resurrects from S3). Never auto `npm install -g skillwiki` in headless/goal/satellite sessions. If `skillwiki page publish --help` is unavailable, fail closed.
58
+ Never write typed pages, `index.md`, or `log.md` directly. On leaf hosts, captures use HTTP MCP (`wiki_capture`), never local `raw/transcripts` or `log.md` writes. Project workspace saves (`projects/<slug>/README.md`, `architecture/`, `requirements/`, `compound/` — `.md` only) go through MCP `wiki_workitem_write` CAS; feature-detect and STOP if the tool is absent or the deployed server predates the workspace-family allowlist (`PATH_DENIED`). wiki-push / rclone is never an agent writer — an S3-only copy is invisible to `wiki_read_page` until the sg01 snapshot; never report it as "saved to wiki". Never bare `rm` or `git rm` as a fleet delete (snapshot resurrects from S3). Never auto `npm install -g skillwiki` in headless/goal/satellite sessions. If `skillwiki page publish --help` is unavailable, fail closed.
59
59
 
60
60
  ## Sensitive Content
61
61
 
@@ -16,6 +16,8 @@ SkillWiki captures are HTTP MCP only (`type: http`). Claude/Grok use `SKILLWIKI_
16
16
  - Resolve the installed plugin root from `GROK_PLUGIN_ROOT`, falling back to `CLAUDE_PLUGIN_ROOT`, and run `python3 "$PLUGIN_ROOT/scripts/check_readiness.py" --apply --json` before the first SkillWiki MCP call.
17
17
  - **Cursor / Grok Bot:** the Cursor-native plugin requires `SKILLWIKI_MCP_TOKEN` under **Plugins → Configure**. It pins `https://wiki.karldigi.dev/mcp`. Grok Bot does not inherit Mac process env or `~/.cursor/mcp.json`. `failed_to_load` with no token box means this package is missing; after this package is installed, Configure is the token field (same pattern as grok-search).
18
18
  - `missing_prereq` means `SKILLWIKI_MCP_TOKEN` is absent from process environment; stop and ask for a bearer. Do not invent a stdio MCP.
19
+ - A new host (a machine that should write the wiki for the first time) needs an issued host-id bearer before handshake can pass. The operator runs `skillwiki mcp-auth issue-host --host-id <id> --write` on metal (TTY required). The client pastes the printed value into process env or host Configure. Do not auto-write `mcp.env`, `mcp.json`, or Grok `config.toml`. Do not invent a second admin skill. A local vault/FUSE mirror is optional.
20
+ - First-run order: install plugin/CLI → operator issues on metal → paste into process env or Configure → **new session** → `skillwiki doctor --check-mcp` → one write (`wiki_capture`, work-item write, or page publish).
19
21
  - `in_sync` means the probe has a usable URL/token decision.
20
22
  - A 401 is an MCP handshake failure, not a readiness-probe status. Report that the token is missing or rejected and stop.
21
23
  - Grok SessionStart cannot inject the parent MCP environment. A restart cannot supply a missing token.
@@ -33,9 +35,10 @@ On leaf hosts, wiki captures go through MCP. Do **not** write `raw/transcripts/`
33
35
  1. Call MCP `wiki_capture` with `kind` (`task` | `idea` | `bug` | `note`), `project`, `title`, and `content`. Optional `agent_note`.
34
36
  2. Call MCP `wiki_log_append` when a structural `log.md` line is needed. Pass append-only `content`. Do not rewrite log history.
35
37
  3. **Feature-detect work-item and page-publish tools**:
36
- - When the server advertises `wiki_workitem_write`: use it to create, mutate, or close work items under `projects/<slug>/work/**` or update `projects/<slug>/knowledge.md`. Pass `path`, `content`, and `base_sha256` of existing bytes (from `wiki_read_page` or local mirror). On `FILE_CHANGED`, re-read and retry once.
38
+ - When the server advertises `wiki_workitem_write`: use it to create, mutate, or close work items under `projects/<slug>/work/**` or update `projects/<slug>/knowledge.md`, and to save Layer-3 workspace markdown: `projects/<slug>/README.md`, `projects/<slug>/architecture/**/*.md`, `projects/<slug>/requirements/**/*.md`, `projects/<slug>/compound/**/*.md`. Pass `path`, `content`, and `base_sha256` of existing bytes (from `wiki_read_page` or local mirror). On `FILE_CHANGED`, re-read and retry once. Deployed servers that predate the workspace-family allowlist deny those paths — treat that `PATH_DENIED` as "server predates this release"; STOP, do not fall back.
37
39
  - When the server advertises `wiki_page_publish`: use it to publish typed Layer-2 pages (`entities/`, `concepts/`, `comparisons/`, `queries/`, `meta/`) using the same CAS protocol.
38
40
  - When those tools are **absent** from the live tool list (e.g. server is captures-only): do not call them or claim they exist. If `$VAULT/.WIKI_GIT_FROZEN` exists, fall back to capturing a close note via `wiki_capture` or STOP. Work-item close remains unavailable on the frozen leaf without `wiki_workitem_write`. Do not `git commit` / `wiki-push` against `~/wiki`.
41
+ 4. **`PATH_DENIED` means STOP.** Paths outside the allowlist (`projects/<slug>/history/**`, non-`.md` files such as `fleet.yaml` or `.canvas`, `AGENTS.md`/`CLAUDE.md`, raw edits, index/projection rebuilds) have no agent write path over MCP. wiki-push / `rclone copy` is **not** an agent writer: it bypasses the daemon working copy, so `wiki_read_page` cannot see those bytes until the sg01 snapshot. Never report an S3-only copy as "saved to wiki". Capture the blocked intent via `wiki_capture` and report the denial instead.
39
42
 
40
43
  ## Reads
41
44
 
@@ -171,6 +171,7 @@ If the vault has `.WIKI_GIT_FROZEN`:
171
171
  |---|---|---|
172
172
  | Capture note/idea/bug/task | Yes | HTTP MCP `wiki_capture` / `wiki_log_append` |
173
173
  | Close or mutate a work item (`projects/*/work/**`, `knowledge.md`) | Conditional | If live MCP tools include `wiki_workitem_write`, mutate/close via MCP CAS; if absent, capture a close note via MCP `wiki_capture` or STOP. Never local-write. |
174
+ | Save project workspace file (`architecture/`, `README.md`, `requirements/`, `compound/` — `.md` only) | Conditional | Via `wiki_workitem_write` CAS. Feature-detect: if the tool is absent or the deployed server predates the workspace-family allowlist (`PATH_DENIED`), STOP. Never rclone/wiki-push as a fallback writer. |
174
175
  | Publish typed Layer-2 page (`concepts/`, `queries/`, etc.) | Conditional | If live MCP tools include `wiki_page_publish`, publish via MCP CAS; if absent, STOP. Do not run local `skillwiki page publish`. |
175
176
  | `wiki-sync` push/commit | **No** | Git fail-closed. GitHub is sg01 `wiki-snapshot`. |
176
177
  | Read local `~/wiki` | Yes | Mirror reads only |
@@ -242,11 +243,11 @@ for code changes.
242
243
 
243
244
  ## CLI Backbone
244
245
  All skills are backed by the `skillwiki` CLI — a deterministic tool with no LLM calls. It handles path resolution, config management, validation, health reporting, and linting. Skills invoke it via Bash for the mechanical parts and use the active agent for the creative parts.
245
- Key CLI subcommands: `init`, `health`, `lint`, `config`, `doctor`, `path`, `lang`, `install`, `fleet context`, `fleet validate`, `graph build`, `query`, `vectors rebuild`, `vectors status`, `sources pending`, `sources compile`, `sources review`, `sources reviews`, `sources disposition`, `sources dispose`, `archive`, `remove`, `drift`, `dedup`, `compound`, `tag-sync`, `tag reconcile`, `page publish`, `sync status`, `seed`, `stale`, `claim`, `claims audit`, `observe`, `canvas generate`, `mcp`.
246
+ Key CLI subcommands: `init`, `health`, `lint`, `config`, `doctor`, `path`, `lang`, `install`, `fleet context`, `fleet validate`, `graph build`, `query`, `vectors rebuild`, `vectors status`, `sources pending`, `sources compile`, `sources review`, `sources reviews`, `sources disposition`, `sources dispose`, `archive`, `remove`, `drift`, `dedup`, `compound`, `tag-sync`, `tag reconcile`, `page publish`, `sync status`, `seed`, `stale`, `claim`, `claims audit`, `observe`, `canvas generate`, `mcp`, `mcp-auth`.
246
247
  Optional read-only MCP (`skillwiki mcp`) exposes pending/compile/review list tools. Do not use MCP for compile claim, publish, or review writes.
247
248
  `skillwiki claim` binds a transcript to a work item only through an exact `raw/transcripts/...` path in `source:` / `sources:` / `closes:`. A `--project` that contradicts the capture's explicit project is rejected. `skillwiki stale --project` uses exact normalized slugs, not substring matching. `skillwiki claims audit` is the read-only integrity report for duplicate, malformed, dangling, cross-project, and unbacked claims; it never rewrites captures or work items.
248
249
 
249
- Run `skillwiki health <vault> --out /tmp/skillwiki-health.json --no-fail` for a bounded whole-system report that includes the nonblocking source-lifecycle backlog. Pending captures are informational and do not make health fail. Run `skillwiki lint <vault> --summary` for lint-only bucket counts with capped examples and details commands. Run `skillwiki doctor` to diagnose setup/runtime issues only, including HTTP MCP URL/auth presence and the frozen-leaf write path. Pass `--check-mcp` for a live initialize handshake and pin/tool-list lag; the default doctor path does not contact HTTP MCP. There is no second MCP admin skill. Run `skillwiki config list` to see current configuration.
250
+ Run `skillwiki health <vault> --out /tmp/skillwiki-health.json --no-fail` for a bounded whole-system report that includes the nonblocking source-lifecycle backlog. Pending captures are informational and do not make health fail. Run `skillwiki lint <vault> --summary` for lint-only bucket counts with capped examples and details commands. Run `skillwiki doctor` to diagnose setup/runtime issues only, including HTTP MCP URL/auth presence and the frozen-leaf write path. Pass `--check-mcp` for a live initialize handshake and pin/tool-list lag; the default doctor path does not contact HTTP MCP. New hosts need an issued host-id bearer from metal `skillwiki mcp-auth issue-host` before handshake can pass. There is no second MCP admin skill. Run `skillwiki config list` to see current configuration.
250
251
 
251
252
  ## Runtime Host Context and Fleet Freshness
252
253
  Resolve the active project vault with `skillwiki path` first. Then pass that exact path to `skillwiki --human fleet context <vault>` for host identity and safety guidance. `fleet context` is authoritative for host identity. It overrides stale injected SessionStart context, remembered workspace context, and prior conversation summaries. `fleet context` is local and network-free; it reports `identity_status`, resolver trace, warnings, and the fact that remote freshness was not checked.
@@ -55,7 +55,7 @@ separate concerns.
55
55
 
56
56
  ## Fail-Closed Boundary
57
57
 
58
- Never write typed pages, `index.md`, or `log.md` directly. On leaf hosts, captures use HTTP MCP (`wiki_capture`), never local `raw/transcripts` or `log.md` writes. Never bare `rm` or `git rm` as a fleet delete (snapshot resurrects from S3). Never auto `npm install -g skillwiki` in headless/goal/satellite sessions. If `skillwiki page publish --help` is unavailable, fail closed.
58
+ Never write typed pages, `index.md`, or `log.md` directly. On leaf hosts, captures use HTTP MCP (`wiki_capture`), never local `raw/transcripts` or `log.md` writes. Project workspace saves (`projects/<slug>/README.md`, `architecture/`, `requirements/`, `compound/` — `.md` only) go through MCP `wiki_workitem_write` CAS; feature-detect and STOP if the tool is absent or the deployed server predates the workspace-family allowlist (`PATH_DENIED`). wiki-push / rclone is never an agent writer — an S3-only copy is invisible to `wiki_read_page` until the sg01 snapshot; never report it as "saved to wiki". Never bare `rm` or `git rm` as a fleet delete (snapshot resurrects from S3). Never auto `npm install -g skillwiki` in headless/goal/satellite sessions. If `skillwiki page publish --help` is unavailable, fail closed.
59
59
 
60
60
  ## Sensitive Content
61
61