Wiki Update
Extract durable knowledge from the current source — a project, the conversation, a research session — and place it in the user's wiki. Merge before creating, respect the wiki's conventions, and keep every file inside its size cap.
<!-- ws:core -->
The wiki model
A wiki is a folder whose
carries a
heading.
is the navigation contract: every space directly inside is listed there as
- [label](path/index.md) — description
, and tools traverse only what it lists. Spaces nest recursively; each space is itself a wiki one level down. Plain folders (no
) just group files. The markdown dialect is Obsidian — wikilinks, frontmatter, callouts, embeds; the companion
and
skills cover the syntax.
Resolving the wiki
Resolution order: an explicit path from the user → the nearest CWD-ancestor folder that is a wiki, or carries a
folder that is one (a folder's own space) → the
key in
~/.config/wiki-spaces/config
. The user's words override the mechanics: "my wiki" means the configured one even when CWD sits inside another wiki (a company repo, say). When a CWD wiki and a different configured wiki both exist, announce which root you resolved; ask once if intent is ambiguous. Never silently operate on the wrong wiki.
The bundled script
sits next to this SKILL.md — stdlib python3 (3.9+), zero dependencies, read-only. It parses the contract, never the content: structure — traversal, scope, caps, drift — is the script's side; reading and judging meaning is yours. Invoke it by absolute path (your working directory is usually elsewhere):
python3 <skill-dir>/scripts/ws.py list --wiki <root>
— spaces reachable via the contract, each with its entry description ( to cross mounts).
- — markdown files reachable via the contract.
… grep <pattern> [-i] [-F] --wiki <root>
— regex line search over those files, for a literal string (a name carrying metacharacters sweeps exact); prints , exits 1 on no match. The sweep primitive: a link worklist, a tag inventory, an escaping-reference check are each a pattern plus your judgment on the hits.
… check-size <target> [--stdin] --wiki <root>
— cap verdict for a file; pipe planned content with to check before writing.
- — contract drift, entries crossing a space boundary, over-cap or unreadable files, unhealthy mounts. Findings name their repair where one is safe to name (a prints the exact line to add); apply repairs as ordinary edits and re-run the audit to verify — the script never writes.
Trust the script's output over re-deriving structure by hand. Stdout is data; stderr carries the resolved root (
prints it as its stdout header instead) and
advisories naming whatever a walk skipped, the enclosing wiki when the root is nested inside one, and the configured wiki when the root is another — relay them when they could change the answer.
Trust scope and size discipline
Owned vs external is relative to the resolved root: anything under a folder named
(at any depth), a git submodule, or a symlink into either is external; a symlink to a folder outside the tree answers to where it sits, like a clone. Reads cross owned spaces by default and enter external ones only when the user explicitly asks. Writes stay inside the targeted space; any other space — owned or external — is written only on explicit instruction.
Caps are UTF-8 bytes including frontmatter, keyed by basename:
5000,
and
100000, any other
15000.
- Caps belong to the user: a wiki that wants different ones sets them in , and reads them.
- Check caps with : pipe the planned content via before every write, new page or edit — a write that shrinks an over-cap file reports , progress, so repairs converge; a file checked on disk answers to the cap alone.
- An overflow is a signal about shape, not just size: distill the page, reshape the space, or promote a page that has grown into one — never truncate, never raise the cap.
- The exception is : an over-cap log rolls — move it whole to
_archives/log-<YYYYMMDD>.md
and start a fresh one — so the history archives, never shrinks.
Conventions are opt-in per wiki. Read the markers present at the scope root (the space the user targeted, else the resolved root) —
,
,
,
, frontmatter on pages,
,
,
— and degrade gracefully when one is absent. If
exists, append one line per operation:
sh
printf '%s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '<OP> <details>' >> <scope-root>/log.md
<!-- /ws:core -->
Initialization
When nothing resolves — no explicit path, no CWD-ancestor wiki, no valid config — set one up inline: follow
references/init.md, then resume the request. A broken configured path (missing on disk, no
, not absolute) is a hard stop, not a setup trigger — surface it and let the user decide. A folder's own space — asked for ("set up a wiki for this project"), or offered once when a sync targets a folder that has none — follows
references/own-space.md, whether or not a wiki already resolves.
Procedure
-
Resolve the wiki (core block) and announce the root when it came from CWD or could be ambiguous.
-
Detect conventions at the scope root (core block). Presence markers (
, taxonomy,
) never inherit from a parent;
,
, and
follow their nearest-ancestor rule. Skip every step whose marker is absent.
-
Detect the mode from the user's intent — CWD only disambiguates which project, never the mode:
| Mode | Trigger | Input |
|---|
| Direct add | "add this to the wiki", "save this recipe" — a concrete artifact in hand | the handed content |
| Project sync | "sync this project", explicit project naming | project files, git log |
| Conversation capture | "save this", "capture this" — the session itself, no single artifact | the current conversation |
| Research capture | "store this research" | findings from the session |
-
Extract knowledge. Direct add: take the content as handed — your job is placement and dedup, not re-synthesis. Project sync: decisions and rationale, patterns, tool/API wiring, trade-offs, results — from the files and recent git history. Conversation: durable conclusions and decisions, written as facts ("X works by…"), never chat summary. Research: what took effort and would be expensive to re-derive.
-
Filter and deduplicate. Knowledge-capture wikis get the noise filter: answerable from the code or a quick search? skip; needed in 3 months? keep. Content-store wikis (recipes, journals, runbooks) skip the filter — every entry is intentional. Enumerate existing pages via
and rank by filename/path/frontmatter overlap: when a near-match exists,
merge into it instead of creating a sibling.
-
Place. prints each space with its entry description — the placement hints; check top-level plain folders too. Match semantically: knowledge about a source belongs with that source's space when one exists — its own
, or its space in the wiki; knowledge reusable beyond it belongs with its topic. Standing in a folder's own space, that topic's home is the configured wiki the script notes — a second root: name the page and its place there, and on a yes take that root through steps 2 and 5 before writing. Several equally plausible candidates, or none → ask. Flat wiki → write at the root. Names follow the wiki's own pattern — match what existing pages do; where no pattern exists, default to lowercase, hyphenated, ≤50 chars.
-
Check the cap on every write. Pipe planned content before writing:
sh
python3 <skill-dir>/scripts/ws.py check-size <target> --stdin --wiki <root> <<'EOF'
<planned content>
EOF
An edit pipes its planned content the same way (a shrink of an over-cap page reports
); the audit backstops what slips through. On
— never truncate, never ignore, never raise the cap. Re-read the page and its space's index, diagnose why it overflowed, then act:
- Bloat — padding, near-duplicates, prose pasted in raw, entries you wouldn't re-create today → distill: merge, tighten, drop. The cap exists to force this judgment.
- Growth — genuinely distinct topics sharing one file → reshape the space to what it would look like had it been designed for today's content: self-standing sibling pages under a hub, a promotion, or a regrouped layout (Space operations links both procedures).
Both can apply — distill first, then reshape what remains. Update every index you touch. Filenames like or mean a file was split without rethinking the space — never ship them.
An over-cap is navigation debt: push detail into child pages, one line per entry.
-
Write. New pages: nearest ancestor
if present, else the wiki's page shape (frontmatter only where the wiki already uses it). Mark non-source claims
, conflicting sources
. Add up to 2 wikilinks on first natural mentions. Updates: merge, preserve manual content, bump
if frontmatter is in use, never overwrite unrelated sections. On a project sync, record the repo path (
-contracted) on the project's hub page —
/
frontmatter where in use, else one plain line — so a later session maps the checkout to its page. More than ~10 pages changing → show the plan and ask first.
-
Keep the contract. Created a new space, removed one, or moved pages? Update
per
Space operations below.
sections are optional human curation — maintain one where the index already has it. Then check the shape you're leaving: entry descriptions still true, no name that only makes sense historically — small fixes now; bigger reshapes become the close-out's
suggestion.
-
Close out. Run
. Apply the safe structural repairs yourself, re-auditing between rounds until gone:
<!-- ws:safe-repairs -->
- Add the exact entry line a finding prints, then trail it with a — the placement hint every later operation reads.
- Insert the heading a registered bare child lacks — only where the finding's hint asks for the insert; a near-miss hint asks for a rename, which stays reported as author intent.
- Remove an entry the audit says crosses another space's boundary — that space owns the deeper listing; register it there instead when it is missing.
<!-- /ws:safe-repairs -->
An undeclared bare index is a promotion decision — surface it, act only on the user's call. Other findings are reported, not auto-repaired; outside this sync's write scope, suggest a
pass — suggestion only, never run it yourself. Log an
line per the core block and confirm in one block:
with created paths, updated paths, mode, and audit outcome.
Space operations
Create a space (a folder needing first-class navigation):
sh
mkdir -p <root>/<path> && printf '# <Title>\n\n## Spaces\n' > <root>/<path>/index.md
Register it in the nearest ancestor space's
—
- [<name>/](<name>/index.md) — description
, href percent-encoded where the name demands it; the description is the placement hint later operations read. The audit's
finding prints the exact line if in doubt.
Remove a page: sweep for what points at it first —
grep -F '<stem>' --wiki <root>
(every link form carries the stem; judge each hit, code examples aside) — rewrite or drop the real links, prefer a move to
over deletion, then
.
Remove a space: confirm with the user (prefer
over deletion), delete the folder, remove its entry from the parent's
, then
to verify nothing dangles.
Mount someone else's space: references/mount.md. Share a space of yours: references/share.md.
Promote a page into a space — routine once a page's shape asks for it; inventory its links, snapshot, move, rewrite, verify: references/promote.md. Rename, move, merge, or demote a space on the same skeleton: references/restructure.md.