A Claude Code plugin that turns a non-self-grounding conceptual document into a grounded, queryable knowledge graph — a human-editable canon with three-axis provenance, a span-present write boundary, a grounding loop with memory of failures, and a regenerable NetworkX/SQLite derived layer.
It both generates ideas and grounds them — in that order, and never confusing the two.
The graph generates offensively: deterministic discovery mechanisms (bridges, residual
connectability, compression, re-partition, hub transplant, cross-construction ensemble) propose
candidates into a separate hypothesized lane, never gatekept by a quality metric. Then it
judges defensively: the same grounding loop is the filter, applied afterward. A generated
candidate is a hypothesis under test — provenance=hypothesized, epistemic_state=unverified,
no span — and becomes grounded knowledge only when a grounder supplies support, which upgrades
its provenance; the rest are kept forever as negative information that binds the next generation.
Whether generation actually helps ideation is itself a question you measure — see
/kg-experiment (§Stage 8). The portico that stood at the door of imagination is moved to after it.
A prose theory does not verify itself the way code verifies against a parse tree. Its claims "sound right," so a naive extractor turns it into convincing nonsense: vague nodes that touch everything, edges no one ever checked, confident verdicts no one ever earned. This plugin exists to make that failure mode structurally impossible.
A deterministic Python engine (scripts/kg_engine, 496 tests green) does the work that must be
exact — schema validation, span verification, verdict stamping, projection, scrubbing. The
Claude Code session and its subagents do the language work — reading prose, proposing typed
edges, copying spans, arguing the adversarial case — and hand structured JSON back across an
MCP boundary that refuses anything it cannot ground.
Two layers, one source of truth:
- Canon —
${CLAUDE_PROJECT_DIR}/canon/<node-id>.md. One human-editable Markdown file per node (YAML frontmatter + free body); directed edges live in the source node'sedges:block. The canon carries the grounding state. It lives in your project, not in the plugin, is diffable, and is the single source of truth. You can hand-edit it. - Derived —
${CLAUDE_PLUGIN_DATA}/derived/{graph.json,index.sqlite}. A NetworkX node-link graph plus a SQLite index, regenerated from the canon by the projector. It is disposable and contains nothing the canon does not. Delete it and reproject; a verdict in the canon survives reprojection because the reconciler re-attaches it.
The derived layer precomputes only honest, cheap signals: local degree (advisory) and a labelled structural-bridge signal (a node whose neighbors span ≥2 Leiden communities).
A claim is not "good" or "bad" on a single number. Three independent axes:
| axis | values | answers |
|---|---|---|
provenance |
span-present | inferred | hypothesized |
Is there a verbatim span to check? |
authored_by |
deterministic | agent | human |
Who put this here? |
epistemic_state |
unverified | grounded | rejected | failed | obsolete |
Has it survived checking? |
A span-present, agent-authored edge that is still unverified is a perfectly ordinary, honest
object: well-sourced, but not yet a verdict.
These are enforced by the engine — agents cannot opt out:
- span-present (§1.5). Every non-deterministic edge MUST carry a
spanthat is a verbatim substring of the source (whitespace/case-normalized). No span →REJECTED/no-supporting-span. A span not found in the source →REJECTED/span-not-in-source(fabrication). Spans are copied exactly, never paraphrased. - never-forge-a-verdict (§1.4/§1.8). A write payload may not assert
grounded/rejected/failed, norauthored_by=human. Such a payload isDEMOTED(verdict reset tounverified; human stripped to agent). Verdicts are applied only throughkg_ground, which stampsverdict_by/verdict_atand appends an audit record. The reconciler re-quarantines any out-of-band verdict edit that lacks a matching audit record. - generality confound → degree advisory + gated specificity metric (§1.6). A vague node
accumulates spurious edges and spuriously high betweenness — it "looks central while
explaining nothing." So degree is the honest MVP advisory, and
specificity-weighted betweenness stays gated until validated by the harness. Grounders
must reject edges that are "true" only because they are generic/unfalsifiable
(verdict reason:
vague). - memory of failures (§1.7).
rejected/failededges are negative information — never pruned by the projector, surfaced inkg_contextasfalsification_counters. The adversarial grounder creates these: typedattacked_byedges pluskg_ground(verdict="failed"). A claim that collapses into a known failure is rejected on sight. - validation at two points. Extraction precision is gated at build time
(
f4_probe.py score≥ 0.70) and the bridge metric is gated at ground time (kg_engine.harness specificity) before any specificity-weighted ranking is trusted. - PII scrub on egress (§1.9).
kg_scrub(the egress scrub tool) wrapsScrubber(sensitivity): secrets (always) + PII (per sensitivity) are redacted with consistent placeholders (⟦SECRET:1⟧etc.) before text is handed to a subagent. Egress scrubbing is now wired intokg_writetoo: span verification restores placeholder spans to the original source text for the canon (the boundary stores the restored original span), so scrubbing never breaks grounding.
The reason these are invariants and not lint rules: the boundary returns one of
ACCEPTED | DEMOTED | QUARANTINED | REJECTEDper item, and the canon is only ever written through it.
This is a Claude Code plugin. From inside Claude Code (works in both the CLI and the Desktop app), run these two commands:
/plugin marketplace add sergiparpal/creativity-graph
/plugin install creativity-graph@sergiparpal
The first command registers this repo as a plugin marketplace (Claude Code reads
.claude-plugin/marketplace.json from github.com/sergiparpal/creativity-graph); the second
installs the creativity-graph plugin from it. Restart the session if prompted so the plugin's
hooks and MCP server load.
For local development instead of installing from GitHub, point Claude Code at this checkout:
claude --plugin-dir /path/to/creativity-graph.
Updating to the latest version. If you don't have the latest version installed, update it from inside Claude Code:
/plugin marketplace update sergiparpal
/plugin install creativity-graph@sergiparpal
On SessionStart a cross-platform hook (hooks/provision.mjs → an OS launcher →
scripts/bootstrap.py) provisions an isolated engine venv under ${CLAUDE_PLUGIN_DATA}/.venv in a
detached background process, so it never blocks the session. It uses uv when present and falls back
to the stdlib venv + pip otherwise — only Python ≥3.10 and Node (always present in Claude Code) are
required, on Windows, macOS, Linux, or WSL/Git-Bash. The MCP server (.mcp.json → node scripts/launch_server.mjs) self-heals the venv in the foreground if it is spawned before the build
finishes, so it starts cleanly on a fresh machine. The launcher is a persistent supervisor: it logs
every engine lifecycle event to <KG_DATA>/server.log, self-heals a crashed engine, isolates a
cancelled request to that one call (the connection stays alive), and turns a dropped stdio transport
into a clean automatic reconnect — no manual /mcp reconnect. See
Installation system in CLAUDE.md for the full chain.
/plugin install says Plugin "creativity-graph" not found in marketplace "sergiparpal" — even
though /plugin marketplace add reported success. This is a stale marketplace cache, not a
problem with the published manifest. marketplace add reports "Successfully added" even when it reuses
an existing cached clone of the marketplace (under ~/.claude/plugins/marketplaces/<name>/), so an old
clone that predates the plugin entry hides it from the install lookup. Fix it in order:
# 1. Refresh the cached manifest, then retry the install:
/plugin marketplace update sergiparpal
/plugin install creativity-graph@sergiparpal
# 2. Still "not found"? Remove and re-add the marketplace fresh:
/plugin marketplace remove sergiparpal
/plugin marketplace add sergiparpal/creativity-graph
/plugin install creativity-graph@sergiparpal
If it still fails after that, delete the cached clone (rm -rf ~/.claude/plugins/marketplaces/sergiparpal) and restart Claude Code — the in-session marketplace
registry isn't always refreshed until restart — then redo step 2. As a last resort, confirm the machine
can actually reach GitHub (a failed clone silently falls back to cache); anything other than 200 here
is a network/access problem on that machine, not the repo:
curl -sS -o /dev/null -w "%{http_code}\n" \
https://raw.githubusercontent.com/sergiparpal/creativity-graph/main/.claude-plugin/marketplace.jsonThe canon is one Markdown file per node, so two machines (or two branches) editing the same node
hand git a textual 3-way merge that mangles the edges: list and — worse — can silently keep one
side's grounding verdict. A semantic merge driver ships for this: it unions edges by their deterministic
edge_id and, when both sides carry the same edge at a different epistemic_state, resolves the
merged edge to unverified (clearing verdict_by/verdict_at) — never to either side's verdict. It
is the out-of-process mirror of the in-engine Canon._merge_into_existing.
It is not auto-installed (pure git plumbing; the plugin never writes to your repo's git config).
Opt in once per canon-vault clone — add the routing line to the vault's .gitattributes (this repo
already ships one) and register the driver:
echo 'canon/*.md merge=kgcanon' >> .gitattributes
git config merge.kgcanon.name "creativity-graph canon merge"
git config merge.kgcanon.driver "node ${CLAUDE_PLUGIN_ROOT}/scripts/canon_merge_driver.mjs %O %A %B"
# (substitute the absolute path to the plugin checkout if ${CLAUDE_PLUGIN_ROOT} isn't exported in your shell)After a merge: edges are preserved, conflicting verdicts are demoted to unverified — re-ground the
demoted edges (/kg-ground) to re-earn the verdict. The driver can only ever write unverified on
a conflict, so it cannot forge a verdict; a verdict that survives a clean merge with no local audit
record is re-quarantined by the per-session reconciler anyway. (Sharing verdicts across machines — a
syncable audit log — is a deliberately deferred follow-up; see CHANGELOG.md.)
/plugin install creativity-graph@sergiparpal opens a Configure creativity-graph screen
listing the four options below and a final Save configuration row:
❯ Source document path
Egress sensitivity
Metrics mode
Extraction wave size
Save configuration
These are free-text fields, not menus — there are no preset choices to pick. Claude Code's
userConfig schema has no enum/options support, and all four keys are declared "type": "string", so each renders as a text box you type into (not a selectable list). Move between rows
with ↑/↓, type a value into a field — or leave it blank to accept its default — then choose
Save configuration. Pressing Enter on a row without typing just leaves that field at its
default and moves on: harmless for the bottom two, but not for the source path (see below).
The userConfig table just below is the per-option reference; in short:
- Source document path — you must set this. Type the absolute path to the Markdown/text
file you want graphed (or a directory/glob of
.md/.txtfiles), e.g./home/you/notes/theory.md. It has no default. Leave it blank and the build runs without error but produces an empty, unusable graph: with no source text to verify against, every extracted edge is rejectedspan-not-in-source. (The engine'sexamples/source.mdfallback is resolved against your project directory — where that file does not exist — so it only ever fires when you run from inside this repo checkout, never for an installed plugin.) Always enter an absolute path here. - Egress sensitivity — optional, defaults to
medium. Leave blank, or type exactly one oflow/medium/high. An unrecognized word silently behaves asmedium(thoughkg_pingechoes back whatever you typed), so stick to the three words. - Metrics mode — optional, defaults to
structure_only. Leave blank.structure_onlyis the only value that does anything;with_embeddingsis inert (the engine never branches on it — the formersqlite-vsspath was removed). - Extraction wave size — optional, defaults to
6. How many section-extractor subagents/kg-buildlaunches concurrently per wave (bounded parallelism). Type an integer 1–10; higher is faster but applies more rate-limit/lock pressure. Unset / non-numeric /< 1falls back to6;> 10clamps to10. Unlike the other three, this is an orchestration knob the/kg-buildcommand consumes — the engine never reads it — so changing it needs no server restart, and a one-off run can override it inline (/kg-build <source> <wave_size>) without touching config.
Changing it after install. The values are stored in settings.json under
pluginConfigs["creativity-graph@sergiparpal"].options. To change them, edit that block (user
scope ~/.claude/settings.json, or project scope .claude/settings.json) and run
/reload-plugins, or re-open the configure screen from the /plugin menu. Confirm the server
picked up the change with kg_ping(), which echoes {metrics_mode, sensitivity, …}.
| option | values | default | effect |
|---|---|---|---|
source_path |
absolute path — a file, directory, or glob of .md/.txt |
none — set this | the document(s) the graph is built and grounded against. A single file is the common case; a directory or glob (R4) builds from every .md/.txt member, and each edge's span is verified against the specific file it came from (source_file). Effectively required: there is no default, so until you set it the graph has nothing to verify spans against. (Markdown/text only — no PDF/media.) |
sensitivity |
low | medium | high |
medium |
egress scrubbing: low = secrets only; medium = + structured PII; high = + person/address heuristics. |
metrics_mode |
structure_only |
structure_only |
the only effective value: graph structure is the bridge signal. The engine never branches on this (it is stored and echoed by kg_ping only), and there is no enum constraint — an embeddings path is not implemented (the former sqlite-vss candidate generator was removed), so any other value is inert. |
extract_wave_size |
integer 1–10 (as a string) | 6 |
how many kg-extractor subagents /kg-build launches concurrently per wave (bounded parallelism). An orchestration knob the command/skill consumes (${CLAUDE_PLUGIN_OPTION_EXTRACT_WAVE_SIZE}) — the engine never reads it, so it is the one userConfig key with no build_engine_from_env read. Unset / non-numeric / < 1 → 6; > 10 → 10. Override inline for one run with /kg-build <source> <wave_size> (precedence: inline arg > this option > default). Higher = faster but more rate-limit/lock pressure; a wave's brief kg_write calls funnel through the one single-threaded MCP server and serialize there, with the canon's single-writer lease as the cross-process safety guarantee, so a build is never dropped or corrupted regardless of size. |
⚠️ Setsource_pathfirst. It has no default. If it is left unconfigured, every extracted edge fails the span-present check (REJECTED: span-not-in-source) because there is no source text to verify against — the graph builds but is empty/unusable. Point it at the absolute path of the document you want grounded (the bundledexamples/source.mdis only used as a fallback when you run from inside this repo).
Confirm the server sees your config:
mcp__plugin_creativity-graph_creativity-graph__kg_ping()
→ {name, version, metrics_mode, sensitivity, pack_loaded}
A plain-English walkthrough for using the plugin after it's installed and configured (the two sections above). No coding — you'll type a few short commands and ask questions in normal words.
You give it a document full of ideas — a theory, an essay, a set of notes. It reads that document and builds a map of the ideas and how they connect — and it checks every connection against your original text instead of taking it on faith. It will never tell you "this idea is good." It only tells you which claims actually hold up against what you wrote, and which ones don't.
Think of it as a careful research assistant who refuses to repeat a claim back to you unless they can point to the exact sentence that supports it.
- Commands you type yourself. These start with a slash (
/), like/kg-build. You type them straight into Claude Code — these are the main buttons you press. - Helpers Claude runs for you. These have names like
kg_ping(no slash). You don't type these — you just ask Claude in plain English ("check that the creativity-graph server is running") and it runs the right helper behind the scenes. The slash commands use these helpers automatically.
Rule of thumb: anything with a /, you type. Anything without a /, you just ask for in normal words.
About the brackets below.
<angle brackets>mean a detail you must fill in;[square brackets]mean an optional detail you can leave off for a sensible default. (Same notation as the rest of this README.)
Step 1 — Point it at your document. The map is built from one specific document, set as the source_path
option on the configure screen (see The install config screen and the userConfig table just above).
Just trying it out? The repo ships a demo document at examples/source.md.
Step 2 — Check it's awake. Before building, make sure the plugin is connected and running. There's no command to type — just ask Claude something like:
"Check that the creativity-graph server is running and show me its settings."
Claude runs the health check (kg_ping) and reports back the version and your settings. (You can also type
/mcp to see every connected server and confirm creativity-graph is in the list.)
Step 3 — Build the map.
/kg-build [source_path]
Leave [source_path] off to use the document from your settings (Step 1); add a path to build from a
different file just this once. Claude reads your document section by section — several sections at once, so
it's quick — and builds the map. Every connection it draws has to quote an exact phrase from your document;
if it can't, that connection is thrown out. When it finishes, you have a first draft of the map. (There's
also an optional speed setting, extract_wave_size, in the config table above — you can ignore it to start.)
Step 4 (optional) — Check the map is accurate.
/kg-eval [graph.json]
Grades how accurate the map is before you rely on it (leave the bracket off to grade the current map). If the score is too low, the map isn't trustworthy yet, and you'd want to revisit your source document.
Step 5 — Fact-check the connections.
/kg-ground [query-or-node-filter]
The heart of the plugin. It goes through every connection that hasn't been checked yet and decides whether it really holds up — keeping the good ones, rejecting the vague or unsupported ones, and even actively trying to disprove the strongest claims. Anything that fails is kept on record as a known weakness, not quietly deleted. Leave the bracket off to check everything not yet checked; add a topic or area to check just that part.
Step 6 — Ask questions.
/kg-query <question>
The question is required — it's the thing you want answered. For example:
/kg-query What does the document say about compression?
Claude answers using only what's in the map, and for every part of its answer it shows you the supporting evidence and whether that evidence has been fact-checked. If something hasn't been verified, it says so instead of pretending it's solid.
Step 7 (optional) — Test whether it actually helps.
/kg-experiment [prompts_path]
Runs a fair test of whether the map genuinely helps you come up with ideas, compared to not using it — so you find out whether it's worth the effort instead of assuming (leave the bracket off to use the built-in prompts).
- Your map is a set of plain files you can edit by hand. They live in a
canonfolder inside your project, one file per idea. Nothing is hidden in a black box. - You can't break it by deleting the working copy. The plugin keeps a separate, regenerable copy for speed; if it ever gets messy, you can rebuild it and lose nothing.
- The usual order is: point at a document → build → (check) → fact-check → ask questions. The two optional
steps (
/kg-eval,/kg-experiment) are about measuring quality, not everyday use.
So far you've built a map and fact-checked it. You can also flip it around: instead of only verifying what's already in your document, ask the map to propose new ideas from the way its concepts connect — and then fact-check those the exact same way. The design idea is generate freely, judge strictly: new candidates are never accepted just because they look clever; they only "stick" once grounding finds real support for them, and the ones that fail are remembered, not deleted. Three optional commands:
/kg-generate [mechanism] [k]— ask the map to suggest new idea candidates from its own structure (for example, surprising links between distant topics, or a single idea that could absorb a whole cluster of others). They land as clearly-marked proposals — then the very next/kg-groundis the filter that keeps only the ones it can support./kg-perturb [second_source_or_pack]— build a second version of the map (a different angle on the same material, or a second document) and cross-compare, to surface connections the first map would have missed on its own./kg-view [html|report|all]— produce a self-contained, offlinegraph.htmlyou can open in a browser, plus a writtenGRAPH_REPORT.md, so you can see the map (rejected claims and all) instead of only querying it. It's a read-only snapshot — it never changes the map.
The first five are the everyday flow; the last three are the optional "going further" commands above.
| Command | What it does | The detail in brackets |
|---|---|---|
/kg-build [source_path] |
Build the map of ideas | Optional: a document to build from (defaults to your settings) |
/kg-ground [query-or-node-filter] |
Fact-check the connections | Optional: limit it to one topic or area (defaults to everything) |
/kg-query <question> |
Ask a question, answered from the map | Required: your question |
/kg-eval [graph.json] |
Grade how accurate the map is | Optional: which map file to grade (defaults to the current one) |
/kg-experiment [prompts_path] |
Test whether the map really helps | Optional: a file of test prompts (defaults to the built-in set) |
/kg-generate [mechanism] [k] |
Propose new idea candidates from the map | Optional: which mechanism, and how many (defaults to a sensible set) |
/kg-perturb [second_source_or_pack] |
Stress-test coverage with a second map | Optional: a second document or setup (defaults to a re-angle of the same source) |
/kg-view [html|report|all] |
Make a visual + written view of the map | Optional: which artifact to render (defaults to both) |
Remember: the status check (kg_ping) and the other behind-the-scenes helpers have no slash; you just ask
Claude for them in plain words.
creativity-graph/
├── .claude-plugin/plugin.json # manifest + userConfig
├── .mcp.json # MCP server "creativity-graph" (node → launch_server.mjs)
├── commands/ # slash commands (the orchestration layer)
│ ├── kg-build.md # /kg-build — extract → canon → project
│ ├── kg-ground.md # /kg-ground — grounding loop + adversarial red-team
│ ├── kg-generate.md # /kg-generate — discovery mechanisms → hypothesized lane
│ ├── kg-perturb.md # /kg-perturb — external structure + ensemble cross-generation
│ ├── kg-query.md # /kg-query — answer with provenance + counters
│ ├── kg-view.md # /kg-view — render graph.html + GRAPH_REPORT.md (read-only)
│ ├── kg-eval.md # /kg-eval — extractor precision + α reliability (Stages 4/7)
│ └── kg-experiment.md # /kg-experiment — blind ideation eval (Stage 8)
├── agents/ # subagents (the language layer)
│ ├── extractor.md # kg-extractor → kg_write
│ ├── grounder.md # kg-grounder → kg_ground (grounded/rejected)
│ ├── adversarial-grounder.md # kg-adversarial-grounder → attacked_by + kg_ground(failed)
│ ├── generator.md # kg-generator → phrase/name candidates → kg_propose
│ ├── annotator.md # kg-annotator → f4_probe labels / α label passes
│ └── evaluator.md # kg-evaluator → blind ideation experiment (control|graph|graph+generate|rag)
├── skills/creativity-graph/ # SKILL.md operating guide + references/
├── pack/{pack.yaml,glossary.md} # the declared vocabulary
├── hooks/ # SessionStart provisioning + PreToolUse context (cross-platform)
│ ├── hooks.json
│ ├── provision.mjs # SessionStart dispatcher → provision.sh / provision.ps1
│ ├── provision.sh provision.ps1 # OS launchers → bootstrap.py --background
│ └── precontext.mjs precontext.py
├── examples/source.md # the demo corpus (a theory of grounded knowledge)
├── scripts/
│ ├── kg_engine/ # the deterministic engine
│ │ ├── model.py boundary.py canon.py reconciler.py
│ │ ├── atomicio.py groundaudit.py graphio.py # IO/durability leaves (atomic writes · §1.8 audit log · node-link IO)
│ │ ├── projector.py scrub.py pack.py harness.py sources.py # sources.py = R4 multi-doc SourceSet
│ │ ├── generate.py operations.py # the generative layer (discovery mechanisms + §8 endo ops)
│ │ ├── export.py templates/graph_html.py # R1 human-facing render (kg_export → graph.html)
│ │ ├── canonmerge.py # R5 semantic git merge driver for per-node canon
│ │ └── backend.py server.py # headless extract CLI + FastMCP server
│ ├── bootstrap.py # cross-platform self-provisioning installer (uv | venv+pip)
│ ├── launch_server.mjs # Node MCP supervisor (pointer + catch-up; logs lifecycle, self-heals)
│ └── f4_probe.py # extraction-precision scorer CLI
└── tests/ # pytest suite
Server name creativity-graph ⇒ tools are namespaced mcp__plugin_creativity-graph_creativity-graph__<tool>. The
fourteen verify/read tools (kg_ping, kg_scrub, kg_write, kg_ground, kg_rename, kg_metrics,
kg_status, query_graph, get_node, get_neighbors, shortest_path, kg_context, kg_agenda, kg_export) plus the
four generative-layer tools (kg_propose — the hypothesized write lane; kg_generate — the discovery
mechanisms; kg_operate — the §8 endo operations; kg_absorption — the §14 absorption window) are the
eighteen and only graph tools (no kg_build/kg_query/kg_project tools exist — those are slash
commands).
| tool | purpose |
|---|---|
kg_ping() |
{name, version, metrics_mode, sensitivity, pack_loaded} — health + config. |
kg_scrub(text=None) |
the §1.9 egress scrub → {scrubbed, redactions, sensitivity, categories}; redacts secrets (always) + PII (per sensitivity) with consistent placeholders (⟦SECRET:1⟧ etc.) before text reaches a subagent. No-op (0 redactions) on the no-PII demo source. |
kg_write(payload, idempotency_key=None) |
the span-present write boundary → {dispositions, details[], written_nodes[], rolled_back, error, receipt}; egress scrubbing is wired in here too — placeholder spans are restored to the original source text for the canon. Every response carries a deterministic receipt (a hash of the payload's target ids); an optional idempotency_key makes a retry of a write whose transport response was lost a true no-op that replays the same receipt (idempotent_replay: true) — never a duplicate. |
kg_ground(target_id, verdict, kind, note) |
the only way to set a verdict (always attributed to the agent — by is not a parameter); verdict ∈ {grounded, rejected, failed, obsolete}, kind ∈ {edge, node}. |
kg_rename(old_id, new_id) |
rename a node and re-key its edges. |
kg_metrics() |
{nodes, edges, edges_by_epistemic_state}. |
kg_status() |
cheap, projection-FREE status + coverage probe (reads only the canon, never opens the derived db) → {ok, version, nodes, edges, edges_by_epistemic_state, nodes_by_epistemic_state, unverified_edges, coverage:{files[],sections[]}, derived_present, projection_degraded}; reports the unverified grounding-queue size and which source files/## sections already have an anchored edge — for confirming progress and resuming a partial build after a transport hiccup. |
query_graph(node_type, relation, epistemic_state, limit) |
filtered {nodes[], edges[]}. |
get_node(node_id) |
a node dict with its incident edges. |
get_neighbors(node_id, relation) |
[edge dicts]. |
shortest_path(source, target) |
`{path: [node_ids] |
kg_context(query, budget) |
budgeted context pack: {items[] (grounded), hypotheses[] (the separate hypothesized lane), approx_tokens, budget, falsification_counters:{failed_or_rejected_edges}, advisory:{signal:"structural-bridge", note, nodes[], bridge_metric, stale_verdicts[]}}. |
kg_agenda(limit=5) |
read-only structural "suggested questions" (R6) → {answerable_now[] (well-grounded), blocked_on_grounding[] (orphans / hypothesized-only / under-grounded hubs / disconnected clusters), ranked_by, gate_on, count, note}. Suggests, never acts; heuristic, not a guarantee. |
kg_export(kind="all") |
read-only human-facing render (R1) → {ok, kind, html_path, report_path}; writes a self-contained offline graph.html (three axes on independent visual channels; failed/rejected edges drawn) + GRAPH_REPORT.md under the derived dir. kind ∈ {html, report, all}. Disposable view, never a write to the canon. |
kg_propose(payload) |
the hypothesized write lane → the kg_write shape + {propose_lane, refused_text_claims}; forces provenance=hypothesized, refuses text claims. |
kg_generate(mechanism, k, second_graph) |
read-only discovery → {mechanism, k, gate_on, count, candidates[], note}; bridge|seed|compression|regroup|transplant|ensemble. |
kg_operate(op, …) |
the four §8 endo ops (collapse|explode|regroup|open) — write via the propose lane → the kg_propose shape + {ok, op, info}. |
kg_absorption() |
the §14 absorption window → {tracked, summary, nodes:{id:{half_life, status}}, note}. |
What the extractor emits to kg_write, grounded in examples/source.md:
idis optional (slugged fromlabel).edge.idis derived deterministically ase_{source}__{relation}__{target}(slugged); identity is(source, relation, target).- The boundary auto-creates a placeholder node for an edge's
sourceif absent fromnodes[]; targets may reference not-yet-created nodes. retryable=falsefor semantic rejections (no-span, span-not-in-source);retryable=truefor transport failures (truncation, schema-invalid) — so the orchestrator knows whether to retry.
The declared vocabulary. Types outside these lists are QUARANTINED as undeclared-type,
never silently accepted.
- node_types:
compression,primitive,claim,metric,operation,failure - edge_types:
grounds,attacked_by,reconciles_with,bridges,collapses_into,confounded_by,approximates,defends_against,projects,survives
The pack also seeds per-term specificity (IDF-like) so vague terms (idea 0.4, thing 0.2) are
not mistaken for bridges, while rare terms (betweenness 2.4, specificity 2.2) can be.
Validate it:
python -m kg_engine.pack validate pack/pack.yaml examples/source.md # PackContract + coverageRun from the repo with the engine venv (/home/sergi/creativity-graph/.venv/bin/python) or
uv run:
uv sync # provision the engine venv (dev; the plugin runtime uses scripts/bootstrap.py)
uv run pytest tests/ -q # → 496 passed
claude plugin validate --strict # validate the plugin manifest + componentsDeterministic CLIs used by the commands/agents:
# Extraction precision (build-time gate)
python scripts/f4_probe.py summary derived/graph.json
python scripts/f4_probe.py sheet derived/graph.json --n 80 --out labels.csv
python scripts/f4_probe.py score labels.csv # PRECISION (gate ≥ 0.70), astrology rate, span-support rate
# Harness (ground-time / experiment gates) — all emit JSON
python -m kg_engine.harness agreement label_sets.json # Krippendorff α (≥ 0.67 reliable)
python -m kg_engine.harness specificity derived/graph.json examples/source.md # bridge-metric gate verdict
python -m kg_engine.harness ideation outputs.json # control|graph|graph+generate|rag scoringf4_probe verdict vocabulary (the only labels an annotator may emit):
correct | fabricated | vague | wrong_type, plus span_found: y | n.
model (enums + Node/Edge + span_verifies) · boundary (validate_payload) ·
canon (Canon, atomic git-backed writes) · reconciler (re-attach verdicts, re-quarantine
forgeries) · groundaudit (GroundAuditLog — the §1.8 grounding-audit log the reconciler reads for
forge detection) · atomicio (atomic_write_bytes/atomic_write_text) · graphio (node-link IO —
_node_link_data/node_link_graph/node_attr) · projector (project, kg_context) · scrub
(Scrubber) · pack (PackContract, coverage) · sources (SourceSet — R4 multi-doc ingestion) ·
harness (agreement/specificity/ideation) · generate (run_generators — the six discovery
mechanisms) · operations (the four §8 endo ops) · export (build_html/build_report/export —
R1 human-facing render) · canonmerge (semantic git merge driver — mirror of
Canon._merge_into_existing) · backend (BackendExtractor — headless extract) · server
(KGEngine + FastMCP tool registration).
MIT © Sergi Parpal
{ "nodes": [ {"label": "Compression", "node_type": "compression", "file_type": "prose", "provenance": "span-present", "authored_by": "agent", "epistemic_state": "unverified", "body": "A single idea that stands in for many observations."} ], "edges": [ {"source": "generality-confound", "target": "specificity", "relation": "attacked_by", "provenance": "span-present", "authored_by": "agent", "epistemic_state": "unverified", "span": "a more specific claim, when it holds, defeats a vaguer one", // VERBATIM substring of the source "source_file": "source.md", "confidence": "INFERRED", "confidence_score": 0.6, "notes": ""} ], "complete": true // MUST be true; false/missing ⇒ REJECTED as truncated }