Obsidian Canvas Boards
AgriciDaniel/claude-obsidian
Creates, inspects and updates Obsidian JSON Canvas boards in a vault, with text, file, link, group and edge nodes, using safe recoverable edits.
Build and explore a 3D knowledge graph from code, research, stories, or business material in the Pneuma Cosmos workspace.
$ npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install pandazki/pneuma-skills pneuma-cosmos --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/pandazki/pneuma-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/modes/cosmos/skill .claude/skills/pneuma-cosmos && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "pneuma-cosmos" agent skill from https://github.com/pandazki/pneuma-skills/tree/main/modes/cosmos/skill into .claude/skills/pneuma-cosmos/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pneuma-cosmos", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/pandazki/pneuma-skills/tree/main/modes/cosmos/skillType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install pandazki/pneuma-skills pneuma-cosmos --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pandazki/pneuma-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/modes/cosmos/skill .agents/skills/pneuma-cosmos && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "pneuma-cosmos" agent skill from https://github.com/pandazki/pneuma-skills/tree/main/modes/cosmos/skill into .agents/skills/pneuma-cosmos/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pneuma-cosmos", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install pandazki/pneuma-skills pneuma-cosmos --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pandazki/pneuma-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/modes/cosmos/skill .cursor/skills/pneuma-cosmos && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "pneuma-cosmos" agent skill from https://github.com/pandazki/pneuma-skills/tree/main/modes/cosmos/skill into .cursor/skills/pneuma-cosmos/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pneuma-cosmos", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/pandazki/pneuma-skills.git --path modes/cosmos/skill--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install pandazki/pneuma-skills pneuma-cosmos --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pandazki/pneuma-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/modes/cosmos/skill .gemini/skills/pneuma-cosmos && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "pneuma-cosmos" agent skill from https://github.com/pandazki/pneuma-skills/tree/main/modes/cosmos/skill into .gemini/skills/pneuma-cosmos/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pneuma-cosmos", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install pandazki/pneuma-skills pneuma-cosmosInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/pandazki/pneuma-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/modes/cosmos/skill .github/skills/pneuma-cosmos && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "pneuma-cosmos" agent skill from https://github.com/pandazki/pneuma-skills/tree/main/modes/cosmos/skill into .github/skills/pneuma-cosmos/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pneuma-cosmos", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install pandazki/pneuma-skills pneuma-cosmos --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pandazki/pneuma-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/modes/cosmos/skill .opencode/skills/pneuma-cosmos && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "pneuma-cosmos" agent skill from https://github.com/pandazki/pneuma-skills/tree/main/modes/cosmos/skill into .opencode/skills/pneuma-cosmos/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pneuma-cosmos", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
pneuma-cosmosBuild and explore a 3D knowledge graph from code, research, stories, or business material in the Pneuma Cosmos workspace.
Pneuma Cosmos is an agent skill from pandazki/pneuma-skills. Build and explore a 3D knowledge graph from code, research, stories, or business material in the Pneuma Cosmos workspace. Use for creating, extending, or explaining cosmos.json and grounded graph projections.
Its SKILL.md is about 11k tokens, which your agent loads only when the skill is triggered. The skill folder holds 6 other files, including reference files (for example `references/cosmos-schema.md`, `references/node-type-vocabularies.md` and `references/perspective-lenses.md`).
It sits in Knowledge Management, covering Knowledge graphs. The repository describes itself as: Co-creation infrastructure for humans and code agents — visual environment, skills, continuous learning, and distribution. The licence is MIT.
2 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 0023d3c. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships script files (JavaScript), which the agent can run.
Shell commands in SKILL.md call:
brewpdftoppmaptffmpegFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
arxiv.orgFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Pneuma Cosmos loads about 11k tokens when it runs, and up to ~42k if it reads all its reference files. Until then it costs about 56 tokens; SKILL.md has 5,644 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from pandazki/pneuma-skills at commit 0023d3c, republished under its MIT licence (© pandazki). 5,644 words, ~10,560 tokens.
.claude/skills/pneuma-cosmos/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.In script examples, <SKILL_DIR> means the actual directory containing this
loaded SKILL.md. Substitute its full path and keep shell paths quoted. The
runtime installs it under .claude/skills for Claude Code, .agents/skills for
Codex, or .kimi-code/skills for Kimi; use the path given in your instructions.
<!-- pneuma:start -->
You and the user are doing a structured projection together. The
user brings content — a codebase, a short story, a research paper, a
business workflow, a long-form thread — and you turn it into a cosmos:
a graph of typed nodes and labeled edges that lays the work's inner
shape bare. You read, you pick a vocabulary that fits the content's
domain, you write a single cosmos.json. The user explores it as a
player in a live viewer — they pan, zoom, click, ask you to dive
deeper, or redirect your attention to a slice they care about.
"Structured" is what the projection is — not a precondition on the input. Prose can be projected. Conversations can be projected. A photo album with captions can be projected.
The viewer subscribes to cosmos.json. Every time you write it,
the viewer re-lays out and re-renders. The user sees the change live.
A single node — by clicking it. When they do, the chat they send next
will be prefixed with a <viewer-context> block carrying the node's
address (machine-routable) plus its label and summary. You can copy
the address verbatim back into actions that take one.
| Key | Kind | Meaning |
|---|---|---|
nodeId | coarse | A specific concrete node in the cosmos (e.g. { nodeId: "c-eliot" }). |
layerId | coarse | A layer slice (e.g. { layerId: "clues" }). Use this for layer-level operations like focus-layer. |
perspectiveId | coarse | A perspective tour — a variant walk through the cosmos framed by one design lens (e.g. { perspectiveId: "perspective-closed-loop" }). navigate-to an address with this key starts that tour. |
subgraphId | coarse | A user-driven drill subgraph (e.g. { subgraphId: "subgraph-cybernetic-loop-deep" }). navigate-to enters the subgraph view; emit one in a <viewer-locator> after writing the subgraph so the user can click into it. See the Drill-down chapter. |
Nodes, perspective tours, and drill subgraphs are the atomic addressable units. There are no fine keys in v0.1.
navigate-to({ address: { nodeId } }) — Move the viewer to that
node and select it. Use after writing or refining a region of the
cosmos so the user immediately sees what changed.focus-layer({ address: { layerId } }) — Dim everything outside
that layer. Use when the user asks a layer-specific question
("show me only the clues", "what's in the service layer?") or when
you're guiding them through one slice at a time.fit-view() — Zoom out to fit the whole cosmos. Use when you
want the user to see the big picture before diving in.switch-persona({ persona }) — overview (labels only),
learn (labels + summaries — the default), deep-dive (everything,
including tags). Switch up for "give me detail", switch down for
"step back and orient me".capture({ address? }) — Framework-built-in. Take a screenshot
of the cosmos (or a specific node) and read the resulting PNG
yourself. Use this to visually self-verify that the layout
reads cleanly — too many edges in one node? a cluster looks
disconnected? the user shouldn't be the one to catch that.regenerate — User says "the input changed, redo the cosmos".
Re-read inputs and rewrite cosmos.json from scratch.onboard — User wants a guided tour. Make sure tour[] in
cosmos.json is good (refresh it if stale), then step through it
with navigate-to per step, narrating each.Match the user's working language for prose, English for the type
system. Pneuma surfaces the user's locale in three places — listed
in order of authority: (1) the <system-info user-locale="…">
wrapper around your greeting, (2) the <pneuma:env user_locale="…" /> tag in the first system message of the session, (3) the
<!-- pneuma:preferences --> block in your instructions (free-form
prose, e.g. "主要工作语言为中文"). When the env signal is set, follow
it; when only the preferences block speaks, follow that. Apply the
resolved language to every field a human reads as prose:
project.name and project.description, node.name and
node.summary and languageNotes, layer.label and
layer.description, edge description, every tour[].narrative,
every perspectives[].name / insight / evidence. Keep stable
identifiers and the vocabulary in English (kebab-case): all id
fields, node.type (file, character, claim, …), edge.type
(imports, discovers, supports, …), perspectives[].lens
(orthogonality, cybernetic-loop, tension, …). These function
as a type system, not as display text. Don't be misled by the bootstrap
seed — it's English because pneuma-skills itself is an English
codebase. When you project the user's own content, follow their
language. For names that live in the source (filenames, character
names, function names, paper titles), keep them verbatim regardless
of language — those are quoting the source, not labeling it.
One cosmos per workspace. cosmos.json is the single source of
truth at the workspace root. Don't shard. If the user wants two
different projections of the same content, that's two workspaces.
node.type is open string, but pick a coherent vocabulary per
cosmos. Don't mix file + character in the same cosmos — that
signals two different domain projections fighting for the same
graph. If the user's content has multiple natures (e.g., code + its
docs), pick the dominant lens and surface the rest as edges /
attributes, not parallel node-types.
Every node has a layerId, and every layerId exists in
layers[]. Layers drive color + grouping in the viewer. Three
to six is the comfortable range; going to seven or eight is fine
if each layer represents a genuinely distinct concern you can name
in one sentence. Below three feels under-modeled.
Node ids are stable kebab-case prefixed by short layer hint.
Examples: c-eliot (character), cl-x-mark (clue), fn-auth-login
(function). Stability matters: when you re-project, keep old ids
for objects the user has already explored.
Edges have a type (verb) and optional direction. Default
direction is forward. Use bidirectional sparingly — it usually
means you haven't decided which side owns the relationship.
Summaries are one sentence, two at most. The viewer renders them in cards; long summaries break the layout and the gestalt.
Tours are 5–8 steps. If you can't tell the story in eight, the cosmos is doing too much or the layers are wrong.
Every node should cite its source(s). Cosmos is domain-agnostic
— the same protocol covers code, prose, research, conversations,
domain models. The way the user verifies a node is by jumping
to what produced it. Use node.sources[] (see Source references
below) to attach one or more refs per node: a code node cites the
file(s) it abstracts; a character node cites the chapter passages
the character appears in; a claim node cites the paper section and
the dataset URL. Even when the source is "the conversation we just
had", a passage ref pinpointing where in that transcript the
inference rests beats no ref at all.
Set project.sourceRoot when the cosmos has an on-disk root —
and make sure relative source paths resolve against it.
For codebase / notes-folder / manuscript-directory cosmoses, write
the absolute path of the source root into cosmos.project.sourceRoot.
Two reasons it matters:
path / file values on CosmosSourceRef resolve
against sourceRoot, NOT against the session directory. The
session lives at <projectRoot>/.pneuma/sessions/<id>/, which
contains no source material — so a ref like {kind: "file", path: "src/main.ts"} without sourceRoot set produces "Path
does not exist" when the user clicks the chip. Set sourceRoot,
OR write absolute paths. Don't write bare relative paths and
hope the viewer guesses.Leave sourceRoot undefined only when the cosmos genuinely has no
on-disk root (web URLs, transcripts, ad-hoc scattered files) — and
in that case use absolute paths or full URLs on every ref.
Every node carries sources?: CosmosSourceRef[] — one or more
pointers back to the artifacts that produced the node. The viewer
renders each ref as a click-to-open chip in the INFO panel; the
chip's behaviour depends on kind.
| kind | Shape | Opens with |
|---|---|---|
file | { path, range? } | OS default app, or the editor chosen in the editor picker |
url | { url } | Default browser |
passage | { file, locator, quote? } | Underlying file — the chip opens it without jumping; the locator and quote show in the tooltip |
image | { path } | OS default image viewer |
audio | { path, t? } | OS default audio app |
video | { path, t? } | OS default video app |
All kinds accept an optional label to override the auto-derived
chip text.
Every kind also accepts an optional locator?: string and
excerpt?: { path, caption? }. See Visual anchoring for what
they're for and the shell commands to populate them.
Codebase node — typically one or more file refs, often with
ranges narrowing to the relevant span:
{
"id": "ct-mode-manifest",
"type": "contract",
"name": "ModeManifest",
"summary": "...",
"sources": [
{ "kind": "file", "path": "core/types/mode-manifest.ts", "range": [1, 120] },
{ "kind": "file", "path": "modes/cosmos/manifest.ts", "label": "example impl" }
]
}Fiction node — passage refs pinpointing where a character
appears, with a lifted quote so the user can verify the inference:
{
"id": "c-eliot",
"type": "character",
"name": "Eliot Vance",
"summary": "...",
"sources": [
{ "kind": "passage", "file": "chapter-03.md", "locator": "¶12-14",
"quote": "Eliot's hand trembled as he reached for the bell, and the housekeeper saw it." },
{ "kind": "passage", "file": "chapter-07.md", "locator": "¶3" }
]
}Research node — mix of file (paper PDF or transcript) and
url (data source, related work):
{
"id": "claim-baseline-undertrained",
"type": "claim",
"name": "The baseline model was undertrained on long-context tasks",
"summary": "...",
"sources": [
{ "kind": "file", "path": "paper.pdf", "label": "§4.2" },
{ "kind": "url", "url": "https://arxiv.org/abs/2410.12345" },
{ "kind": "file", "path": "data/long-bench.csv" }
]
}file ref to a 5000-line file with no
range is barely a ref — the user can't trust the link. Either
add a range or pick a more specific source.Older cosmos files used a single string field source: string plus
an optional lineRange: [start, end]. The viewer's parser migrates
those to sources[0] (as a file or url ref depending on
http(s) prefix), so older files keep working. New files should
write sources[] directly and skip the legacy fields.
Users open a cosmos to dive into source. They click a node, read your summary, and the very next thing they want is to see the artifact that produced it — the actual paragraph, the actual page, the actual frame. A node without a visual anchor is a node they can't trust. Chips get them there in one click; excerpts get them there in zero.
So: when the source has a real visual you can lift from it, lift
it. Crop the PDF page, save the video frame, screenshot the UI
region. Put the path in excerpt.path and the viewer renders it
inline above the chip strip. The chip remains as the open-the-real-
thing affordance underneath.
Every excerpt.path MUST be a real extract from the source.
Concept imagery belongs on the canvas as a node, not as an excerpt on someone else's node. The whole point of the excerpt is that the user can verify the inference at a glance — that trust collapses the moment you smuggle in generated material.
If the source is genuinely non-visual (a transcript, a CLI log, a
blob of prose), don't fabricate an excerpt to fill the slot. Use a
passage ref with a quote instead — the viewer renders it as a
quote card with the same prominence, and the user still gets the
verifiable extract.
Every ref kind accepts locator?: string. Open-ended hint
about where inside the artifact this node points. Examples:
"p.23" — PDF page"5:32" — moment in audio or video"figure 3" / "§4.2" — section / figure in a paper"verse 14" / "ch.7 ¶3" — passage in prose"slide 7" — deck"bottom-left" / "nav-header" — region in an image / UI"turn 14" — turn in a transcriptWhatever phrasing lets the user find the spot in five seconds.
(On passage the locator is required — same idea; on the other
five kinds it is optional.)
These run on macOS by default; Linux alternatives noted where they diverge. Don't ask the user to install anything you don't need — fall back to chip-only if a tool isn't around.
pdftoppm -f N -l N -png -r 150 paper.pdf out
(requires brew install poppler; Linux: apt install poppler-utils)
Produces out-N.png. The -r 150 gives a readable 150-dpi crop.
Fallback if pdftoppm is missing on a single-page PDF:
sips -s format png paper.pdf --out page.png.sips -c <h> <w> input.png --out cropped.png (center crop), or
sips --cropToHeightWidth <h> <w> --cropOffset <x> <y> input.png --out cropped.png
for a specific region. Verify the flag against the agent's
machine if you're unsure — sips --help lists exact arg names.
Linux: convert input.png -crop <w>x<h>+<x>+<y> cropped.png (ImageMagick).ffmpeg -ss N -i video.mp4 -frames:v 1 -q:v 2 out.png
(requires brew install ffmpeg). Put -ss before -i for a
fast seek.excerpt.locator like "p.N"
or "figure N". Quotes are fine as backup, but when the source
is visual a cropped figure trumps prose every time.file ref + range. Excerpts
are OPTIONAL — only when there's a real visual associated (an
architecture diagram in the docs, a UI screenshot for a frontend
component, an SVG asset). Don't excerpt code as image. The
file ref + line range is already the right primitive — a
screenshot of source code is worse on every axis (no copy, no
scroll, dies on theme change).passage ref with quote lifted
verbatim (≤80 chars) + locator like "ch.3 ¶12". Skip excerpt
unless the book has illustrations and the node is about one.locator naming the area ("nav-header",
"empty-state", "settings: privacy tab"). The viewer's image
card sits right where the user expects to see the thing you're
describing.locator
like "5:32". The video kind already has an optional t —
use it alongside excerpt.path so the chip click jumps the
player to the moment too.passage ref with quote +
locator like "turn 14". Excerpts only when the conversation
includes shared images you want to lift.Default convention: .cosmos-assets/<node-id>/ at the workspace
root. Keeps the cosmos.json clean of giant inline binaries and
makes the asset tree shippable alongside the cosmos.
Examples: .cosmos-assets/claim-baseline/p23.png,
.cosmos-assets/c-eliot/manuscript-folio.jpg. Use your judgement
when the source itself already lives somewhere obvious — a figure
already saved next to the paper at paper/figures/fig-3.png
doesn't need to be copied; reference it where it sits.
CosmosEdge.sources?: CosmosSourceRef[] — same shape nodes use.
Most edges don't need sources; use sparingly and only when the
relationship claim itself benefits from grounding. Examples worth
the citation:
imports edge can cite the import statement's line
range — useful when "A imports B" is non-obvious because the
import is conditional or aliased.supports edge can cite the section that
establishes the support — different from citing the supporting
claim's source, which lives on the node.vanished_near edge can cite the passage that
establishes the disappearance.If an edge is mechanical (a contains edge from a folder to a
file), don't bother — the source belongs on the nodes, not on
the link between them.
When the user opens a fresh workspace, the seed gives them a
bootstrap cosmos — Pneuma Skills projecting itself (contracts,
runtime, backends, modes, shell, reference, ~55 nodes / 6 layers).
Read README.md and skim cosmos.json; understanding the seed is
understanding what cosmos is for. The user typically asks you to
re-project their own content next — that's where you start working.
The first decision each projection is which of two paths produces it:
Workflow tool (Claude Code backend only), hand the
heavy lifting to the projection workflow. It reads every partition in
its own fresh context — so coverage isn't capped by your context —
resolves cross-partition edges, and does the thing you cannot do
reliably under context pressure: verifies every node against its
cited sources, tagging each with a trust level. You stay the
author — you survey, launch it, add the tour, write cosmos.json.Workflow tool
is absent (Codex / Kimi backends). You read and project it yourself,
in the passes below.How to choose: survey first — Glob the source, count files. A handful
of files or a token-light single document → Path B. Dozens of source
files / a real repo you can't hold in one context → Path A. No Workflow
tool → always Path B. Path A currently covers the codebase domain
only; fiction / research / business go through Path B until their
workflow paths land.
Survey (cheap, in-context). Glob the source; read README,
package manifests, entry points. From that decide:
partitions[] — one per coherent subsystem (usually a top-level
dir): { id, label, paths: ["<relative dir/file>", …], hint }.
Each partition is read by its own fresh-context subagent, so
partition by concern a reader cares about, not by file count.layers[] table (3–6, by architectural concern), a
vocabulary ({ nodeTypes, edgeTypes }), the working language,
the absolute sourceRoot, and a projectName.Launch the workflow:
Workflow({
scriptPath: "<SKILL_DIR>/references/projection.workflow.js",
args: { sourceRoot, language, projectName, partitions, vocabulary, layers, maxCompletenessRounds: 2 }
})Watch it in /workflows: Extract (parallel per partition) → Merge →
Verify → Complete (loop-until-dry). It spins up many subagents and
costs real tokens — reserve it for inputs that genuinely exceed one
context, never a ten-file folder (that's Path B).
Take the returned graph. It returns { version, kind, project, nodes, edges, layers, perspectives?, stats } — every node already
carries a trust verdict and real sources[], and perspectives[]
(if present) have already survived a judge panel for groundedness.
Read stats.trust: a healthy run is mostly verified; a pile of
unverifiable means the source wasn't where the extractor thought —
investigate before you ship it.
Then read stats.warnings — a merge that loses something says so,
and an empty warnings is the only run that covered what you asked
for. stats.partitions[] gives one row per slice: failed (its
subagent never came back, even after the one retry) and empty (its
paths held nothing) are both holes in the projection, and
duplicate-only means two of your partitions overlap. Each entry in
stats.droppedEdgeDetail names an id some slice cited and no slice
produced — a missing node, not a bad edge. Do not write
cosmos.json on top of these: re-survey the named paths and project
the gap yourself (Path B passes over that one slice), or tell the
user plainly which region is missing. A silently thin cosmos is
worse than a small one, because it looks finished.
stats is a run report for you, not part of the schema — drop it
when you write cosmos.json, or the file fails validation.
Add the tour (and prune if needed). The workflow writes the
verified graph + perspectives but NOT the overall tour — pick the
5–8 nodes that teach how the cosmos hangs together (tour discipline
below). Write tour[] as { step, nodeId, narrative } per beat —
see the contrast box in Perspective tours for how it differs
from perspectives[].steps[]. If the graph came back denser than a
reader needs, prune trivial nodes here before writing.
Write cosmos.json atomically, then capture({}) to eyeball
readability, fit-view(), and drop a <viewer-locator> to the most
striking node — the same finish as Path B step 8–9.
Read the input. Whatever the user has dropped into the workspace — a file, a folder, a chapter — use Read / Glob / Grep liberally. The projection's quality is gated by how much of the content you actually saw. If the user hasn't dropped anything yet, ask them what they want to project.
Pick a vocabulary. Open references/node-type-vocabularies.md
and find the closest match. Note 3–6 node types and 5–10 edge
types you'll use. Don't lock it in too early — re-pick after
you've read more.
Sketch the layer table. Layers are what kind of node, not what part of the work. Characters / events / clues for fiction; API / service / data / UI for code. 3–6 layers; assign a color per layer (use the seed's palette as a starting point).
Pass 1 — extract nodes. Walk the content sequentially, emit
nodes as you encounter referents. Give each a stable id, name,
layerId, one-sentence summary, and a sources[] array
citing the file paths / passages / URLs that produced it. The
sources are not optional polish — they're how the user verifies
your work (see Source references chapter for the six kinds and
per-domain examples). Also set category when the node clearly
belongs to one (CODE / DOCS / INFRA / DATA / DOMAIN / KNOWLEDGE),
and complexity when you have a sense (the viewer's layer cards
aggregate it). Tags are optional and only worth including when
they help search.
Pass 2 — extract edges. Re-walk with an eye for connections.
Use specific verbs (discovers, authored, vanished_near) over
generic ones (relates_to). Add a description when the verb
alone doesn't tell the story.
Pass 3 — write the tour. Pick the 5–8 nodes that, in order,
teach the user how the cosmos hangs together. The tour is a
reading path, not a complete tour of every node. The shape is a
flat array of { step, nodeId, narrative } — not the
perspective-step shape:
"tour": [
{ "step": 1, "nodeId": "ct-published-language", "narrative": "..." },
{ "step": 2, "nodeId": "sp-omne-core-v1", "narrative": "..." }
]step is a 1-based integer, nodeId is a single node id (string,
not an array), narrative is this beat's paragraph. Do not
write focus here — focus belongs to perspectives[].steps[],
which is a different field with a different shape (see the contrast
box in Perspective tours).
Pass 4 — write perspective tours. (Optional but encouraged.
See the Perspective tours chapter below before doing this.) Step
back from the facts you just wrote. What design lenses make the
cosmos read differently — what variant walks would teach the user
something the overall tour can't? Add 0–6 perspectives[] entries.
Each perspective is a walk, not a tag — it has a thesis
(insight) and an ordered steps[] array; each step has its own
focus (1+ node ids that light up together) and its own
narrative paragraph (what the user is reading on THIS beat, not
the thesis again). Per-step narratives are the discipline knob: if
you can't write a distinct paragraph per step, the perspective
isn't sharp enough yet.
Write cosmos.json atomically. Single Write call. Then
immediately capture({}) to look at the result — verify
readability before you tell the user it's done.
fit-view() then drop a <viewer-locator> card pointing to the
most striking node. Make the user's first click satisfying.
When the user selects a node and asks for depth, don't just write
prose — update the cosmos. Add edges. Add adjacent nodes. Then
navigate-to({ address: { nodeId } }) to bring them back to focus.
regenerate)The input changed substantively. Preserve node ids that still exist so the user doesn't lose their bearings. Diff-aware re-write is preferable to nuke-and-pave when the input is incrementally different.
onboard)If tour[] is empty or stale, regenerate it. Then walk: for each
step, call navigate-to and send a short narrative message. Wait
for the user to nod (or react) before advancing.
A cosmos has more than one way to be read.
tour[] is the overall tour — the single canonical reading path
the agent picks (5–8 steps) for "you've never seen this cosmos before,
here's how it hangs together". One cosmos, one overall tour.
perspectives[] are variant tours — alternate reading paths
through the same cosmos, each framed by a specific design lens:
"where does the system maintain a feedback loop?", "where do the v0.2
and v0.3 abstractions collide?", "where does entropy accumulate?".
Each perspective answers one such question by ordering the nodes
that bear on it and giving the through-line. Same cosmos, different
walks.
The viewer surfaces overall + perspectives side-by-side in the TOUR tab. The user picks one. Picking starts a stepper that walks the chosen nodes in order, with the framing (lens + thesis) shown alongside.
Both the overall tour and each perspective have an ordered walk, and
both call the beats "steps". The field shapes are different, and
mixing them is the single most common cosmos mistake — the symptom is
a tour whose step numbers don't render and whose canvas won't navigate,
because you wrote focus where the viewer expects step + nodeId.
| Field | One beat's shape | Node reference | |
|---|---|---|---|
| Overall tour | cosmos.tour[] | { step: number, nodeId: string, narrative } | nodeId — a single string |
| Perspective walk | cosmos.perspectives[].steps[] | { focus: string[], narrative } | focus — an array of ids |
The tour numbers its beats (step: 1, 2, …) and lights exactly one
node each (nodeId). A perspective does not number its beats and
can light several nodes per beat (focus: ["a", "b"], first is the
primary anchor). narrative is the only field they share. If you find
yourself writing focus inside tour[] or nodeId inside a
perspective step, stop — you've crossed the two.
A perspective isn't a slogan with a few node-id fig leaves. Three practices keep it honest:
Facts before perspectives. Don't write perspectives[] until
you've finished passes 1–3 (nodes, edges, overall tour). A
perspective earned by stepping back from concrete material reads
differently from one composed before the material exists; the user
can tell even if they can't articulate why.
Every perspective must be grounded. Each step's focus[]
names the concrete node ids the beat lands on. If you can't pick
specific ones for every step, the perspective isn't earned.
Delete it. The grounded list is what separates "you can actually
take this walk" from "I'm narrating a vibe".
Per-step narratives, not a refrain. Each step's narrative
must be its own paragraph — what the user is reading on THIS
beat, why these specific focus nodes matter here, what the next
beat will pivot to. Repeating the perspective's overall insight
on every step is the tell that you only had one thing to say.
Cut the perspective down to fewer steps and write each one
sharply, rather than padding the manifestsIn list.
A perspective that walks five focused beats with five distinct narratives is worth more than one that lists eight nodes and repeats the thesis verbatim each step.
Perspectives aren't a fixed catalogue. They're a way of looking — and the agentic-systems literature has crystallized a handful of mental models that name this kind of looking. Treat them as lenses to set on a perspective you're already perceiving, not as boxes to fill.
Some lenses worth recognizing (deeper catalog + per-domain examples
in references/perspective-lenses.md):
When none of these lens names fit, invent. perspectives[].lens is
open vocabulary like node types are. The list above is help, not
grammar.
Do reach for perspectives when:
Don't reach for perspectives when:
The field is cosmos.perspectives[]. Each entry:
{
"id": "perspective-<slug>", // stable kebab-case
"name": "...", // noun phrase in user language
"lens": "cybernetic-loop", // open vocab, English kebab-case
"insight": "...", // 1-paragraph thesis (user language)
"steps": [
{
"focus": ["node-id-a"], // 1+ nodes lit on this beat
"narrative": "..." // THIS step's paragraph
},
{
"focus": ["node-id-b", "node-id-c"], // multi-node beat OK
"narrative": "..."
}
],
"evidence": "...", // optional — why the inference is reasonable
"tags": ["..."] // optional
}steps[] is the walk. Each step's focus is the set of node ids
the canvas lights up together on that beat; narrative is the
paragraph the sidebar shows. The viewer's INFO panel pins to
focus[0]; the rest stay lit alongside.
Backward compat: older cosmos files may have tao[] instead of
perspectives[], type instead of lens, or manifestsIn[]
instead of steps[]. The viewer's parser normalizes all three to
the new shape — files with only manifestsIn[] get steps
synthesized with the perspective's insight reused as narrative
(renders, but degraded). New files should write steps[] with
distinct per-step narratives.
See references/cosmos-schema.md for the full schema.
The overall tour and perspective tours are your pre-curated walks through the cosmos: "I think you'll want to see things in this order". Drill-down is the inverse channel: the user picks one or more nodes, asks "go deeper here", and you generate a focused subgraph on demand.
This pattern is the cosmos's solution to the "must I analyze everything upfront?" problem. The main graph stays a navigable overview; depth is paid for where the user has shown interest.
When the user clicks the Drill into N nodes → button on the
canvas, the viewer dispatches a <drill-request> block as a
system message just before your next turn. It looks like this:
<drill-request>
<anchors ids="node-id-a,node-id-b,node-id-c" />
<parent subgraph-id="subgraph-prev-drill" /> <!-- present only if drilling inside an existing subgraph -->
<anchor-names>node-id-a (Foo), node-id-b (Bar), node-id-c (Baz)</anchor-names>
<prompt>
The user's edited prompt — what they actually want you to analyze
about these anchors. May be in their working language.
</prompt>
</drill-request>When you see this block, do not respond with prose alone. Generate
a CosmosSubgraph, write it to cosmos.json, then emit a
<viewer-locator> card so the user can click into it.
Append a new entry to cosmos.subgraphs[] with the full subgraph:
{
"id": "subgraph-<slug-derived-from-prompt>", // stable kebab-case
"anchors": ["node-id-a", "node-id-b", "node-id-c"],
"prompt": "<verbatim user prompt from the request>",
"status": "ready", // or "pending" → "ready" if two-phase
"generatedAt": "<ISO timestamp>",
"parentSubgraphId": "subgraph-prev-drill", // copy from the request when nested
"title": "<short noun phrase — 4-8 words, user language>",
"nodes": [
{
"id": "sg-<id>", // ids unique to this subgraph; can also reference main-graph node ids to link back
"type": "...",
"name": "...",
"summary": "...",
"sources": [...] // cite where the analysis comes from — see Source references
}
],
"edges": [
{ "source": "node-id-a", "target": "sg-some-new", "type": "...", "description": "..." }
]
}Then in your chat reply emit:
<viewer-locator label="Open the new drill: <title>"
address='{"subgraphId": "subgraph-<slug>"}'/>The user clicks the card → canvas swaps into the subgraph view.
<prompt> text is what the
user wants from THIS drill. If they asked "how do v0.2 and v0.3
collide here?", the subgraph should organize nodes around that
collision — not be a generic expansion of the anchors.sources[] if relevant) before authoring the
subgraph. The drill expands from what the user pointed at.sources: [{kind: "file", path: "...", range: [...]}, ...] is non-negotiable for code; for
prose, use passage refs with quote. See the Source
references chapter.<parent subgraph-id="..."/>
is set, the user drilled inside an existing subgraph. Copy that
id into your new entry's parentSubgraphId field; the viewer
uses it to build a breadcrumb.status: "failed"
entry with a short message explaining why. Don't fabricate.Most drills come from the user clicking the button. But the agent can also write subgraphs unprompted when:
In both cases, follow the same schema; just leave the prompt
field as a brief restatement of what triggered it, and emit the
<viewer-locator> for the user to navigate.
| Topic | File |
|---|---|
| Full schema (TypeScript types + JSON shape + auto-fix rules) | references/cosmos-schema.md |
| Vocabulary catalogs by content domain (code / fiction / research / business / mixed) | references/node-type-vocabularies.md |
| Step-by-step projection workflows per domain | references/projection-workflows.md |
| Perspective-lens catalog — mental models for variant tours | references/perspective-lenses.md |
<!-- pneuma:end -->
© pandazki, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 5 other files (references) in modes/cosmos/skill of pandazki/pneuma-skills.
Open the folder on GitHubat commit 0023d3c
Pneuma Cosmos next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Pneuma Cosmos this skillpandazki/pneuma-skills | 161 | — | ~11k | Automated safety check: Pass | MIT | |
| Obsidian Canvas BoardsAgriciDaniel/claude-obsidian | 15k | — | ~1.4k | Automated safety check: Pass | MIT | |
| Ontology1mancompany/OneManCompany | 442 | 2 repos | ~1.5k | Automated safety check: Pass | Apache-2.0 | |
| Knowledge Graphgnomeria/usbtree | 691 | — | ~1.5k | Automated safety check: Pass | MIT | |
| Graphagenticnotetaking/arscontexta | 3.5k | — | ~4.9k | Automated safety check: Notes | MIT | |
| LLM Wiki Knowledge GraphEgonex-AI/Understand-Anything | 86k | — | ~1.5k | Automated safety check: Pass | MIT |
AgriciDaniel/claude-obsidian
Creates, inspects and updates Obsidian JSON Canvas boards in a vault, with text, file, link, group and edge nodes, using safe recoverable edits.
1mancompany/OneManCompany
Typed knowledge graph for structured agent memory and composable skills.
gnomeria/usbtree
Set up and maintain a lightweight, file-based knowledge graph of the repo — entities, typed relations, decisions, gotchas — so agents load context fast instead of re-exploring the codebase every…
agenticnotetaking/arscontexta
Interactive knowledge graph analysis. An agent skill from agenticnotetaking/arscontexta.
Egonex-AI/Understand-Anything
Detects a Karpathy-pattern LLM wiki and builds an interactive knowledge graph with entities, implicit relationships and topic clusters.
aws-samples/sample-kolya-br-proxy
A skill your agent uses when the user asks about GitNexus itself — available tools, how to query the knowledge graph, MCP resources, graph schema, or workflow reference.
pandazki/pneuma-skills
Explain something by writing it on a board. An agent skill from pandazki/pneuma-skills.
pandazki/pneuma-skills
AI-orchestrated video production on @pneuma-craft. An agent skill from pandazki/pneuma-skills.
pandazki/pneuma-skills
Pneuma Lucid Mode workspace guidelines. An agent skill from pandazki/pneuma-skills.
pandazki/pneuma-skills
Pneuma Plotwise workspace guidelines. An agent skill from pandazki/pneuma-skills.
pandazki/pneuma-skills
Pneuma Sprite Mode workspace guidelines. An agent skill from pandazki/pneuma-skills.
pandazki/pneuma-skills
Pneuma WebCraft Mode workspace guidelines with Impeccable.style design intelligence.
Categories
Build and explore a 3D knowledge graph from code, research, stories, or business material in the Pneuma Cosmos workspace. Pneuma Cosmos is an agent skill from pandazki/pneuma-skills. Build and explore a 3D knowledge graph from code, research, stories, or business material in the Pneuma Cosmos workspace.
Pneuma Cosmos fits situations like: explaining cosmos.json and grounded graph projections; tasks that involve Knowledge graphs.
Run `npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a claude-code`. Or copy the skill folder (modes/cosmos/skill in pandazki/pneuma-skills) into .claude/skills/pneuma-cosmos in your project. Claude Code loads it when a task matches its description.
Run `npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a codex`. Or copy the skill folder (modes/cosmos/skill in pandazki/pneuma-skills) into .agents/skills/pneuma-cosmos in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/pneuma-cosmos, .gemini/skills/pneuma-cosmos, .github/skills/pneuma-cosmos and .opencode/skills/pneuma-cosmos in your project.
Going by SKILL.md and its folder, Pneuma Cosmos needs JavaScript for the scripts in its folder and the command-line tools its instructions call (brew, pdftoppm, apt and ffmpeg). Our summary lists: Node.js.
SKILL.md names 1 domain. In commands or code: arxiv.org; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Pneuma Cosmos is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 11k tokens (SKILL.md is roughly 42k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 31k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Pneuma Cosmos: Obsidian Canvas Boards (AgriciDaniel/claude-obsidian, 15k stars), Ontology (1mancompany/OneManCompany, 442 stars), Knowledge Graph (gnomeria/usbtree, 691 stars) and Graph (agenticnotetaking/arscontexta, 3.5k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
pandazki (a GitHub user) maintains it in pandazki/pneuma-skills, which has 161 GitHub stars. The repository holds 30 skills in this directory. The repository was last updated on October 9, 2026.
Source: pandazki/pneuma-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.