The template repo now keeps three branches with fixed meanings — main is
stable, test is the release candidate, experimental is development — and
ckb-init/ckb-upgrade can source from any of them instead of only main.
Selection is per-invocation, in words the user already uses ("initialize
from the test branch", "check experimental for updates", "switch back to
stable"), and sticky: the resolved repo and branch are written to a
template: block in ckb.yaml. Without persistence, a KB bootstrapped from
experimental would be silently pulled back to main by its next upgrade.
A missing file or missing block both mean main, so every KB predating
this convention behaves exactly as before.
One consequence needed explicit handling. A KB tracking test or
experimental can sit on a VERSION main has not released yet, so comparing
it against main finds nothing newer — which the version check would have
reported as "up to date". That is true and misleading. ckb-upgrade now
reports it as "ahead", and treats a move back to main as a downgrade:
explicitly confirmed, with the specific losses named, and blocked
outright where kb_schema_version would drop below what local pages are
already written against.
ckb-module is told not to clobber the template: block — a module install
that silently reset a KB's channel would change what its next upgrade
pulls, which is not a module's business.
Documented in both READMEs, both MANUALs and both CHANGELOGs. VERSION
1.8.0 -> 1.9.0; kb_schema_version stays 1.5, since this is tooling rather
than a content contract.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
27 KiB
| name | description |
|---|---|
| ckb-upgrade | 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". Also use when they name a release channel - "upgrade from the test branch", "check experimental for updates", "switch this KB to the stable channel" - since the template repo keeps main (stable), test (release candidate) and experimental (development) branches; the branch this KB tracks is recorded in ckb.yaml's template block and defaults to main. 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/CHANGELOG.md/CHANGELOG.pl.md, and the base.gitignorerules. Compared via the rootVERSIONfile. 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, plusraw/,outputs/,workload/. Compared viawiki/index.md's ownkb_schema_versionfield (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 0 — Resolve which repo and branch to compare against
Read ckb.yaml at the repo root:
template:
repo: https://git.wierzbowa.cloud/michal/ckb.git
branch: main
That block records where this KB's tooling comes from (written by
ckb-init). Missing file, missing block, or missing field → fall back to the
canonical repo on main, which is what every KB predating this
convention was effectively tracking.
The three channels
| Branch | What it is | Who should be on it |
|---|---|---|
main |
Stable. The released template. | Everyone, by default. |
test |
Release candidate. Validated before merging to main. |
Anyone helping validate a release, or needing a landed-but-unshipped fix. |
experimental |
Development. Active work; may be broken or reverted. | People developing the template itself. |
A user switches channel by saying so: "upgrade from the test branch", "check
experimental for updates", "switch this KB to the stable channel", "I want
the dev version". A branch named in the request overrides ckb.yaml for
this run, and — once the upgrade is actually applied — is written back to
ckb.yaml so the next run stays on the channel the user chose. Do not write
it back on a run the user cancelled: they asked to look, not to move.
Clone shallowly into a scratch location under tmp/ — never touch this
repo's own git remotes or history to do this comparison:
rm -rf tmp/ckb-upgrade-src
git clone --depth 1 --branch <branch> <repo> 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. If it fails specifically because the
branch doesn't exist, list what does (git ls-remote --heads <repo>)
and stop; never quietly substitute main for a branch the user named.
State the resolved repo and branch before doing anything else. On test or
experimental, say what that means in one line — an upgrade that pulls
unreleased or actively-broken tooling into a working KB should never be a
surprise.
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.:
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.
When the local version is higher than the remote's, say so explicitly
rather than reporting "up to date". The two are different facts and only
one of them is reassuring. This happens routinely once channels exist: a KB
that took tooling from experimental sits on a version main has not
released yet, so comparing it against main finds nothing newer — which is
true, and also not what "up to date" usually means to a reader.
Report it as what it is: "local v1.9.0 is ahead of main's v1.8.0 — this KB
is carrying tooling from a pre-release channel." Then ask what they want,
because both answers are legitimate: stay ahead, or downgrade to the
stable branch. A downgrade is a real operation with real consequences — it
can remove skills, remove schema fields that local pages already use, and
lower kb_schema_version below what the content is written against — so
never perform one as a side effect of a channel switch. Name the specific
losses, take an explicit confirmation, and treat a kb_schema_version that
would drop below the local wiki's as a blocker, not a warning: the
content would stop conforming to its own declared contract.
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.mdhas nokb_schema_versionat 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 vX, wiki schema
vY," 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 theCLAUDE.mdsymlink — recreate it if it's missing or isn't a symlink toAGENTS.md; don't diff its content, it's just a symlink)LICENSEVERSIONREADME.md,README.pl.md,MANUAL.md,MANUAL.pl.md,CHANGELOG.md,CHANGELOG.pl.md— whichever exist upstream (an older local KB may not have some of these yet). Take the changelogs from upstream wholesale rather than merging: they record the template's history, which the upstream copy is authoritative about..agents/skills/<name>/**for every skill folder present intmp/ckb-upgrade-src/.agents/skills/.agents/modules/<name>/**for every optional module present upstream (seeckb-module). Upgrade the module payload freely — it is inert template content. But never delete a skill under.agents/skills/just because it is absent upstream: it may be a module-installed copy that this KB deliberately enabled. Checkckb.yamlbefore treating any skill as removed upstream. When an installed module's payload changes, say so and suggest reinstalling it — the installed copies are now stale.- The base ignore rules in
.gitignore(libs/,linked/,tmp/, regeneratedoutputs/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 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):
## 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.mdisn't a symlink toAGENTS.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
VERSIONto the template's new version last, only once every other accepted change has been applied successfully. - If the user switched channel for this run (Step 0), write the new
branch:intockb.yaml'stemplate:block now that the switch has actually happened. Create the file with just that block if it doesn't exist; if it does, edit onlytemplate:and leavekb_modules:exactly as found — that list belongs tockb-module. Persisting the branch is what stops the next upgrade from silently pulling the KB back to whichever channel it was on before.
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.jsonwiki/error-book.md,wiki/overview.md- Any subdirectory under
wiki/entities/-style groupings that's missing its ownindex.mdper 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 underwiki/entities/describing a person, project, library, or concept). Don't silently guess: batch every inferredtypeinto one list and confirm it with the user before writing, sincetypeis 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 wayckb-ingestwould 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 callckb-ingestmakes 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.
b2. Schema 1.4 → 1.5: evidence sections. Schema 1.5 added the reserved
body sections (## Sources, ## Crux, ## Notes), the
source_fingerprint/source_checked frontmatter fields, and the completed
edge vocabulary in wiki/graph/index.md. Migrating a 1.4 wiki:
wiki/graph/index.md— replace its vocabulary section with the template's table verbatim. Existing edges stay valid; 1.5 only added verbs (part_of,produces,configures,validates,implements), it removed none.## Sourceswithout fingerprints — backfill a digest for every cited file that still exists (sha256sum <file> | cut -c1-8), withsource_checkedset to today. Where the cited file is gone, do not quietly drop the bullet: leave it and flag the page, because a page whose evidence has vanished is a finding the migration surfaced, not one it should bury.## Crux— do not manufacture one. A Crux is verbatim source text, and inventing quotes during a migration is precisely the failure the section exists to make impossible. Pages gain a Crux when they are next ingested or deliberately re-grounded, and a 1.5 page with no Crux is fully conformant.## Notes— add an empty one to generated pages underlibs/<name>/so the protected affordance exists. Elsewhere, leave it absent.
These are additive: a 1.4 page with none of them is valid 1.5, so this step
never blocks the version bump. Backfilling fingerprints is worth doing in
the same pass anyway, since it is mechanical and it is what makes ckb-lint
check 12 meaningful from that point on.
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:
## [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
rm -rf tmp/ckb-upgrade-src
Report a summary covering whichever tracks actually ran:
## Upgrade report
**Source:** <repo> on branch **<branch>** (channel: stable / release candidate / development)
**Channel changed:** <old> → <new> (or "no")
**Template version:** v<old> → v<new> (or "already current", or "local vX is ahead of this branch's vY")
**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
-
ckb.yamlexists but has notemplate:block — a KB created before this convention. Treat it as canonical repo onmain, and add the block once an upgrade is actually applied. Don't write it on a check-only run. -
ckb.yamlnames a branch that no longer exists upstream (a dev branch that was merged and deleted) — report it with the list of branches that do exist, and ask which to move to. Don't guess: a deletedexperimentalmay mean "its work is inmainnow" or "it was abandoned", and those lead to different answers. -
User asks to switch channel but declines every proposed change — the switch didn't happen, so don't persist the new branch. They looked at another channel and chose not to take it; recording it would make the next run pull from a channel they rejected.
-
Local
VERSIONis ahead of the target branch — see Step 2. Report it as "ahead", never as "up to date", and treat any downgrade as an explicit, separately-confirmed operation. -
Template repo is this very repo (the template project upgrading itself) — the comparison is between branches of one repo rather than between two repos. That's valid, and the usual flow is
experimental→test→main; but say plainly that this is a self-upgrade, since the "local vs upstream" framing in the report reads oddly otherwise. -
No
VERSIONfile locally — treat local version as0.0.0; any real template version counts as newer. Mention in the report that this KB predates version tracking. -
No
kb_schema_versionin localwiki/index.mdat 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
originis 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/, includingkb_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
typeis 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 at the repository root, or http://www.apache.org/licenses/LICENSE-2.0.