From 0351a412fafce04eb88359f13c182621ef6f9489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kope=C4=87?= Date: Thu, 6 Aug 2026 14:28:29 +0200 Subject: [PATCH] Expand cascade-knowledge-base plugin with new skills and richer workflows Add ckb-ingest, ckb-lint, ckb-retrieve, ckb-teach-me, ckb-upgrade, and ckb-index-external skills; update ckb-init's default skill set and ckb-sync-changes to handle missing origin remotes. Co-Authored-By: Claude Sonnet 5 --- .../skills/ckb-export-okf/SKILL.md | 11 +- .../skills/ckb-export-starlight/SKILL.md | 5 + .../scripts/export_starlight.py | 13 + .../skills/ckb-index-external/SKILL.md | 437 ++++++++++++++++++ .../skills/ckb-ingest/SKILL.md | 195 ++++++++ .../skills/ckb-init/SKILL.md | 165 +++++-- .../skills/ckb-lint/SKILL.md | 194 ++++++++ .../skills/ckb-onboard-me/SKILL.md | 5 + .../skills/ckb-project-summary/SKILL.md | 5 + .../skills/ckb-quiz/SKILL.md | 5 + .../skills/ckb-retrieve/SKILL.md | 284 ++++++++++++ .../skills/ckb-sync-changes/SKILL.md | 64 ++- .../skills/ckb-teach-me/SKILL.md | 327 +++++++++++++ .../skills/ckb-upgrade/SKILL.md | 390 ++++++++++++++++ 14 files changed, 2046 insertions(+), 54 deletions(-) create mode 100644 plugins/cascade-knowledge-base/skills/ckb-index-external/SKILL.md create mode 100644 plugins/cascade-knowledge-base/skills/ckb-ingest/SKILL.md create mode 100644 plugins/cascade-knowledge-base/skills/ckb-lint/SKILL.md create mode 100644 plugins/cascade-knowledge-base/skills/ckb-retrieve/SKILL.md create mode 100644 plugins/cascade-knowledge-base/skills/ckb-teach-me/SKILL.md create mode 100644 plugins/cascade-knowledge-base/skills/ckb-upgrade/SKILL.md diff --git a/plugins/cascade-knowledge-base/skills/ckb-export-okf/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-export-okf/SKILL.md index a5aaac2..cfa9c24 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-export-okf/SKILL.md +++ b/plugins/cascade-knowledge-base/skills/ckb-export-okf/SKILL.md @@ -134,8 +134,8 @@ the report rather than silently patching the export. ### Step 7 — Validate the output bundle Before reporting done, re-check the *generated* `outputs/okf/` bundle -against OKF's own conformance criteria (the same shape of check `CLAUDE.md` -§5 step 1 runs against the source wiki): +against OKF's own conformance criteria (the same shape of conformance check +`ckb-lint` runs against the source wiki): - Every non-reserved `.md` file has frontmatter with a non-empty `type`. - The root `index.md`'s frontmatter contains only `okf_version` (or is @@ -168,7 +168,7 @@ Tell the user: spec-valid, don't skip the directory entirely. - **A wiki page missing `type`:** per Step 3, use `type: unknown` and flag it in the report — this indicates the source wiki itself failed lint's - conformance check (see `CLAUDE.md` §5 step 1), which is worth surfacing + conformance check, which is worth surfacing to the user rather than quietly masking it in the export. - **A future `wiki/archived/` directory:** export it like any other subdirectory (mirror the structure, apply the same per-file rules) — @@ -179,3 +179,8 @@ Tell the user: arbitrary ordering when listing directory entries), sort filenames alphabetically wherever you're generating a bullet list or walking a directory, so re-runs are stable. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-export-starlight/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-export-starlight/SKILL.md index df1dd12..2e2af27 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-export-starlight/SKILL.md +++ b/plugins/cascade-knowledge-base/skills/ckb-export-starlight/SKILL.md @@ -145,3 +145,8 @@ The script prints, and you should summarize back to the user: - **A wiki page with no H1:** falls back to a slugified filename as the title (e.g. `foo-bar.md` → "Foo Bar"), same fallback rule `ckb-export-okf` uses. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-export-starlight/scripts/export_starlight.py b/plugins/cascade-knowledge-base/skills/ckb-export-starlight/scripts/export_starlight.py index 1713314..3016a7e 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-export-starlight/scripts/export_starlight.py +++ b/plugins/cascade-knowledge-base/skills/ckb-export-starlight/scripts/export_starlight.py @@ -1,4 +1,17 @@ #!/usr/bin/env python3 +# Copyright 2026 Michał Kopeć +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. """Export wiki/ into an Astro + Starlight-consumable form at outputs/starlight/. Usage: diff --git a/plugins/cascade-knowledge-base/skills/ckb-index-external/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-index-external/SKILL.md new file mode 100644 index 0000000..2efcf95 --- /dev/null +++ b/plugins/cascade-knowledge-base/skills/ckb-index-external/SKILL.md @@ -0,0 +1,437 @@ +--- +name: ckb-index-external +description: Walk every connector-backed libs// (identified by a source.yaml declaring a live external source — SharePoint, Google Drive, a plain URL, or another connector) and build/refresh a self-contained generated index for it — index.md/entities/graph/log.md, mirroring wiki/'s own shape but scoped entirely to that one connector. Indexing goes beyond one page per document: for every document found, it also extracts the people, organizations, projects, decisions, systems, and processes that document actually discusses into their own thin, pointer-style entity pages (evidence back to the specific documents that mention them, not a second copy of wiki/'s synthesis), so the index supports "what do we know about X / what's the process for Y" lookups, not just "what documents exist at this source". The index can optionally be published to (and fetched from) a shared location — a git repo or a shared resource — declared in source.yaml, so most users just read an already-built index instead of re-scanning the live source. Read vs. write access to a given source is a per-user, local-only setting (libs//source.local.yaml, gitignored) — read-only by default, so one or two designated admins can maintain a source for everyone else. Never touches wiki/, never touches source.yaml, never touches a git-copy lib. Use when the user says "index external sources", "index libs", "refresh the external index", or "scan the SharePoint/Drive folder". This is the on-demand external-source workflow routed by CLAUDE.md/AGENTS.md, distinct from `ckb-ingest` (which processes raw/inbox/ into wiki/) and from a plain git-copy libs// (a frozen clone, never touched by any skill). +--- + +# Index external sources skill + +## Purpose + +Give `libs//` a second population mode alongside the existing +git-copy one: a `libs//source.yaml` declares a *live* external +source — a SharePoint folder, a Google Drive folder, a plain URL, or +another connector — that the user doesn't want to fully mirror locally. +This skill walks that source and builds a small, self-contained index of +what's there, using the same `index.md`/`graph`/`log.md` shape `wiki/` +already uses, rooted at `libs//` instead. + +The index holds two kinds of pages, and both matter for retrieval: + +- **Document pages** — one per source item found (one per email, one per + file, one per SharePoint page), the original design. These answer "what + exists at this source". +- **Entity and process pages** — one per person, organization, project, + decision, system, or named process that those documents actually + *discuss*, extracted the same way `ckb-ingest` extracts entities into + `wiki/`, but kept deliberately thin here: a `tldr` plus a list of which + document(s) mention it and what they say, not a full synthesis. These + answer "what do we know about X" without forcing whoever's asking to + read every document's `tldr` by hand looking for a name. A document-only + index is fine for browsing a source but too narrow for actually + retrieving information out of it — that's what this second pass fixes. + +This is deliberately **not** blended into the main `wiki/entities/` or +`wiki/graph/edges.json` — the generated index lives entirely inside its own +`libs//`, at the lowest cascade layer, the same way a git-cloned +KB's own files would. If something in it needs to override or correct what +the connector says, that's what writing the corrected version into `wiki/` +is for (cascade priority already covers that — `wiki/` always wins). Where +an extracted entity already has a full page in `wiki/entities/`, this +skill's own page for it stays thin and points there rather than +re-synthesizing — see Step 6. + +Two refinements on top of that base design: + +- **Shared, pre-built indexes.** `source.yaml` can declare *where the + already-built index lives* (a git repo, or a shared resource such as a + network path or another connector-reachable location). Every run checks + that location: if it already has an index, fetch it; if it doesn't yet, + a write-access user's run is what creates it there for the first time. + Either way, a read-only user just gets whatever's already there — they + never have to build the index from scratch themselves. +- **Read vs. write access, per user, per source.** Building/refreshing an + index from the live connector is gated by a **local, per-user** setting + (`libs//source.local.yaml`, never committed) — read-only by + default. This lets a team designate one or two people as the "admin" of + a given external source, while everyone else just consumes whatever + index the admin has already published, without needing their own + connector authorization or triggering redundant/conflicting rebuilds. + +This skill only ever writes within a connector-backed `libs//` (never +`source.yaml` itself, never a git-copy lib, never anything under `wiki/`) +— and it never touches this repo's own git remote; pushing the resulting +changes is a separate, explicit step (see Step 8). + +## Trigger phrases + +Use this skill when the user says: +- "Index external sources" +- "Index libs" +- "Refresh the external index" +- "Scan the SharePoint/Drive folder" (or similarly names a specific + connector) +- "Make me the admin for ``" / "give me write access to ``" + / "I don't want write access to `` anymore" — a lighter-weight + request that only touches that one source's `source.local.yaml` (see + Configuration below) and doesn't necessarily trigger a full re-index in + the same turn unless the user also asks for one. + +Do **not** use this skill for "Ingest" / "Sync the wiki" (that's +`ckb-ingest` — raw material into `wiki/`, unrelated to `libs/`), for +"Lint" (that's `ckb-lint`, which now also health-checks a connector's own +generated index, but doesn't build it in the first place), or for +answering a question against an index that already exists (that's +`ckb-retrieve`, which reads what this skill built and always verifies +against the underlying source before answering — this skill never answers +questions, only builds/refreshes the index). + +## Configuration + +### `libs//source.yaml` (shared, tracked in git, same for everyone) + +```yaml +connector: sharepoint # sharepoint | google_drive | web | custom — open string, not a fixed enum +location: "https://contoso.sharepoint.com/sites/Finance/Shared Documents/Reports" +description: "Finance team's shared reports folder" # optional + +refresh_interval_days: 7 # optional — how often a write-access run should rebuild this source, + # and the freshness_window_days stamped on its generated pages. + # Omit to use the default of 30. Tune per source: a busy folder + # that changes daily deserves a shorter window than a quarterly + # reports archive that barely moves. + +index: # optional — omit entirely for the original default: the index lives only + # here, in this repo, tracked by this repo's own git (nothing to fetch/publish) + store: git # git | shared — open string, where the built index is published to / fetched from + location: "https://github.com/org/finance-index-cache.git" # a git repo URL (store: git), or a + # filesystem/network path or connector-reachable location (store: shared) + ref: main # optional — branch, tag, or subpath hint within that store +``` + +### `libs//source.local.yaml` (per-user, per-machine, **never committed**) + +```yaml +access: write # write | read — defaults to read if this file is absent or the field is omitted +``` + +This file is intentionally **not** carved out of `.gitignore` — it stays +caught by the existing `libs/*/*` catch-all, exactly like any other +unlisted file inside a connector-backed `libs//`. It's local +machine/user state, the same category as a personal `.env` — never synced, +never reviewed by anyone else, and it's what makes "read vs. write" a +per-user decision rather than a shared one baked into `source.yaml`. + +Unlike `source.yaml`, this skill *may* create or edit `source.local.yaml` +on this user's behalf — but only when they explicitly ask to become (or +stop being) a given source's admin (e.g. "make me the admin for the +finance reports source" / "I don't want write access to X anymore"), never +as a side effect of just running "index external sources." + +## How to run this skill + +### Step 1 — Find connector-backed libs + +Scan `libs/*/` for a `source.yaml`. A `libs//` with one is +connector-backed and in scope; a `libs//` without one is a git-copy +lib and stays completely untouched by this skill. + +If no `libs//source.yaml` exists anywhere, tell the user there's +nothing to index yet and how to add one (a `source.yaml` with `connector` +and `location`), and stop — don't fabricate an index from nothing. + +### Step 2 — Read the local access setting + +Read `libs//source.local.yaml` if it exists. `access: write` means +this user is an admin for this one source; anything else (the field is +`read`, or the file doesn't exist at all) means read-only. This check is +**per connector-backed lib** — a user can be write-access for one source +and read-only for another. + +### Step 3 — Check the shared index store, and fetch it if it exists + +If `source.yaml` has an `index:` block, check whether `index.location` +already has a published index (per `index.store`: a `git` remote with +commits/a reachable ref, or a filesystem/network/`shared` location with +files already in it): +- **It exists** → fetch/pull it (`git pull`/clone for `git`, a plain file + copy for a filesystem/network `shared` path, or the matching connector + tool for a `shared` location that needs one) and use it to refresh + `libs//{index.md,entities/,graph/,log.md}`. Do this **regardless + of this user's access level** — reading the published index never + requires write access, and it's exactly what lets a read-only user skip + building anything themselves. +- **It's empty / nothing published yet** → there's nothing to fetch. Don't + treat this as an error; it's the normal first-time state before anyone + with write access has run this. Continue to Step 4 — whether that turns + into "create it" or "nothing to report" depends entirely on this user's + access level. + +If no `index:` block is configured at all, skip this check — the index (if +any exists yet) already lives directly in `libs//`, same as before. + +### Step 4 — Decide whether to build or refresh from the live connector + +This is the one place access level actually changes behavior: + +- **Read-only** (the common case, and the default for anyone who hasn't + set `access: write` locally): stop here, regardless of what Step 3 + found. Never touch the live connector on a read-only user's behalf. + - If Step 3 fetched something (or one already lived in `libs//` + with no `index:` block): report what it covers. + - If nothing exists anywhere yet (Step 3 found the shared store empty, + or there's no `index:` block and `libs//` is empty too): say so + plainly, and suggest asking whoever administers this source to run it, + or setting `access: write` locally if this user is meant to be that + admin. +- **Write access**: always continue to Step 5, whether Step 3 fetched an + existing index (refresh it) or found the store empty (build the very + first version from scratch) — the two cases are handled identically + from here on; Step 8 is what actually creates the remote copy either + way. + +Either way, compare the existing index's newest `last_updated` against +this source's `refresh_interval_days` (default 30) and say where it +stands. A read-only user needs to know they're reading a copy that's three +weeks past due so they can go ask the admin rather than quietly trusting +it; a write-access user is about to rebuild anyway, but "this was 40 days +stale" is worth saying, because a source that's routinely overdue is +either configured with too tight an interval or has nobody actually +maintaining it. Both are worth surfacing rather than silently correcting. + +### Step 5 — Resolve the connector and enumerate/summarize documents + +Resolve `connector` to whatever live tool is actually available this +session: +- `sharepoint` / a Microsoft-hosted location → search (`ToolSearch`) for a + connected Microsoft 365 MCP tool. +- `google_drive` → search for a connected Google Drive MCP tool. +- `web` / `custom` / anything else with a plain URL → `WebFetch`. + +If the needed connector isn't authorized in this session (per the current +MCP auth state), **don't fail the whole run** — tell the user which +connector needs authorizing (via claude.ai connector settings, or `claude +mcp`/`/mcp` for non-claude.ai servers), skip that source, and continue with +any others. + +For each document found at the location: +- Read enough content to write a real 1-2 sentence `tldr` when the + connector allows fetching content. +- If only metadata is available (listing only, no read access), say so + honestly in the `tldr` (e.g. "Metadata only — content not readable") and + set `confidence` low (e.g. 0.3) rather than fabricating a summary. + +Create/update one entity page per document at +`libs//entities/.md`: +```yaml +--- +type: document +resource: +tldr: ... +confidence: 0.3–0.9 # per the rule above +quality: ... +last_updated: YYYY-MM-DD +freshness_window_days: 30 # this source's refresh_interval_days, or 30 if unset — shorter than a + # typical wiki page, because external sources change without notice +retention: medium +--- +``` + +### Step 6 — Extract entities and processes mentioned within each document + +A document-only index tells a reader *what exists*, but not *what's known +about a given person, topic, or procedure* without reading every `tldr` by +hand. Close that gap the same way `ckb-ingest` extracts entities into +`wiki/`, but keep the result scoped and thin — this connector's own layer +is a retrieval index into its source documents, not a second knowledge +base competing with `wiki/`'s synthesis. + +For each document processed in Step 5, identify what it actually +*discusses*, not just what it *is*: named people, organizations, projects, +decisions, systems, and processes/procedures (e.g. "VDI access request +process", "candidate profile approval") mentioned in its content. Skip +this for a document that's purely about itself with nothing else +extractable (a bare calendar acceptance with no discussion, for instance) +— not every document yields additional pages. + +For each distinct entity/process found across the source's documents, +create or update one page at `libs//entities/.md`, +using the same slug convention `wiki/entities/` would use for that name +(so `damien-gultig.md`, not a date-prefixed slug — this is what keeps +entity-page filenames from colliding with document-page filenames, which +are always date-prefixed per Step 5): + +```yaml +--- +type: person | organization | project | decision | system | concept | ... # same open field as wiki/'s schema +resource: /wiki/entities/.md # OPTIONAL — only if a full page for this entity already exists in wiki/ +tldr: One sentence — who/what this is, and what these documents specifically show (not a full biography; + if wiki/ already has a full page, this tldr should say what these documents add, not restate it) +confidence: 0.3–0.9 +quality: ... +last_updated: YYYY-MM-DD +freshness_window_days: 30 # or this source's refresh_interval_days, if set +retention: medium +--- +``` + +Body: a short "Mentioned in" list, one bullet per document that discusses +this entity, linking to that document's own page +(`entities/.md`) with a one-line note of what that specific +document says — enough for `ckb-retrieve` (or a human) to know exactly +which document to open for the full context, without needing to re-derive +it from scratch. + +**If this entity already has a full page in `wiki/entities/`** (check the +cascade first, same as `ckb-ingest`'s Step 2), set `resource:` to that +page's path and keep this page's body to just the "Mentioned in" list — +don't re-synthesize what the wiki page already says. The wiki page remains +authoritative (cascade priority); this page's only job is pointing back to +*these specific documents* as additional evidence, which the wiki page may +not have cited yet. + +Record real relationships surfaced by a document between two entities +(`uses`, `depends_on`, `caused`, `contradicts`) as edges in +`libs//graph/edges.json`, same edge vocabulary `wiki/` uses. Also add +a `mentioned_in` edge from each entity to every document that discusses +it — this is what makes the graph a genuine index into the source +documents rather than just a bag of loose pages. + +### Step 7 — Update the hub page, entities index, graph, and log + +Create/update `libs//index.md` — the root routing page for this +connector, mirroring `wiki/index.md`'s own role: +```yaml +--- +type: external-source +resource: +tldr: One sentence — what this source is, how many documents were found, and how many entities/processes were extracted from them +last_updated: YYYY-MM-DD +--- +``` +followed by a short routing table pointing to `entities/index.md` and +`graph/index.md`. + +Update `libs//entities/index.md` as two sections, so both kinds of +page stay easy to find without conflating them: +```markdown +## Documents +- [](.md) — +... + +## Entities & Processes +- [](.md) — +... +``` +Same flat-bullet, no-frontmatter convention as `wiki/entities/index.md` +otherwise — this is just a two-heading variant of it, not a new format. + +Update `libs//graph/index.md` (same convention as +`wiki/graph/index.md`) to summarize both the `mentioned_in` document +coverage and any real entity-to-entity edges found. Log every +created/updated page in `libs//log.md`, same reverse-chronological +format as Rule B in `CLAUDE.md`/`AGENTS.md` — this log is independent of +`wiki/log.md`; **nothing under `wiki/` is touched by this skill at all.** + +### Step 8 — Publish, if this source has both write access and a configured index store + +If this user has `access: write` **and** `source.yaml` has an `index:` +block, push the refreshed `libs//{index.md,entities/,graph/,log.md}` +back out to `index.location` (`git push` for `store: git`, a file copy +back for a filesystem/network `store: shared` path, or the matching +connector tool for a `shared` location that needs one) — **every single +run**, not just the first one, so every other user's next fetch (Step 3) +picks up the update. This is exactly how a shared index gets created in +the first place: if Step 3 found the store empty, this step's push is what +populates it for the first time; there's no separate "initialize" action. + +If no `index:` block is configured, there's nothing external to publish; +the refreshed files staying inside this repo's own `libs//` (tracked +by this repo's own git) *is* the publish step, same as the original +default behavior. + +If this user is **read-only**, this step never runs — nothing is ever +pushed or copied to `index.location` (or, in the no-`index:`-block case, +nothing is even rebuilt in `libs//` to begin with). A read-only user +has, by construction, nothing of their own to save back — Step 4 already +stopped them before anything was built. + +### Step 9 — Remind to review and sync + +This is always the last step, every time this skill makes any change at +all. Close with a short reminder — do not sync or push anything yourself +here: + +> "External source indexing complete for `libs//` — see +> `libs//log.md` for the details. Please review the changes, and +> once you're happy with them, say 'sync changes' to commit and push them +> to `origin`." + +If nothing was actually indexed or fetched (no connector-backed libs +found, every source was skipped for lack of authorization, or every source +was read-only with nothing new to fetch), skip this reminder. + +## Edge cases + +- **No connector-backed `libs//` exists** — report that and explain + how to add one; don't touch anything. +- **`source.local.yaml` doesn't exist yet for a source** — treat as + read-only; this is the correct default, not a misconfiguration worth + flagging loudly. Mention once, briefly, how to become the admin + (`access: write` in that file) if the user seems to expect a rebuild. +- **Everyone is read-only and nothing has ever been published** — report + that clearly rather than silently doing nothing; this is the one case + worth flagging as a real gap (nobody can currently index this source). +- **Connector not authorized this session** — report which one and how to + authorize it (claude.ai connector settings / `claude mcp` / `/mcp`), + skip that source, keep going with the rest. Never ask the user for + tokens or callback URLs. +- **Fetching a published index (Step 3) fails or the remote is + unreachable** — report it and fall back to whatever's already cached + locally in `libs//` from a previous fetch, rather than blocking + the whole run; don't let a transient network issue block a read-only + user from seeing the last-known index. +- **Re-running against an already-indexed source** — refresh existing + document *and* entity/process pages in place (update + `tldr`/`last_updated`/`confidence`, add newly-seen `mentioned_in` edges); + never duplicate a document's or entity's page. +- **A previously-indexed document is no longer found at the source** — + don't delete its page. Update its `tldr` with a note ("No longer found + at source as of YYYY-MM-DD") and set `retention: low`, so the existing + `ckb-lint` retention sweep archives it naturally on a later pass — no new + archival mechanism needed. Leave any entity pages that cite it alone; + the citation is still historically accurate even if the document itself + is gone. +- **An extracted entity already has a full page in `wiki/entities/`** — + keep this connector-side page thin (evidence/`mentioned_in` pointers + only, `resource:` set to the wiki page) rather than re-deriving + everything the wiki page already says; that duplication is exactly what + the cascade design is meant to avoid. +- **A document is dense with names/topics and extracting every one would + produce dozens of near-duplicate pages** — extract what's clearly named + and substantively discussed (not every passing mention), and prefer + updating an existing entity page's "Mentioned in" list over creating a + marginal new one. Don't force artificial granularity just to maximize + page count. +- **A document yields no extractable entity beyond itself** — that's fine; + its Step 5 document page is the only page it produces. Not every + document needs to feed Step 6. +- **A source is very large** — cap what gets fully fetched/summarized in + one run and explicitly report what was skipped (e.g. "42 of ~300 + documents summarized this pass — re-run to continue"). Never silently + truncate while implying full coverage. +- **Write access but publishing (Step 8) conflicts with a newer version + someone else already pushed** — this is why Step 3 (fetch) always runs + first, even for write-access users: rebuild on top of the latest fetched + state rather than blindly overwriting it. If a real conflict still shows + up at publish time, report it rather than force-pushing over it. +- **`libs//` has both real content files and a `source.yaml`** — + ambiguous and out of scope for this skill to resolve; report it and stop + for that folder (this is the same case `ckb-lint`'s external-source + config check flags). +- **`source.yaml` is missing `connector` or `location`** — report it as + malformed and skip that source; don't guess at intent. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-ingest/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-ingest/SKILL.md new file mode 100644 index 0000000..ead6656 --- /dev/null +++ b/plugins/cascade-knowledge-base/skills/ckb-ingest/SKILL.md @@ -0,0 +1,195 @@ +--- +name: ckb-ingest +description: Process raw/inbox/ (or raw/ directly if the inbox is empty) into the structured wiki/ — consult the cascade, extract typed entities and relationships, synthesize frontmatted pages, cross-link them, update the index and log, then remind the user to review and sync to origin. Use when the user says "Ingest", "Sync the wiki", or "Update the Wiki". This is the content-level workflow routed by CLAUDE.md/AGENTS.md, distinct from the git-level `ckb-sync-changes` skill (which reconciles this repo's own history with its `origin` remote and does no wiki synthesis at all). +--- + +# Ingest skill + +## Purpose + +Turn raw, unstructured material in `raw/inbox/` (notes, links, pasted text, +scratch files) into the local, mutable, structured `wiki/` — the top layer +of the cascade that overlays read-only upstream KBs in `linked/` and +`libs/`. This is the primary way the wiki grows. It is implemented as a +skill (rather than living inline in `CLAUDE.md`/`AGENTS.md`) so the full +ingestion procedure only loads into context when actually invoked. + +This skill only ever writes to `wiki/` (and moves processed files within +`raw/`). It never touches `linked/` or `libs/` — those are immutable +upstream sources of truth — and it never touches this repo's own git +remote; pushing the resulting changes is a separate, explicit step (see +Step 7). + +## Trigger phrases + +Use this skill when the user says: +- "Ingest" +- "Sync the wiki" +- "Update the wiki" + +Do **not** use this skill for "sync changes", "sync with git/origin", or +"reconcile git" — those are git-level operations with nothing to do with +wiki content, handled by the `ckb-sync-changes` skill instead (see +`.agents/skills/ckb-sync-changes/SKILL.md`). This skill and that one are +deliberately separate: this one turns raw material into wiki pages; that +one commits/pulls/pushes whatever is currently on disk, wiki changes +included. + +## How to run this skill + +### Step 1 — Process the inbox + +Scan `raw/inbox/` for new material. After ingesting each item, move it to +`raw/archive//`, where the date is today's ingestion date +(create the dated folder if it doesn't exist yet). + +If `raw/inbox/` is empty, scan `raw/` directly instead — excluding +`raw/archive/`, which holds material already processed by a previous +ingest. + +### Step 2 — Consult the cascade + +Before writing anything, check whether the entity already exists: local +`wiki/` first, then each `linked//`, then each `libs//` +(alphabetical within each layer). The local `wiki/` always wins — upstream +content is informative context, but it can be overridden locally rather +than treated as final. + +### Step 3 — Extract entities + +Identify typed entities in the source material — people, projects, +libraries, concepts, systems. Create entity pages at +`wiki/entities/.md` if they don't already exist. Record typed +relationships between entities — `uses`, `depends_on`, `caused`, +`contradicts`, `supersedes` — as edge data in `wiki/graph/edges.json`. + +Also record `has_expertise_in` and `owns` edges when the material actually +evidences them: `has_expertise_in` when a person demonstrably answers +questions or explains decisions on a topic, `owns` when they hold +declared responsibility for a system, area, or decision. These are what +make "who knows about X" and "who owns X" answerable as a direct graph +lookup instead of a full-text guess (see `ckb-retrieve` Step 3). Record +them only from demonstrated evidence — someone being present in a meeting +or cc'd on a thread is not expertise, and don't infer ownership from job +title alone. Both are optional, like every other edge type; an absent +edge is better than a fabricated one. + +For recurring teams, clients, systems, or initiatives, consider whether a +plain project scope page under `wiki/projects/.md` would make future +queries easier to route. A scope page should list when to use it, included +wiki/entity/source paths, exclusions, and refresh hints. Create one only +when the source material shows a real repeated scope; don't manufacture +scopes for one-off facts. + +### Step 4 — Synthesize pages + +Convert the core knowledge into clean, modular Markdown files. Every page +gets frontmatter with: +- A `tldr:` — one sentence, optimised for LLM reading. +- A `confidence:` score (0.0–1.0, based on source corroboration). +- A `quality:` self-score (0.0–1.0). +- A `last_updated:` timestamp. +- A `freshness_window_days:` appropriate to the topic. +- A `retention:` level. + +`type` is also required (per the page frontmatter schema in +`CLAUDE.md`/`AGENTS.md` page schema) — set it once, based on the entity/content +kind (person, project, concept, library, decision, playbook, ...). + +For long conversations, meeting notes, transcripts, or chat exports, use a +structured distillation before writing the final page: +- `Question` or searchable problem statement, when there is one. +- `Summary` of the thread/note. +- `Resolution` or `Decision`, if the material contains one. +- `Systems and code references` mentioned. +- `People involved` or apparent owners/experts. +- `High-signal excerpts` for dense technical paragraphs or consecutive + messages that would be lost in a single summary. + +"High-signal" needs an acceptance test, or every excerpt looks worth +keeping and the page becomes a second copy of the transcript. Promote a +run of text to its own section or linked page only when it clears all +three: +- **It carries a rare term.** Something specific enough that a future + search would use it — a config flag, an error string, a hostname, a + contract clause, a version number. Check with `rg -c` across `wiki/`: + if the term already appears on many pages it isn't a distinguishing + handle, and the excerpt adds no findability the summary doesn't have. +- **It's substantial.** Roughly 200 characters or more, or a few + consecutive paragraphs/messages from one author. A one-line "yes, do + that" is a resolution to fold into `Resolution`, not an excerpt. +- **Something corroborates it.** It was agreed with, acted on, corrected, + or referred back to later in the material. An unanswered assertion is a + claim, not a settled fact — keep it in the summary with that ambiguity + intact rather than promoting it. + +Fail any one of the three and the content still belongs in the page, just +inside `Summary`/`Resolution` rather than as its own retrievable unit. + +When you do promote an excerpt, carry its parent topic with it — the +thread question or section heading it sat under. An excerpt that reads +unambiguously on its own is the entire point; one that needs the +surrounding transcript to make sense hasn't been extracted, only moved. + +### Step 5 — Link and cross-reference + +Use **both** `[[Wikilinks]]` (Obsidian-compatible) and standard +`[markdown](path.md)` links on every cross-reference, so the wiki works in +Obsidian, GitHub, and CLI tools alike. Where useful, reference upstream +files directly at `linked//...` or `libs//...`. + +### Step 6 — Update index and log + +Add new pages to the routing table in `wiki/index.md` with a **Use when** +description. If the page lives in a subdirectory, also add it to that +subdirectory's own `index.md`. Append a log entry to the most specific +applicable log — the subdirectory's `log.md` if it has one, otherwise the +root `wiki/log.md` — following the format in Rule B (`CLAUDE.md`/ +`AGENTS.md` Rule B). + +If this step creates a brand-new `wiki//` subdirectory, immediately +create that subdirectory's `index.md` per the Recursive Index & Log +Convention. + +If this step creates or updates a project scope under `wiki/projects/`, +also update `wiki/projects/index.md`. If ingest closes a previously +recorded question in `wiki/query-gaps.md`, move that entry from Open to +Resolved and mention the page or source that now answers it. + +### Step 7 — Remind to review and sync + +This is always the last step, every time this skill runs and made any +change at all. Close with a short reminder — do not sync or push +anything yourself here, and do not skip this even if the changes look +small or obviously correct: + +> "Ingest complete — `wiki/` has been updated (see `wiki/log.md` for the +> details). Please review the changes, and once you're happy with them, +> say 'sync changes' to commit and push them to `origin`." + +If nothing was actually ingested (empty inbox and empty `raw/`, nothing to +process), skip this reminder — there's nothing to review or sync. + +## Edge cases + +- **Inbox and `raw/` both empty** — report that there's nothing to + ingest. Don't touch `wiki/`, and skip the Step 7 reminder. +- **Item in inbox doesn't yield a clear entity or page** (too vague, pure + scratch note with no durable fact) — don't force a page into existence. + Still move the item to `raw/archive//` since it's been + considered, but note in the ingest report that it produced no wiki + change. +- **Conflicting information vs. an existing local wiki page** — this is a + supersession case handled consistently with `ckb-lint`, not a + silent overwrite: update the existing page if the new source is clearly + more current/corroborated, and link `supersedes`/`superseded_by` if an + older version is worth preserving rather than edited in place. +- **Material duplicates an upstream (`linked/`/`libs/`) page with nothing + new to add** — don't create a redundant local page just to have one; + the cascade already surfaces the upstream page. Only write locally when + overriding, correcting, or adding to what upstream says. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-init/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-init/SKILL.md index b9aab6e..637e5e7 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-init/SKILL.md +++ b/plugins/cascade-knowledge-base/skills/ckb-init/SKILL.md @@ -1,6 +1,6 @@ --- name: ckb-init -description: Bootstrap a brand-new Cascade Knowledge Base - the same directory structure, AGENTS.md/CLAUDE.md system prompt, and empty wiki/ scaffold as this project - inside a target folder (typically empty, or a new project that doesn't have one yet). Use when the user asks to "set up a new wiki like this one", "initialize a new cascade KB", "bootstrap a wiki here", "create a knowledge base with this schema", or calls it a "wiki initializer". Do not confuse with a generic `init` skill that documents an existing codebase - this one creates the Cascade KB pattern itself, empty, ready for its first ingest. +description: Bootstrap a brand-new Cascade Knowledge Base - the same directory structure, AGENTS.md/CLAUDE.md system prompt, full default skill set, LICENSE/VERSION, and empty wiki/ scaffold as this project - inside a target folder (typically empty, or a new project that doesn't have one yet). Use when the user asks to "set up a new wiki like this one", "initialize a new cascade KB", "bootstrap a wiki here", "create a knowledge base with this schema", or calls it a "wiki initializer". Do not confuse with a generic `init` skill that documents an existing codebase - this one creates the Cascade KB pattern itself, empty, ready for its first ingest. Distinct from `ckb-upgrade`, which catches an *existing* populated KB up with template changes rather than bootstrapping a new one. --- # Cascade KB init skill @@ -9,16 +9,21 @@ description: Bootstrap a brand-new Cascade Knowledge Base - the same directory s Copy this project's Cascade Knowledge Base *schema* - not its content - into a new target folder: the directory structure, the `AGENTS.md`/`CLAUDE.md` -system prompt that defines how the KB behaves, and the empty `wiki/` -scaffold (routing table, overview, log, error book, entity/graph indexes). -The result is a new, empty KB that behaves exactly like this one, ready for -its first `raw/inbox/` drop and "Ingest." +system prompt that defines how the KB behaves, the full default skill set, +`LICENSE` and `VERSION`, the generic `README`/`MANUAL` docs, and the empty +`wiki/` scaffold (routing table, overview, log, error book, entity/graph +indexes). The result is a new, empty KB that behaves exactly like this one, +ready for its first `raw/inbox/` drop and "Ingest." -This is a one-way copy from this repo's own `AGENTS.md`/`wiki/` template -files into a different folder. It never reads or writes anything in this -repo's `raw/`, `wiki/entities/`, `wiki/graph/edges.json`, or `outputs/` - -those hold this project's actual accumulated knowledge, which is exactly -what should *not* travel into a fresh KB. +This is a one-way copy from this repo's own template files into a +different folder. It never reads or writes anything in this repo's `raw/`, +`wiki/entities/`, `wiki/graph/edges.json`, or `outputs/` - those hold this +project's actual accumulated knowledge, which is exactly what should *not* +travel into a fresh KB. (For catching an *already-populated* KB up with +newer template files without losing its accumulated content, see +`ckb-upgrade` instead - that skill does the same source-of-truth copying +this one does, but merges it into an existing KB rather than a blank +folder.) ## Trigger phrases @@ -57,19 +62,39 @@ specifically. ### Step 3 - Default skill set (no need to ask) The bare scaffold (directory structure + `AGENTS.md`/`CLAUDE.md` + empty -`wiki/` templates) is always included, and so is the reusable KB skill set -- these operate purely on the `wiki/` structure, so they carry over -cleanly and are part of "the schema" as far as this skill is concerned: -`ckb-export-okf`, `ckb-export-starlight`, `ckb-sync-changes`, `extract-transcript`, -`ckb-project-summary`. Don't ask about these - just include them. +`wiki/` templates) is always included, and so is the full reusable KB +skill set - these operate purely on the `wiki/` structure (or, for +`ckb-init` and `ckb-upgrade` themselves, on the schema layer), so they +carry over cleanly and are part of "the schema" as far as this skill is +concerned. As of this writing, that's every skill under this repo's +`.agents/skills/`: -`ghost-writer` and `clouddrift-docx` are not part of the default set (a -general writing tool and a brand-specific export skill respectively, not -KB-schema-native) - only include either if the user explicitly asks for it, -e.g. "also bring over ghost-writer." +- `ckb-init` (this skill - a new KB can bootstrap further KBs of its own) +- `ckb-upgrade` (lets the new KB catch up with template changes later) +- `ckb-ingest` +- `ckb-lint` +- `ckb-sync-changes` +- `ckb-project-summary` +- `ckb-export-okf` +- `ckb-export-starlight` +- `ckb-onboard-me` +- `ckb-teach-me` +- `cbk-quiz` -Record the final skill list (default five, plus anything explicitly added) -- this affects Steps 6 and 7. +Don't ask about any of these - just include them. + +If, at the time this skill runs, `.agents/skills/` also contains skills +*not* in the list above, they're either a newer schema-native addition +this document hasn't been updated to mention yet (safe to fold into the +default set the same way - they follow the same "operates purely on the +KB structure" test) or a project-specific/general-purpose skill someone +added for this project only (e.g. a brand-specific export tool or a +general writing aid, unrelated to the Cascade KB pattern itself) - in +that case, only include it if the user explicitly asks for it by name, +e.g. "also bring over ``." + +Record the final skill list (the defaults above, plus anything explicitly +added) - this affects Steps 8 and 9. ### Step 4 - Create the directory structure @@ -87,11 +112,20 @@ wiki/graph/ workload/ ``` -`libs/`, `linked/`, and `tmp/` are gitignored per the schema (Step 6) and -stay empty. `raw/inbox/`, `raw/archive/`, and `workload/` are meant to be -tracked but start empty - add a placeholder `.gitkeep` file to each so they -survive a fresh `git init` + first commit rather than vanishing as empty -directories. +Git doesn't track empty directories, so every one of these - plus +`.agents/`, `.agents/skills/`, and `.claude/` created in Step 9 - needs a +placeholder to survive a fresh `git init` and first commit. This repo's +own convention is an empty file named `.gitadd` in each directory (not +`.gitkeep`) - match that convention exactly, so a new KB's directory +listing looks identical to this one's. + +`libs/` and `tmp/` are gitignored per the schema (Step 8) except for their +own `.gitadd` placeholder, so they stay effectively empty. `linked/` gets +a `.gitadd` too but is *not* gitignored - it's meant to hold real +symlinks, which git tracks natively (as a small blob storing the link +target), so nothing extra is needed there. `raw/inbox/`, `raw/archive/`, +and `workload/` are meant to be tracked and start genuinely empty aside +from their placeholder. ### Step 5 - Write `AGENTS.md` and the `CLAUDE.md` symlink @@ -101,7 +135,30 @@ schema definition). Then create `CLAUDE.md` in the target as a symlink to `AGENTS.md`, matching this repo's own convention (one source of truth, readable under either filename). -### Step 6 - Write the empty `wiki/` scaffold +### Step 6 - Write `LICENSE`, `VERSION`, and the generic docs + +Copy these verbatim from this repo - they're already fully generic (no +project-specific content, confirmed by having zero references to any +actual project entity): + +- `README.md` and `README.pl.md` - the technical feature overview, including + the "source repo" pointer at the top. Leave that pointer as-is (pointing + at this template's own canonical repo) unless the user says the new KB + should point somewhere else - it's what lets the new KB's own + `ckb-upgrade` find template updates later. +- `MANUAL.md` and `MANUAL.pl.md` - the task-oriented user guide. +- `VERSION` - copy the exact current value; the new KB starts life on the + same template version it was just cloned from. + +For `LICENSE`, copy the Apache License 2.0 text, but **ask the user first** +whether to keep the copyright line as-is (appropriate if this new KB is +still effectively part of the same umbrella/organization) or update it to +their own name/organization (appropriate if this is a genuinely separate +project that will accumulate its own content under its own ownership) - +don't silently carry over a copyright attribution that may not apply to +what the new KB is about to collect. + +### Step 7 - Write the empty `wiki/` scaffold Create these files in the target, using this repo's current versions as the template and stripping every reference to this project's actual @@ -129,28 +186,53 @@ Do not carry over any entity pages, graph edges, log entries, or overview content specific to this project - the whole point is an empty KB with the same shape. -### Step 7 - Write `.gitignore` +### Step 8 - Write `.gitignore` -Base rules (always): `libs/`, `linked/`, `tmp/`, `.DS_Store`. Since -`ckb-export-starlight` and `ckb-export-okf` are in the default skill set (Step 3), -also always add `outputs/starlight` and `outputs/okf` - both exist to be -gitignored precisely because those two skills are present by default. +Copy this repo's actual current `.gitignore` verbatim rather than +reconstructing it from memory - it uses a `/*` + `!/.gitadd` +pairing (not a bare `/` line) for directories that should exist as a +tracked shell but have their real contents ignored: -### Step 8 - Copy the skill set from Step 3 +``` +libs/* +!libs/.gitadd +tmp/* +!tmp/.gitadd +outputs/starlight +outputs/okf +outputs/teaching +.env +``` + +Since `ckb-export-starlight`, `ckb-export-okf`, and `ckb-teach-me` are all +in the default skill set (Step 3), their `outputs/` subfolders +(`outputs/starlight`, `outputs/okf`, `outputs/teaching`) are gitignored by +default too - each exists to be ignored precisely because its skill is +present by default. If a future skill set change ever drops one of those +three skills from the default set, drop its matching ignore line too; +if the user explicitly adds a skill with its own `outputs/` convention, +ask whether it needs a similar ignore line. + +### Step 9 - Copy the skill set from Step 3 Copy each skill's folder from this repo's `.agents/skills//` into the -target's `.agents/skills//` unchanged - the default five, plus -anything explicitly added. Then create `.claude/skills` in the target as a -symlink to `../.agents/skills`, matching this repo's convention - do this -once, after copying the whole set, not per-skill. +target's `.agents/skills//` unchanged (including each skill's own +license footer, and any support files like +`ckb-export-starlight/scripts/export_starlight.py`) - the full default set +from Step 3, plus anything explicitly added. Then create `.claude/skills` +in the target as a symlink to `../.agents/skills`, matching this repo's +convention - do this once, after copying the whole set, not per-skill. -### Step 9 - Report +### Step 10 - Report Tell the user: - The resolved target path. - The directory tree created. - Whether `AGENTS.md`/`CLAUDE.md` were written or (per Step 2) skipped/merged. -- Which skills were copied (the default five, plus anything explicitly added). +- Which skills were copied (the full default set, plus anything explicitly + added). +- The `VERSION` the new KB starts on, and what was decided for `LICENSE`'s + copyright line. - Next step: "Drop material into `raw/inbox/` and say 'Ingest' to populate the wiki for the first time." ## Edge cases @@ -168,3 +250,8 @@ Tell the user: drifted from each other** (e.g. one mentions a directory the other doesn't) - fix the drift in *this* repo first if noticed, then copy the corrected version. Don't propagate a known inconsistency into a new KB. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-lint/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-lint/SKILL.md new file mode 100644 index 0000000..852970d --- /dev/null +++ b/plugins/cascade-knowledge-base/skills/ckb-lint/SKILL.md @@ -0,0 +1,194 @@ +--- +name: ckb-lint +description: Health-check the wiki/ — conformance, freshness, confidence decay, retention sweep, supersession detection, orphan detection, graph consistency, index/log consistency, and error-book entries — auto-fixing what it safely can and reporting the rest, then reminding the user to review and sync to origin. Also runs the same checks against each connector-backed libs//'s own generated index (see ckb-index-external), plus a source.yaml validity check, without ever touching a git-copy lib or a connector's source.yaml itself. Use when the user says "Lint", "health-check the wiki", "check the wiki", or asks for a periodic/scheduled wiki health check. This is the maintenance workflow routed by CLAUDE.md/AGENTS.md, distinct from `ckb-ingest` (which adds new content) and `ckb-sync-changes` (a pure git-level operation with no wiki synthesis at all). +--- + +# Lint skill + +## Purpose + +Health-check the local, mutable `wiki/` for structural rot: missing or +malformed frontmatter, stale pages, decayed confidence, orphaned or +archivable content, broken graph edges, and index/log drift. This is +maintenance, not growth — it never adds new knowledge the way `ckb-ingest` +does; it only checks and repairs the shape of what's already there. + +Implemented as a skill (rather than living inline in +`CLAUDE.md`/`AGENTS.md`) so the full checklist only loads into context when +actually invoked — on demand, or on a schedule if the user has set one up. + +This skill only ever writes within `wiki/` (including moves into +`wiki/archived/`) and, for any connector-backed `libs//` (one with a +`source.yaml` — see `CLAUDE.md`/`AGENTS.md` directory contract) where this user has +local `access: write` (see `ckb-index-external`), within that connector's +own agent-owned generated index (`index.md`/`entities/`/`graph/`/`log.md`). +For a connector-backed `libs//` where this user is read-only (the +default), findings against that index are reported only, never auto-fixed +— the same access gate `ckb-index-external` applies to rebuilding applies +here too. It never touches `linked/`, a git-copy `libs//`, or a +connector's `source.yaml`/`source.local.yaml` — those stay immutable or +user-owned — and it never touches this repo's own git remote; pushing the +resulting changes is a separate, explicit step (see the final step below). + +## Trigger phrases + +Use this skill when the user says: +- "Lint" +- "health-check the wiki" / "check the wiki" +- "run the periodic/scheduled wiki check" + +Do **not** use this skill for "Ingest" / "Sync the wiki" (that's +`ckb-ingest` — turning raw material into new wiki pages) or for "sync +changes" / "sync with git" (that's `ckb-sync-changes` — reconciling this +repo's own commit history with `origin`, no wiki content involved). + +## How to run this skill + +Work through each check in order. A malformed page breaks every later +check's ability to reason about it, so conformance comes first. + +Checks 1-9 below are written against `wiki/`, but the same checks also run +a second time against each connector-backed `libs//`'s own generated +index — scoped entirely to that one connector's `index.md`/`entities/`/ +`graph/`/`log.md`. Auto-fixes there only happen where this user has local +`access: write` for that source (see `ckb-index-external`); everywhere +read-only, findings are reported but not applied. Findings and fixes there +are logged in that connector's own `log.md`, never in `wiki/log.md`. A +git-copy `libs//` (no `source.yaml`) and any `source.yaml`/ +`source.local.yaml` are never touched by any of these checks. + +### 1 — Conformance check + +Verify every non-reserved `.md` file under `wiki/` (i.e. excluding +`index.md` and `log.md`) has parseable YAML frontmatter with a non-empty +`type` field. Flag violations first, and treat flagged pages as +unreliable input for the checks below rather than guessing at their +intended type/content. + +### 2 — Freshness check + +Scan every page whose `last_updated` exceeds its `freshness_window_days`. +Flag as stale; suggest the user confirm or update the content — don't +silently rewrite stale content yourself. + +### 3 — Confidence decay + +Reduce `confidence` on pages not reinforced by a new source since the last +check. Pages that fall below 0.3 confidence get flagged for re-review. + +### 4 — Retention sweep + +Move `retention: low` pages older than 2× their `freshness_window_days` +into `wiki/archived/`. Never delete — always move, and log the move (see +Rule B in `CLAUDE.md`/`AGENTS.md`) with a note explaining why. + +### 5 — Supersession detection + +When two pages appear to cover the same entity, check for contradictions. +If one is clearly newer/better corroborated, add `supersedes` / +`superseded_by` links between them. Preserve the older page rather than +deleting it, but mark it stale. + +### 6 — Orphan detection + +Find pages with no inbound links (`[[wikilinks]]` or +`[markdown](path.md)` references from elsewhere in the wiki). Either add +backlinks from relevant pages where an obvious connection exists, or move +the orphan to `wiki/archived/` with a log note if no natural backlink +exists. + +### 7 — Graph consistency + +Verify every edge in `wiki/graph/edges.json` points to an existing entity +page. Remove or fix broken edges; note what was removed rather than +silently dropping entries. + +### 8 — Index/log consistency + +Verify every subdirectory under `wiki/` that contains pages has an +`index.md` listing all of them, and that no single change is recorded in +both a subdirectory `log.md` and the root `wiki/log.md` (per the +Recursive Index & Log Convention). Fix missing index entries and +duplicate log entries directly. + +### 9 — Error Book entry + +Record any systemic issue found above (a repeated broken pattern, a +recurring format mismatch, the same kind of orphan appearing again) in +`wiki/error-book.md` with its root cause, the fix applied, and the derived +constraint that should prevent recurrence. A one-off, isolated issue +doesn't need an Error Book entry — this is for patterns, not incidents. + +### 10 — External source config check + +For each `libs//source.yaml`, verify it has a non-empty `connector` +and `location` — report only, this file is never edited by any skill. If +an `index:` block is present, verify it has a non-empty `store` and +`location` too. If `refresh_interval_days` is present, verify it's a +positive integer. Also flag (report only) a `libs//` that +ambiguously has both real content files and a `source.yaml` — that's a +configuration conflict for the user to resolve, not something to guess at. + +Report any connector-backed source whose generated index is overdue: +newest `last_updated` in `libs//` older than its +`refresh_interval_days` (default 30). Report it the same way whether or +not this user has write access — a read-only user can't fix it, but +knowing which source to chase the admin about is the actionable part. Name +how overdue it is rather than just "stale," since a source two days past a +7-day interval is a different situation from one six months past a 30-day +one. Never re-index here; that's `ckb-index-external`'s job, and suggesting +it is as far as this check goes. + +Don't flag a missing `libs//source.local.yaml` as an issue — its +absence is the correct, read-only default (see `ckb-index-external`), not +a gap to report or fix. + +### Auto-fix vs. report + +Auto-fix what can be done safely and mechanically: broken links, missing +backlinks, stale flags, missing index entries, duplicate log entries, +dangling graph edges. Report anything that needs a judgment call +(supersession decisions, low-confidence content, ambiguous orphans) rather +than guessing on the user's behalf. + +### Final step — Remind to review and sync + +This is always the last step, every time this skill makes any change at +all to `wiki/`. Close with a short reminder — do not sync or push +anything yourself here: + +> "Lint complete — see `wiki/log.md` for what changed (auto-fixed: ...; +> flagged for your review: ...). Please review the changes, and once +> you're happy with them, say 'sync changes' to commit and push them to +> `origin`." + +If any connector-backed `libs//` was also touched, mention it +separately (its own `log.md`, not `wiki/log.md`) rather than folding it +into the same sentence. + +If the lint pass made no changes at all (clean bill of health, nothing to +fix or flag), skip this reminder — there's nothing to review or sync. + +## Edge cases + +- **Wiki is empty or near-empty** — report that there's little to lint + yet; don't fabricate findings to look thorough. +- **A page's frontmatter is unparseable** (not just missing `type`, but + invalid YAML) — flag it prominently in the conformance check and skip + it in every later numbered check rather than letting a parse error + crash or silently mis-handle downstream logic. +- **Retention sweep would archive a page that's clearly still in active + use** (e.g. linked from a very recent `workload/` entry) — flag it for + the user to confirm rather than auto-archiving; recency of use can + override a stale `last_updated`/`retention` combination. +- **Supersession is ambiguous** (two pages disagree and neither is + clearly newer/better corroborated) — report the conflict rather than + guessing which one wins. +- **Repeated run with nothing changed since the last lint** — should + produce essentially the same clean report each time; don't invent + variation just to seem active. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-onboard-me/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-onboard-me/SKILL.md index 8ea47d0..e66b39e 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-onboard-me/SKILL.md +++ b/plugins/cascade-knowledge-base/skills/ckb-onboard-me/SKILL.md @@ -141,3 +141,8 @@ Close with a short offer: to go deeper on any single step, to widen the tour - **Upstream-only topic** — if the anchor lives in `linked/`/`libs/` with no local overlay, build the tour from the upstream KB's own index/links and mark every step as upstream/read-only. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-project-summary/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-project-summary/SKILL.md index e7a92e4..2ec2664 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-project-summary/SKILL.md +++ b/plugins/cascade-knowledge-base/skills/ckb-project-summary/SKILL.md @@ -175,3 +175,8 @@ whatever the wiki says at that moment, not what it said today. - **Re-running with no wiki changes since the last run** - should produce essentially the same content each time; don't introduce random variation in section content or ordering between runs. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-quiz/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-quiz/SKILL.md index 9664ce1..7b13691 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-quiz/SKILL.md +++ b/plugins/cascade-knowledge-base/skills/ckb-quiz/SKILL.md @@ -196,3 +196,8 @@ Wait for the answer. If yes, go back to Step 2 with the new parameters. If no, c **No wiki content.** If the topic has no coverage in the wiki at all, say: "That topic does not appear in the wiki yet. Choose a different topic, or ingest a source on it first." **Ambiguous open answers.** When an open answer is on the border — partially right — mark it correct, note what was right and what the full answer includes. Do not leave the user unsure whether they got credit. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-retrieve/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-retrieve/SKILL.md new file mode 100644 index 0000000..ac9d448 --- /dev/null +++ b/plugins/cascade-knowledge-base/skills/ckb-retrieve/SKILL.md @@ -0,0 +1,284 @@ +--- +name: ckb-retrieve +description: Governs how a question actually gets answered from the knowledge base. An index entry — a wiki page's `tldr`, a connector-index document/entity page — is deliberately compressed so lazy-loading stays cheap; that compression also means it can be incomplete, paraphrased loosely, or stale relative to the real source. This skill makes "go verify against the source before answering" a standing step, not an optional last resort: every time a page surfaced by the index looks relevant enough to actually ground part of the answer, follow it to its underlying source material — a wiki page's own `## Sources` citations into `raw/archive/`/`outputs/`, or a connector-index page's `resource:` pointer back to the live connector item — before treating its content as settled. Use whenever answering a question or researching a topic from `wiki/`, `linked//`, or a connector-backed `libs//` — this is the retrieval workflow routed by CLAUDE.md/AGENTS.md, always in play, not something the user needs to name explicitly. Distinct from `ckb-onboard-me` (produces a reading-order tour, not an answer to a specific question) and from the write-side skills `ckb-ingest`/`ckb-index-external`/`ckb-lint` (build or repair the index; this skill only ever reads it, plus the sources behind it). +--- + +# Retrieve (source-verified query) skill + +## Purpose + +The whole point of `tldr`/lazy-loading (CLAUDE.md/AGENTS.md index-first +navigation and skill routing) is that most of the wiki never has to enter +context — a one-sentence summary decides +whether a page is worth opening at all. That's the right trade for +*deciding relevance*. It's the wrong trade for *grounding an answer*: a +`tldr` is a compression of whatever the page's author judged important at +write time, a connector-index entity page is (per `ckb-index-external`) +deliberately a thin pointer rather than a synthesis, and either can have +drifted from the primary material since — a source updated, a nuance +dropped, a paraphrase that's subtly wrong. + +This skill closes that gap: once a page looks relevant enough to actually +use in an answer, don't stop at its `tldr` or even its full synthesized +body — follow it to the source material that page was built from, and +answer from there. It's the difference between citing what the index +*says about* the evidence and citing the evidence. + +This skill is **read-only**. It never writes to `wiki/`, `libs//`, +or anywhere else — it only reads what already exists (the index, and the +source material behind it) to answer the question in front of it. If +verification surfaces a real gap or contradiction worth fixing in the +wiki, say so and suggest `ckb-lint`/`ckb-ingest` rather than editing +anything mid-answer. + +## Trigger phrases + +This is the default retrieval path for **any** question answered from the +knowledge base — the user does not need to name this skill. Typical +prompts that should route here: +- A direct question answerable from the wiki ("what do we know about X", + "what's the status of Y", "who owns Z"). +- "Look up X" / "check the wiki for X" / "search for X". +- Mid-conversation moments where CLAUDE.md/AGENTS.md routes a KB question + to retrieval — this skill *is* that workflow's implementation. + +Do **not** use this skill for: +- Building or refreshing an index in the first place — that's + `ckb-ingest` (raw material → `wiki/`) or `ckb-index-external` + (connector → `libs//`). This skill only ever consumes what those + produced. +- A guided reading order across many pages on a topic — that's + `ckb-onboard-me`. This skill answers one question with verified + evidence; it doesn't produce a curriculum. +- Health-checking the index's own structure (frontmatter, staleness, + broken links) — that's `ckb-lint`. Verification failures found here + (Edge cases, below) are worth mentioning to the user as a possible lint + finding, but this skill doesn't run the lint checklist itself. + +## How to run this skill + +### Step 1 — Read the index + +Same cascade order as CLAUDE.md/AGENTS.md, first match wins: +1. `wiki/index.md` — match the question against the **Use when** column. +2. `wiki/projects/index.md` — if a project scope matches the question, + use that project's listed pages, entity pages, raw/archive sources, + connector-backed libs, outputs, and graph areas as the first search + boundary. A project scope narrows the first pass only; it never hides + the rest of the cascade. +3. `wiki/entities/index.md` — match against entity titles/`tldr`. +4. If nothing local matches: each `linked//` index (alphabetical), + then each connector-backed `libs//entities/index.md` — for a + connector-backed lib this means its *generated* index (both the + Documents and the Entities & Processes sections `ckb-index-external` + produces), never the live source directly. If it isn't built yet, + suggest "index external sources" rather than querying the live + connector ad hoc from inside this skill. + +### Step 2 — Shortlist every page that looks relevant + +Read the `tldr` of every page the index match surfaced — don't stop at +the first plausible hit. A question is often best answered by +triangulating two or three pages (e.g. a concept page plus the specific +person/decision page that qualifies it), and a page whose `tldr` looks +only tangential can still be hiding the exact fact needed in its body or +its Sources. Keep the shortlist to what's plausibly relevant; this isn't +"open everything," it's "don't stop at one." + +If index/TLDR matching is not enough, run a local hybrid pass before +giving up: use `rg` for exact tokens across `wiki/`, `raw/archive/`, +`outputs/`, `raw/inbox/`, and readable upstream indexes; combine those +hits with project-scope matches, entity/title/TLDR matches, graph +proximity, freshness, confidence, and quality. Prefer exact text matches +for error strings, commands, flags, filenames, hostnames, IDs, and other +literals; prefer entity/semantic matches for paraphrased questions. + +Sweep `raw/inbox/` even though nothing there has been ingested yet. +Material dropped an hour ago can already hold the answer, and finding it +there is also the clearest possible signal that an `ckb-ingest` run is +overdue — mention that. Say plainly when an answer rests on un-ingested +inbox material rather than on a synthesized page. + +Keep each signal's hits as its own ranked list rather than merging them by +eye as you go. Step 4 needs the separate orderings. + +### Step 3 — Walk the graph for anything the shortlist missed + +If a shortlisted page has edges in `wiki/graph/edges.json` (or a +connector's own `graph/edges.json`), follow `depends_on`/`uses`/`caused` +edges one hop out to catch a connected page the index text match alone +wouldn't have surfaced. + +For "who knows about X" and "who owns X" questions — both advertised in +the trigger phrases above — the graph is the primary lookup rather than a +fallback. Read the `has_expertise_in` and `owns` edges pointing at the +topic entity and answer from the people or teams on the other end, +ordered by how many distinct sources evidence each edge. Where no such +edge exists yet, fall back to authorship evidence: who the `## Sources` +material actually shows answering questions on that topic. Say which of +the two grounded the answer, since an inferred expert is a weaker claim +than a recorded one. + +### Step 4 — Fuse the signals, dedupe, then rerank + +Signals disagree, and none of them is trustworthy alone: an exact `rg` hit +can sit in a page that answers a different question, and a confident TLDR +match can be a loose paraphrase of something stale. Don't settle that by +picking a favourite signal — fuse the ranked lists from Step 2. + +**Fuse.** For every candidate, sum `weight / (k + rank)` across each list +it appears in, where `rank` is its 1-based position in that list. Use +`k = 10` and a default `weight` of 1.0. A page ranked third in three +different lists beats one ranked first in a single list; consensus is the +whole point. + +`k = 10` is deliberately smaller than the `k = 60` rank fusion is usually +quoted with. 60 is tuned for retrievers returning hundreds of candidates, +and against the dozen-or-so a local wiki produces it flattens every score +into near-identical values. Raise a list's weight when the question +warrants it — for a pasted error string, command, flag, or ID, weight the +exact-match list around 2.0, because no amount of title/TLDR similarity +should outrank a literal match on the token the user actually pasted. + +**Dedupe.** Collapse candidates carrying the *same claim* into one entry +before ranking further. Step 6 actively manufactures these: a `wiki/` +page, the `raw/archive/` file it cites, and a connector-index page whose +`resource:` points back at that same wiki page are three hits for one +fact. Keep whichever sits closest to the primary material and record the +others as corroboration, not as independent evidence. Three views of one +claim are not three sources. + +**Rerank.** Score each surviving candidate 0–10 on how well it answers +*the literal question asked*, not on how well it matches the query's +vocabulary, then keep the best handful and drop the rest. This is the same +agent making a deliberate second pass, not a separate model. The point is +that relevance judgment happens explicitly, over the shortlist, in one +place — rather than being folded silently into how the final answer gets +drafted. + +### Step 5 — Expand local context and build an evidence packet + +For every result that survived Step 4, keep a small evidence packet with: +- source path or connector resource +- matched claim or short excerpt +- source date or `last_updated` +- freshness/confidence/quality signals, when available +- project-scope or graph relationship hints, when relevant +- which signals it was fused from, its rerank score, and anything it + absorbed during dedupe — this is what Step 7 draws caveats from + +When a match is a section, heading, or snippet inside a larger Markdown +file, include nearby headings/paragraphs before deciding what it means. +Avoid answering from an isolated fragment when the neighboring context +changes the interpretation. + +### Step 6 — Follow every page on the shortlist to its source before answering from it + +This is the step this skill exists to enforce. For each page on the +shortlist that will actually ground part of the answer: + +- **A `wiki/` page** — every page synthesized via `ckb-ingest` carries a + `## Sources` section citing the exact `raw/archive//...` or + `outputs/...` file(s) it was built from. Open the cited file(s) — or + the specific section of a large one — and confirm the wiki's claim + matches what the primary material actually says. This also often + surfaces adjacent detail the synthesis compressed away that's directly + useful for the current question. +- **A connector-index page in `libs//`** (a document page, or an + entity/process page from the `ckb-index-external` extraction) — read + its `resource:` field. If the connector is authorized this session (per + `ToolSearch`/MCP auth state), re-fetch the live item for current, + complete content rather than trusting the cached `tldr` — connector + pages use a deliberately short `freshness_window_days` (30, vs. a + typical wiki page's 60-90) precisely because external sources drift + without notice. If the connector isn't authorized, or the item is a + calendar acceptance / metadata-only page with nothing more to fetch, + say plainly that the answer relies on the cached index rather than a + live re-check, so the user can weigh that. +- **A `linked//` page** — this is already full mirrored content, + not a summary; reading the page itself already is reading the source. + No extra fetch needed unless *that* page itself cites something further + outside the mirror. + +Target the specific claim, not the whole file — a large transcript or +deck doesn't need a full read every time, just enough (search for the +name/topic, read the surrounding context) to confirm the point actually +being used. + +### Step 7 — Reconcile and answer + +If the source confirms the index, answer normally — but note what +grounded it (e.g. "per the kickoff transcript cited in +`gt-fde-access-requirements.md`") rather than presenting the answer as if +sourced from the `tldr` alone. + +If the source contradicts, extends, or is more precise than what the +index said, prefer the source for the answer and say so explicitly — this +is exactly the kind of drift `ckb-lint`'s freshness/confidence checks +exist to eventually catch, so mention it's worth a lint pass if the gap +looks like more than a one-off, but don't rewrite the wiki page yourself +mid-answer unless the user asks for that separately. + +State caveats in the answer itself, not only in the metadata you read to +build it. When a page grounding the answer is past its +`freshness_window_days`, carries a low `confidence` or `quality`, rests on +un-ingested `raw/inbox/` material, or was checked against a cached +connector index rather than a live re-fetch, say so in a short clause next +to the claim it qualifies. Surface a conflict between two live pages the +same way, even when neither is marked `superseded_by` yet. The metadata +already exists and Step 4 already put it in front of you; the failure mode +is answering confidently *from* a stale or contested page without passing +that on, which leaves the reader no way to weigh it. + +If no page anywhere is even plausibly relevant, say so — don't verify +against a source that has nothing to do with the question just to appear +thorough, and don't fabricate an answer either. For durable missing +knowledge, add or propose a short `wiki/query-gaps.md` entry with the +question, date, search areas tried, and the smallest missing source/page +that would close the gap. If you edit `wiki/query-gaps.md`, update +`wiki/log.md` immediately. + +## Edge cases + +- **Only one signal returned anything** — fusion is a no-op, so don't run + the arithmetic for show. The rerank still applies (it's the check that + the one list actually answers the question rather than merely matching + its wording), and dedupe still applies as soon as Step 6 pulls in a + page's own cited source. +- **A cited source file no longer exists** (moved, renamed, or cleaned + up) — say so plainly rather than silently falling back to the `tldr` as + if it had been verified. Flag it as a likely `ckb-lint` finding (a + broken `Sources` reference) rather than treating it as a dead end. +- **Connector item unreachable or connector not authorized this + session** — state clearly that the answer is based on the cached + connector index, not a live re-check, and name which connector would + need authorizing to go further. +- **Question is low-stakes and the matched page is high-confidence, + recently updated, and well within its `freshness_window_days`** — still + open the source at least once to ground the answer; skip only a *second* + redundant read if the same source has already been opened earlier in + the same retrieval pass for another part of the same question. +- **Many pages are relevant and reading every cited source in full would + be excessive** — prioritize the sources that actually carry the + specific fact the question needs, not every source any shortlisted page + has ever cited. Say what was skipped rather than silently narrowing + without a note. +- **The "source" is itself a generated artifact** (e.g. an + `outputs/emails/*.md` draft cited as a wiki page's Source) rather than + raw external material — that's still the source relative to the wiki + page; no further hop beyond it is required. +- **A connector-index entity/process page's `resource:` points at a full + `wiki/entities/` page** (per `ckb-index-external`'s thin-page + convention) — treat the wiki page as the real source to verify against; + the connector page is just the pointer that got you there. +- **Nothing in the index is even plausibly relevant** — say the knowledge + base has nothing on this yet, and suggest `ckb-ingest` (for new raw + material) or `ckb-index-external` (for a connector-backed source) if + that seems like the actual gap. For durable gaps, record or propose a + `wiki/query-gaps.md` entry. Don't stretch a weak match into an answer + just to have one. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-sync-changes/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-sync-changes/SKILL.md index c329063..9e8dfcd 100644 --- a/plugins/cascade-knowledge-base/skills/ckb-sync-changes/SKILL.md +++ b/plugins/cascade-knowledge-base/skills/ckb-sync-changes/SKILL.md @@ -31,7 +31,7 @@ Use this skill when the user says things like: - "sync the repo" Do **not** use this skill for bare "Sync" or "Sync the wiki" — those trigger -the content-level Ingestion Workflow in `CLAUDE.md`/`AGENTS.md` §3 instead +the content-level ingest workflow routed by `CLAUDE.md`/`AGENTS.md` instead (processing `raw/inbox/` into `wiki/`), which this skill has nothing to do with. @@ -63,7 +63,35 @@ ask the user via `AskUserQuestion` whether to include or skip each one *before* staging anything in Step 3 — never silently commit or silently drop a flagged file. -### Step 2 — Detect the first-run / unrelated-histories case +### Step 2 — Ensure `origin` is configured + +```bash +git remote get-url origin +``` + +- **Succeeds** → go to Step 3. +- **Fails** (`fatal: No such remote 'origin'`, or `git remote` lists nothing + at all) → this repo has no remote to sync with yet. Ask the user directly + (a plain question is fine here — it's a URL to paste, not a choice between + options): + > "This repo has no `origin` remote configured. Paste the URL of the + > remote repository (e.g. `https://github.com/org/repo.git` or + > `git@github.com:org/repo.git`) and I'll add it as `origin`." + + Once given: + ```bash + git remote add origin + ``` + Then continue to Step 3 with `origin` now configured. If `git remote add` + itself errors (malformed URL, etc.), report the raw error and stop — don't + guess at a corrected URL or retry with a modified one. +- **A differently-named remote already exists** (e.g. `upstream`) that looks + like it might be the intended remote — don't assume. Ask the user whether + that's the one to sync with (in which case, whether to alias/rename it to + `origin` since the rest of this skill assumes that name) or whether to add + a separate, new `origin`. + +### Step 3 — Detect the first-run / unrelated-histories case ```bash git fetch origin @@ -71,10 +99,10 @@ git rev-parse HEAD # fails with "unknown revision" if local has no co git rev-parse origin/main # fails if the remote branch doesn't exist/is empty ``` -- **Local `HEAD` exists** → go to Step 3, regardless of remote state. +- **Local `HEAD` exists** → go to Step 4, regardless of remote state. - **Local `HEAD` doesn't exist, and `origin/main` doesn't exist or is empty** → this is a plain first publish, not a reconciliation. Proceed - automatically to Step 3 (it will just commit and push with nothing to + automatically to Step 4 (it will just commit and push with nothing to merge). - **Local `HEAD` doesn't exist, but `origin/main` already has commits** → **hard stop, every time this is detected.** Show the user: @@ -90,14 +118,14 @@ git rev-parse origin/main # fails if the remote branch doesn't exist/is empt Do **not** offer a fourth "discard remote, force local to become main" option — that requires a force-push and is out of scope for this skill; if the user wants that, tell them it needs to be done manually. Execute - only the option chosen, then continue to Step 3 with whichever git state + only the option chosen, then continue to Step 4 with whichever git state results. -### Step 3 — Steady-state flow +### Step 4 — Steady-state flow Order matters: **commit local changes first, then fetch/merge, then push.** Committing first turns any overlap into an ordinary merge conflict (which -Step 4 already knows how to present), rather than a stash-pop conflict with +Step 5 already knows how to present), rather than a stash-pop conflict with no commit boundary to fall back on. ```bash @@ -113,7 +141,7 @@ git merge origin/main # merge, never rebase — rebase would rewrit Outcomes of the merge: - `Already up to date.` or a clean auto-merge → continue below. -- `CONFLICT` → go to Step 4, then come back here once every conflict is +- `CONFLICT` → go to Step 5, then come back here once every conflict is resolved and committed. ```bash @@ -125,7 +153,7 @@ fetch and push), retry the fetch → merge → push cycle **exactly once**. If it fails again, stop and report the raw error to the user — never force, never retry more than once. -### Step 4 — Present each conflict to the user +### Step 5 — Present each conflict to the user ```bash git diff --name-only --diff-filter=U @@ -162,15 +190,16 @@ staged, commit: ```bash git commit -m "Merge origin/main (conflicts resolved with user input)" ``` -Then return to Step 3's push. +Then return to Step 4's push. -### Step 5 — Report +### Step 6 — Report End with a structured summary: ``` ## Sync report +**Remote:** origin already configured (or "origin added: ") **Pulled from origin/main:** commit(s) — **Committed locally:** file(s) — , commit (or "no local changes to commit") **Conflicts encountered:** (or "none") @@ -195,5 +224,16 @@ blocker. push." - **Push rejected twice in a row** — stop, report the raw git error, do not force and do not retry a third time. -- **No remote configured, or fetch/push fails on auth/network** — report +- **No `origin` remote configured** — handled proactively in Step 2 (ask + the user for the URL and add it), not treated as a failure. +- **User pastes an invalid or unreachable URL** — `git remote add` itself + usually still succeeds (it doesn't validate reachability); the failure + surfaces at the `git fetch origin` in Step 3. Report that raw error and + ask the user to confirm the URL rather than guessing a correction. +- **Fetch/push fails on auth/network once a remote is configured** — report the error clearly. This skill does not manage git credentials. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or .* diff --git a/plugins/cascade-knowledge-base/skills/ckb-teach-me/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-teach-me/SKILL.md new file mode 100644 index 0000000..8d1c407 --- /dev/null +++ b/plugins/cascade-knowledge-base/skills/ckb-teach-me/SKILL.md @@ -0,0 +1,327 @@ +--- +name: ckb-teach-me +description: Turn the wiki knowledge base into a personalised teaching curriculum — plan a single session or a spaced series (duration, frequency, optional calendar .ics reminders), teach one portion per session using varied techniques (Socratic questioning, analogies, worked examples, teach-back, mini knowledge checks), and track progress against the plan across calls, re-teaching weak spots before moving on. Use when the user asks to "teach me the wiki", "teach me about X", "run a teaching session", "continue my lessons", or wants a structured course built from the knowledge base rather than a one-off quiz (for that, use the `quiz` skill instead). +--- + +# Teach me (wiki curriculum) skill + +## Purpose + +Turn the wiki into a taught course, not just a lookup table or a one-off +quiz. This skill has two modes that always run in this order for a given +topic: + +1. **Plan mode** (first call for a topic) — scope the material, ask + scheduling questions, chunk the knowledge into session-sized portions, + present the plan, save it once accepted. +2. **Teach mode** (every later call for that topic) — compare the saved + plan against saved progress, teach the next portion using a technique + different from last time, spot-check retention of earlier sessions, and + update progress. + +The wiki stays authoritative and read-only from this skill's point of +view — it never writes back to `wiki/`. Curricula, plans, and progress live +under `outputs/teaching/`, one subfolder per topic. + +## Trigger phrases + +- "teach me the wiki" / "teach me everything in the wiki" +- "teach me about X" / "I want to learn X" / "run me a course on X" +- "run a teaching session" / "continue my lessons" / "next lesson" +- "where am I up to in my lessons on X" + +Do **not** use this skill for a one-off knowledge test with no curriculum +or progress tracking — that's the `quiz` skill. + +--- + +## How to run this skill + +### Step 0 — Resolve topic and existing state + +1. Determine the topic from the user's phrasing. "Teach me about X" scopes + to X; a bare "teach me the wiki" scopes to the whole KB — confirm this + is really what they want given it may be large, and offer to narrow it + first (e.g. "the whole wiki is quite broad — want me to scope this to a + part of it, or build a multi-session course covering all of it?"). +2. Slugify the topic (kebab-case) and look for + `outputs/teaching//plan.md`. + - **Exists** → this is a **Teach mode** call. Skip to Step 5. + - **Doesn't exist** → this is a **Plan mode** call. Continue to Step 1. + - **Several folders look like plausible matches** for a vague topic + (e.g. user says "continue my lessons" with more than one curriculum + in progress) → list them (topic, sessions done / total) and ask which + one to continue. + +### Step 1 — Scheduling questions (Plan mode only) + +Ask one at a time, waiting for each answer: + +**Q1 — Single session or a series?** + +> "Do you want this as one session, or a series of shorter sessions spread +> over time?" + +**Q2 — Duration and frequency** + +- If single session: "How long should the session be? (e.g. 20, 45, 60 + minutes)" +- If series: "How long should each session be, and how often would you + like them? (e.g. '20 minutes, twice a week' or '30 minutes every + weekday')" Also ask for a start date if they want the calendar file + (Q3) — otherwise it's optional and can default to "starting next + session request." + +**Q3 — Calendar reminders** + +> "Would you like a calendar file (.ics) you can import to get reminders +> for these sessions?" + +If yes and it's a series, also ask for a preferred time of day and start +date if not already given, so events can be scheduled concretely. If it's +a single session, offer a one-off reminder event instead. + +### Step 2 — Gather the material + +1. Read `wiki/index.md` (and `wiki/entities/index.md`, + `wiki/graph/index.md` if present) to find every page in scope. For a + narrow topic, use the cascade (local `wiki/` first, then `linked/`, + then `libs/`) same as any query. For "whole wiki", scope is every page + under `wiki/` plus its graph. +2. Read each in-scope page in full (`tldr` first — skip the body only if + the page turns out irrelevant on inspection). +3. **Optional web supplement** — if the wiki is thin on a subtopic that's + clearly needed for a coherent course, you may search the web to fill + the gap. Mark any such material distinctly as *external, supplementary* + in the plan and during teaching — it does not carry the wiki's + cascade authority. If the gap is substantial enough to be worth + keeping permanently, tell the user afterwards it would be a good + candidate for `raw/inbox/` and a proper Ingest (per the Demand-Driven + Context rule in `CLAUDE.md`) rather than silently folding it into the + wiki yourself. +4. Use `wiki/graph/edges.json` (or link-following if edges are sparse — same + fallback as the onboarding-tour skill) to work out dependency order: + foundations (`depends_on`/`uses` targets) before the concepts that build + on them. + +### Step 3 — Chunk into sessions + +Order the material pedagogically (foundations → core → things that build +on it, same logic as a guided tour), then cut it into session-sized +portions against the duration from Step 1. + +- Rule of thumb: roughly one wiki page or tightly-scoped subtopic per + 10-15 minutes of session time, adjusted for how dense the material + actually is (a short stub page is quick; a long entity page with many + facts takes longer). +- **When in doubt, add a session rather than overfill one.** A session + that runs long or crams two unrelated topics together teaches worse than + two clean, focused sessions. Never let a single session's plan exceed + its stated duration on paper. +- Each session should have one clear theme/title, not a grab-bag. +- Reserve implicit room in later sessions for retention spot-checks (Step + 6) — don't plan every minute as new material. + +### Step 4 — Present the plan and get acceptance + +Show the session breakdown before saving anything: + +```markdown +## Proposed course: [Topic] + +**Format:** [N session(s) of ~M minutes] [ · every X, starting YYYY-MM-DD if series] +**Calendar file:** [Yes — will generate reminders.ics / No] + +1. **Session 1 — [title]** — [1-line: what it covers, sourced from which pages] +2. **Session 2 — [title]** — ... + ... + +Sound good, or would you like the sessions rebalanced (more/fewer, +different split)? +``` + +Wait for explicit acceptance before writing anything. If the user wants +changes, adjust and re-present — don't save a rejected plan. + +### Step 5 — Save the plan (Plan mode only, after acceptance) + +Create `outputs/teaching//plan.md`: + +```markdown +--- +type: teaching-plan +topic: +scope: <"whole wiki" | narrower description> +session_mode: single | series +session_duration_minutes: +frequency: +calendar_file: outputs/teaching//reminders.ics | null +created: YYYY-MM-DD +last_updated: YYYY-MM-DD +--- + +# Teaching plan: + +## Overview +[2-3 sentences: what this course covers and why the sessions are ordered +this way.] + +## Sessions + +### Session 1 — +- **Covers:** [pages/subtopics, as links, e.g. `wiki/entities/foo.md`] +- **Learning goals:** [what the user should be able to explain/do after] +- **External supplements:** [none | list, marked as such] + +### Session 2 — <title> +... +``` + +Create `outputs/teaching/<slug>/progress.md` alongside it, empty of +sessions so far: + +```markdown +--- +type: teaching-progress +topic: <topic as stated> +plan_file: outputs/teaching/<slug>/plan.md +last_updated: YYYY-MM-DD +--- + +# Teaching progress: <topic> + +## Session log + +_No sessions taught yet._ + +## Next up + +Session 1 — <title>. +``` + +If a calendar file was requested, generate +`outputs/teaching/<slug>/reminders.ics` (see Calendar file generation +below). Report the paths written and that the course is ready to start +whenever the user says so — do not start teaching Session 1 automatically +in this same turn unless the user asks for it explicitly. + +### Step 6 — Teach mode: pick up where progress left off + +1. Read `plan.md` and `progress.md` for the resolved topic. +2. Determine the next unit of work: + - If the previous session's knowledge check (see below) showed weak + spots, open this session with a short, targeted recap of just those + weak points before moving on — don't re-teach the whole prior + session. + - If the previous check was very poor (roughly under half recalled), + dedicate this whole session to reinforcing that material instead of + advancing the plan, and note this as an inserted repetition session + in `progress.md` (it doesn't consume a slot from the numbered plan). + - Otherwise, teach the next not-yet-completed session from `plan.md`. +3. Pick a teaching technique **different from the one used last session** + (rotate through the list below) so the course doesn't feel repetitive. +4. Teach the portion: pull the actual facts from the relevant wiki pages + (plus any marked external supplements), and deliver them via the + chosen technique. Keep it interactive — this is a taught session, not + a wall of text. +5. Close the session with a short, informal knowledge check (2-4 + questions, open or quick-recall style) on **today's** material only. + Judge generously, same spirit as the `quiz` skill: if the core fact + came through even imperfectly, count it as understood. +6. Update `progress.md`: append a dated entry for this session (technique + used, brief note on what was taught, knowledge-check result, any weak + spots flagged for next time), update `Next up`, bump `last_updated` on + both `progress.md` and — only if the plan's own shape changed (e.g. an + inserted repetition session) — `plan.md`. +7. If this was the final session in the plan, say so, give a short + overall verdict, and offer either a full-course review (can point at + the `quiz` skill for a proper scored test) or planning a new topic. + +**Teaching technique rotation** (pick one not used last time; introduce +variety, don't always default to plain explanation): +- **Socratic questioning** — lead the user to the fact via guided + questions rather than stating it outright. +- **Analogy / storytelling** — frame the concept through a relatable + comparison or short narrative. +- **Worked example / case walkthrough** — walk through a concrete instance + from the wiki step by step. +- **Compare-and-contrast** — teach a concept against something it's + commonly confused with. +- **Teach-back** — give the user the raw facts, then ask them to explain + the concept back in their own words; correct gently. +- **Mnemonic / memory device** — for lists or sequences, build a memory + aid together with the user. +- **Real-world scenario / role-play** — apply the concept to a + hypothetical situation the user reasons through. + +--- + +## Calendar file generation + +Only when requested. Write a standard RFC 5545 `.ics` file to +`outputs/teaching/<slug>/reminders.ics`: + +``` +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Cascade KB//Teach Me//EN +BEGIN:VEVENT +UID:<slug>-session-1@ckb-teach-me +DTSTART:<YYYYMMDDTHHMMSS> +DTEND:<start + session_duration_minutes> +RRULE:<only if series, e.g. FREQ=WEEKLY;BYDAY=TU,TH> +SUMMARY:Lesson: <topic> — Session 1 +DESCRIPTION:<title of session 1> +BEGIN:VALARM +TRIGGER:-PT30M +ACTION:DISPLAY +DESCRIPTION:Lesson reminder +END:VALARM +END:VEVENT +...one VEVENT per session (or a single RRULE'd VEVENT if the sessions are + evenly spaced and identical in duration)... +END:VCALENDAR +``` + +- For a series with a regular cadence, prefer one recurring `VEVENT` with + an `RRULE` (and a `COUNT=<N>` matching the number of sessions) over N + separate events — simpler for the user's calendar app to manage. +- For a single session or irregular cadence, emit one `VEVENT` per + session with explicit dates. +- Use the date/time the user gave in Step 1; if no time of day was given, + ask before generating rather than guessing. +- Tell the user the file path and that importing it is a manual step in + their own calendar app — this skill only produces the file. + +--- + +## Edge cases + +- **No wiki content in scope.** Tell the user the topic isn't covered + yet, same as the `quiz` skill would — suggest a narrower topic or an + Ingest first. Don't fabricate a curriculum from nothing. +- **Topic scope changes between Plan and Teach calls** (user asks to + teach something broader/narrower than the saved plan). Treat this as a + new topic — create a new `outputs/teaching/<new-slug>/` rather than + overwriting the existing plan, since the old one may still be in + progress. +- **User wants to abandon or restart a course.** Ask for confirmation, + then either delete the folder (only with explicit confirmation — this + is a destructive action) or archive `progress.md` with a note and start + a fresh `plan.md` if they want to redo the scoping. +- **Plan and progress disagree** (e.g. plan.md was hand-edited, or a + session number in progress.md doesn't exist in plan.md). Point it out + to the user and ask how to reconcile rather than silently guessing. +- **Course fully completed and user asks to "teach me" again on the same + topic.** Don't silently restart — tell them the course is complete and + ask whether they want a fresh, deeper course, a review/quiz pass, or a + different topic. +- **Very long-running series** (many sessions already logged) — no need + to re-read every past `progress.md` entry in full each time; the `Next + up` line and the most recent 1-2 session entries are enough context to + continue. Older entries are history, not required reading. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or <http://www.apache.org/licenses/LICENSE-2.0>.* diff --git a/plugins/cascade-knowledge-base/skills/ckb-upgrade/SKILL.md b/plugins/cascade-knowledge-base/skills/ckb-upgrade/SKILL.md new file mode 100644 index 0000000..b7466f0 --- /dev/null +++ b/plugins/cascade-knowledge-base/skills/ckb-upgrade/SKILL.md @@ -0,0 +1,390 @@ +--- +name: ckb-upgrade +description: Check the canonical Cascade KB template repo (https://git.wierzbowa.cloud/michal/ckb) for a newer schema/tooling version, and if one exists, upgrade this KB's template layer (AGENTS.md/CLAUDE.md, .agents/skills/, LICENSE, VERSION, README/MANUAL docs, base .gitignore rules) in place. Also checks wiki/index.md's own kb_schema_version for compatibility (including the case of an unversioned, pre-schema wiki) independently of the template layer, and — only with explicit confirmation — can migrate existing wiki/ content (backfilling missing frontmatter, adding missing scaffold files) up to the current schema while preserving every fact already collected. Use when the user asks to "upgrade the wiki", "upgrade this KB", "check for a newer template version", "update the KB schema", "pull in the latest skills", or "is there a new version of ckb". Distinct from ckb-sync-changes (reconciles this repo's OWN origin remote with its own history) and ckb-init (bootstraps a brand-new, empty KB) — this skill updates an EXISTING, populated KB's tooling layer (and, if asked, its content's schema conformance) from a separate upstream template source. +--- + +# Upgrade skill + +## Purpose + +A Cascade KB, once created, tends to drift from the canonical template as +the template gains new skills, fixes, or schema refinements. This skill +answers "am I behind, and if so, can I catch up?" without risking the +knowledge collected since. It treats a KB as having two layers, and checks +each **independently** — a KB can be behind on one, the other, both, or +neither: + +- **Template layer** — the schema/tooling that defines *how* the KB + behaves: `AGENTS.md`/`CLAUDE.md`, `.agents/skills/*`, `LICENSE`, + `VERSION`, `README.md`/`README.pl.md`/`MANUAL.md`/`MANUAL.pl.md`, and the + base `.gitignore` rules. Compared via the root `VERSION` file. Freely + upgradable — these files hold no project-specific content. +- **Content layer** — everything the KB has actually learned: + `wiki/entities/`, `wiki/graph/edges.json`, `wiki/index.md`'s entity rows, + `wiki/log.md`, `wiki/overview.md`, `wiki/error-book.md`, plus `raw/`, + `outputs/`, `workload/`. Compared via `wiki/index.md`'s own + `kb_schema_version` field (a KB predating that convention entirely + counts as "unversioned" and behind by default). This skill **never** + touches any of it automatically — a migration only ever runs after + explicit confirmation (see Step 3 and Step 7), and even then it only + ever adds/backfills structure, never rewrites the substance of what a + page says. + +It's entirely possible to be behind on the content layer while current on +the template layer, or vice versa: a KB might already have the latest +`AGENTS.md`/skills but still carry `wiki/` pages ingested years ago under +an older (or no) schema version, or the reverse. This skill checks and +offers to fix both, separately. + +## Schema versioning policy + +`wiki/index.md` is the only wiki file that carries `kb_schema_version`. +Treat it as the version of the wiki content contract, not as a per-page +field. + +Use schema versions as `MAJOR.MINOR`: +- Bump the **minor** version for backward-compatible additions: optional + frontmatter fields, optional reserved wiki scaffolds, new optional + subdirectories such as `wiki/projects/`, or additional optional + index/log conventions. +- Bump the **major** version for breaking changes: removing or renaming a + required field, changing the meaning of an existing required field, + removing an existing reserved filename convention, or changing cascade + lookup semantics in a way older tooling cannot safely interpret. + +The root `VERSION` file tracks the template/tooling release, not just the +wiki schema. When a schema convention changes in the template repo, update +the relevant docs/skills and `VERSION` in the same template-layer change. +When migrating an existing KB's content layer, bump `wiki/index.md`'s +`kb_schema_version` only after the confirmed migration has actually +completed. + +This is different from `ckb-sync-changes` (reconciles *this* repo's own +commit history with *its own* `origin` remote — same content, no template +comparison) and from `ckb-init` (bootstraps a brand-new, empty KB from the +template — nothing to preserve because there's no content yet). This skill +assumes you already have a populated KB and want to catch it up with +template improvements made elsewhere, without disturbing anything you've +collected unless you specifically ask it to reshape that content's +structure too. + +## Trigger phrases + +- "upgrade the wiki" / "upgrade this KB" +- "check for a newer template version" / "is there a new version of ckb" +- "update the KB schema" / "pull in the latest skills" + +Do **not** use this for "sync changes" (that's `ckb-sync-changes` — this +repo's own `origin`) or for setting up a brand-new KB (that's `ckb-init`). + +## How to run this skill + +### Step 1 — Fetch the canonical template for comparison + +Clone the canonical repo shallowly into a scratch location under `tmp/` — +never touch this repo's own git remotes or history to do this comparison: + +```bash +rm -rf tmp/ckb-upgrade-src +git clone --depth 1 https://git.wierzbowa.cloud/michal/ckb.git tmp/ckb-upgrade-src +``` + +If the clone fails (network, auth, unreachable host), report the raw +error and stop — this skill does not fall back to a cached or partial +check, and does not retry silently. + +### Step 2 — Compare template (tooling) versions + +Read `VERSION` at the repo root (treat a missing file as `0.0.0` — an +older KB that predates this convention) and +`tmp/ckb-upgrade-src/VERSION`. Compare as dotted-integer tuples +(`1.2.0` > `1.1.9`), not as plain strings — e.g.: + +```bash +python3 -c " +local_v = tuple(int(x) for x in open('VERSION').read().strip().split('.')) +remote_v = tuple(int(x) for x in open('tmp/ckb-upgrade-src/VERSION').read().strip().split('.')) +print('newer' if remote_v > local_v else 'same-or-older') +" +``` + +Record the result (`template_upgrade_available`: yes/no) and continue to +Step 3 regardless — a "no" here does **not** end the skill, because the +wiki content schema (Step 3) is checked independently and may still be +behind. + +### Step 3 — Compare the wiki content's own schema version + +This is a **separate** check from Step 2, and can find something to do +even when Step 2 didn't. Read the `kb_schema_version` frontmatter field +from local `wiki/index.md`, and from +`tmp/ckb-upgrade-src/wiki/index.md` (the version new KBs are created with +today). Compare as `(major, minor)` tuples, e.g. `"1.2"` > `"1.1"`. + +- **Local `wiki/index.md` has no `kb_schema_version` at all** — this is an + **unversioned** wiki: either it predates the convention entirely, or it + was hand-built without the standard frontmatter. Treat it as behind by + default, same as version `"0.0"`. +- **Local version is older than the template's** — behind. +- **Local version is the same or newer** — not behind; nothing to do for + content. + +Record the result (`wiki_schema_upgrade_available`: yes/no, plus the two +version strings for reporting). + +**If both `template_upgrade_available` and `wiki_schema_upgrade_available` +are "no"** → report "already up to date — template v`X`, wiki schema +v`Y`," clean up the scratch clone (Step 8), and stop. + +### Step 4 — Diff the template layer only (if `template_upgrade_available`) + +Skip this step entirely if Step 2 found no template upgrade — go straight +to Step 5 with just the wiki-schema finding to present, if any. + +The template layer is exactly these paths — never anything under `wiki/`, +`raw/`, `outputs/`, `workload/`, `tmp/`, `libs/`, or `linked/`: + +- `AGENTS.md` (and the `CLAUDE.md` symlink — recreate it if it's missing + or isn't a symlink to `AGENTS.md`; don't diff its content, it's just a + symlink) +- `LICENSE` +- `VERSION` +- `README.md`, `README.pl.md`, `MANUAL.md`, `MANUAL.pl.md` — whichever + exist upstream (an older local KB may not have some of these yet) +- `.agents/skills/<name>/**` for every skill folder present in + `tmp/ckb-upgrade-src/.agents/skills/` +- The base ignore rules in `.gitignore` (`libs/`, `linked/`, `tmp/`, + regenerated `outputs/` subfolders, `.env`, etc.) — merged, never + replaced wholesale (see Step 6) + +For every path in that list, diff the local copy against the scratch +clone's copy: + +- **Doesn't exist locally, exists upstream** (e.g. a skill or doc added + since this KB was created) — no local content at risk; stage it as an + addition. +- **Identical** — nothing to do. +- **Differs** — this needs care. The difference might be a template + improvement worth taking, or it might be a deliberate local + customization — nothing here can tell those apart automatically, + especially for `AGENTS.md`, which the [manual](../../../MANUAL.md) + explicitly tells users they're free to edit. Never silently overwrite; + queue it for Step 5. + +### Step 5 — Present findings and get decisions + +Present whichever of the two findings apply (one or both): + +```markdown +## Upgrade available + +### Template: v<local> → v<remote> (only if template_upgrade_available) + +**New files** (nothing local to lose, will be added): +- <path> +- ... + +**Changed files** (local content differs from the template): +- <path> — <one-line summary of the change, e.g. "Step 7 reworded" or + "trigger phrases extended"> +- ... + +### Wiki content schema: v<local-or-"unversioned"> → v<remote> (only if wiki_schema_upgrade_available) + +Your `wiki/` content was built against an older (or no) schema version. +This doesn't stop anything from working, but some pages may be missing +frontmatter fields the current schema expects (`tldr`, `confidence`, +`quality`, `retention`, etc.), or missing structural pieces (e.g. no +`wiki/graph/` folder yet). Nothing factual would be rewritten — only +structure and metadata would be backfilled. +``` + +For each **changed template file**, ask via `AskUserQuestion` — batched +into one question if the user wants to move fast, or one at a time if +they'd rather review each — with options **"Take the template version"**, +**"Keep my local version"**, or **"Show me the full diff first."** + +Default recommendation for template files: +- Skill files (`.agents/skills/**`), `LICENSE`, `VERSION` — lean toward + "take the template version." These are rarely hand-edited and are + exactly the kind of thing that should stay in sync. +- `AGENTS.md`, `README*`, `MANUAL*` — don't default silently. Say plainly + that local customization is common in these files and ask explicitly + rather than nudging toward either choice. + +If `wiki_schema_upgrade_available`, ask a **separate**, explicit question +— don't fold it into the template-file batch, since it's a different kind +of decision with different risk (it touches `wiki/`, which this skill +otherwise never does): + +> "Would you like me to also upgrade all wiki-related folders and data to +> the new standard? I'll review every page under `wiki/`, add any missing +> scaffold files, and backfill missing frontmatter fields — without +> rewriting any of the actual knowledge you've collected. For a large +> wiki this can take a while. Options: **Yes, rebuild to the new +> standard** / **No, just the template files** / **Show me what's +> missing first, then decide.**" + +These two decisions are independent — a user can accept the template +upgrade and decline the wiki migration, or vice versa. + +### Step 6 — Apply the accepted template-layer changes + +Only if `template_upgrade_available` and at least one item was accepted: + +- Copy accepted **new** and **changed** files from `tmp/ckb-upgrade-src/` + over their local counterparts. +- For `.gitignore`, don't overwrite it — append any upstream base rules + not already present locally (line-by-line comparison), preserving every + existing local line, including custom ones the user added for their own + project. +- If `CLAUDE.md` isn't a symlink to `AGENTS.md` (or is missing), recreate + it as one. +- Leave every path outside the template layer completely untouched at + this step — `wiki/` changes, if any, happen only in Step 7. +- Update local `VERSION` to the template's new version last, only once + every other accepted change has been applied successfully. + +### Step 7 — Rebuild wiki content to the new schema (only if confirmed in Step 5) + +This is the one part of this skill that writes under `wiki/` — it only +ever runs after the explicit confirmation from Step 5, never +automatically, and never partially without saying so. Warn the user +before starting if `wiki/entities/` has many pages, since this is a +per-page pass, not instant. + +**a. Fill structural gaps first.** Check for the standard `wiki/` scaffold +pieces and create any that are missing, using the same empty-template +shape `ckb-init` writes for a fresh KB (never overwrite one that already +exists, even if it looks sparse): +- `wiki/entities/index.md`, `wiki/graph/index.md`, `wiki/graph/edges.json` +- `wiki/error-book.md`, `wiki/overview.md` +- Any subdirectory under `wiki/entities/`-style groupings that's missing + its own `index.md` per the Recursive Index & Log Convention. + +**b. Backfill frontmatter on every existing page**, per the schema in +`AGENTS.md` page schema. For each `.md` file under `wiki/` (excluding the reserved +`index.md`/`log.md`/`error-book.md`), check its frontmatter against the +schema and fix only what's missing — never touch a field that's already +present, and never alter the page's body text: +- **Missing `type`** — infer conservatively from the page's own content + and location (e.g. a page under `wiki/entities/` describing a person, + project, library, or concept). Don't silently guess: batch every + inferred `type` into one list and confirm it with the user before + writing, since `type` is the field lint treats as most load-bearing. +- **Missing `tldr`** — synthesize a one-sentence summary from the page's + actual content. Low-risk, mechanical — no need to ask per-page. +- **Missing `confidence` / `quality`** — don't invent a placeholder + number. Re-read the page fresh and score it the same way `ckb-ingest` + would score a newly-synthesized page (source corroboration for + confidence, structure/citations/consistency for quality). +- **Missing `last_updated`** — set to today, and note in the log entry + (Step 7d) that the date reflects this migration, not original + authorship. +- **Missing `freshness_window_days` / `retention`** — set a reasonable + default appropriate to the page's apparent topic, the same judgment call + `ckb-ingest` makes for newly-written pages. +- **Missing dual-linking** on an existing cross-reference (only a + `[[wikilink]]` where a `[markdown](path.md)` link should also exist, or + vice versa) — add the missing form. Don't invent new cross-references + that weren't already there in some form. + +**c. Bump `wiki/index.md`'s `kb_schema_version`** to the template's +current value, once every page has been checked. + +**d. Log every touched page** in `wiki/log.md`, per Rule B's format — this +is the one legitimate exception to this skill's normal "never writes to +`wiki/log.md`" behavior, and should say clearly in each entry that the +change was a schema-migration backfill, not new knowledge: + +```markdown +## [YYYY-MM-DD HH:MM] - UPDATE (schema migration) +- **File Affected:** `wiki/entities/foo.md` +- **Description:** Backfilled missing `tldr`, `confidence`, `retention` during schema migration to v<new>. No content changes. +- **Source:** ckb-upgrade schema migration +--- +``` + +**e. Suggest running "Lint" afterward** as an independent verification +pass, rather than re-implementing lint's own conformance checks here — +the two skills should agree on what "conformant" means. + +### Step 8 — Clean up and report + +```bash +rm -rf tmp/ckb-upgrade-src +``` + +Report a summary covering whichever tracks actually ran: + +```markdown +## Upgrade report + +**Template version:** v<old> → v<new> (or "already current") +**Added:** <N> file(s) — <paths, or "none"> +**Updated:** <N> file(s) — <paths, or "none"> +**Kept local (declined template version):** <N> file(s) — <paths, or "none"> + +**Wiki content schema:** v<old-or-"unversioned"> → v<new> (or "already current" / "declined") +**Scaffold files added:** <paths, or "none"> +**Pages backfilled:** <N> — <paths, or "none"> +**Types inferred and confirmed:** <list, or "none"> +``` + +If anything actually changed, close with the same reminder pattern as +`ckb-ingest`/`ckb-lint`: review the diff, then say "sync changes" to +commit and push it to *this KB's own* `origin` — not the template repo +just checked against, which is typically a different remote for any KB +other than the template project itself. + +## Edge cases + +- **No `VERSION` file locally** — treat local version as `0.0.0`; any real + template version counts as newer. Mention in the report that this KB + predates version tracking. +- **No `kb_schema_version` in local `wiki/index.md` at all** — treat as + unversioned/behind by default (Step 3), and say so plainly in the + report rather than silently treating it as "version 0.0." +- **This KB's own `origin` *is* the template repo itself** (i.e. this is + the template project's own working copy) — the checks still work + (they'll usually report "already up to date" on both fronts since + you're comparing against yourself), but note this in the report so it's + clear why an "upgrade" against your own remote looks like a no-op. +- **Network/auth failure cloning the template repo** — report the raw + error, make no changes on either track, and clean up any partial + scratch clone. +- **A "changed" template file's difference looks trivial** — still + surface it for a decision; don't invent a heuristic for "safe to + auto-take," since the cost of a wrong guess (silently discarding a real + customization) is worse than one extra question. +- **User declines every changed template file** — still add any pure-new + files (nothing lost by doing so) and bump `VERSION`, since the KB + genuinely is now aware it's on the newer template version even if it + kept its own customized copies of specific files. +- **User confirms the wiki migration but the wiki is very large** — process + it in batches with progress updates rather than promising instant + completion; it's fine for this to be the longest-running part of the + skill. +- **User declines the wiki migration** — still bump nothing under `wiki/`, + including `kb_schema_version` — leave it exactly as found, so a future + run of this skill still detects it as behind rather than silently + considering it handled. +- **A page's inferred `type` is ambiguous even after inspection** — ask + the user directly for that page rather than guessing between two + plausible types; don't let one uncertain page block backfilling the + rest. +- **Uncommitted local changes already present before running this skill** + — proceed anyway (nothing here is destructive; every change lands as an + ordinary working-tree diff, reversible with `git checkout`), but mention + in the report that there was pre-existing uncommitted work, so the user + knows the diff they're about to review isn't only from this upgrade. +- **A skill folder was renamed or removed upstream** — don't delete the + corresponding local folder automatically (it might still be in active + use, or further customized locally); mention it in the report as + "removed upstream, left in place locally" and let the user decide + separately. + +--- + +*Licensed under the Apache License, Version 2.0 — see [LICENSE](../../../LICENSE) +at the repository root, or <http://www.apache.org/licenses/LICENSE-2.0>.*