ckb/.agents/skills/ckb-ingest/SKILL.md

195 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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/<YYYY-MM-DD>/`, 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/<name>/`, then each `libs/<name>/`
(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/<entity-name>.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/<name>.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.01.0, based on source corroboration).
- A `quality:` self-score (0.01.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/<name>/...` or `libs/<name>/...`.
### 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/<topic>/` 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/<YYYY-MM-DD>/` 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 <http://www.apache.org/licenses/LICENSE-2.0>.*