Agent skill

Pneuma Cosmos

by pandazki in pandazki/pneuma-skills

Build and explore a 3D knowledge graph from code, research, stories, or business material in the Pneuma Cosmos workspace.

MITAuto-check passedKnowledge Management

Install Pneuma Cosmos

skills CLI
$ npx skills add pandazki/pneuma-skills --skill pneuma-cosmos -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install pandazki/pneuma-skills pneuma-cosmos --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ 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-src

Use ~/.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/

Facts

Skill name
pneuma-cosmos
GitHub stars
161
Token cost
~11k tokens
SKILL.md length
5,644 words
Files
6 (incl. references)
Skills in repo
30
Repo updated
First seen
Licence
MIT

At a glance

Build and explore a 3D knowledge graph from code, research, stories, or business material in the Pneuma Cosmos workspace.

  • Works in 2 steps: The viewer's INFO tab renders an "Open… → **Relative path / file values on…
  • Explaining cosmos.json and grounded graph projections
  • SKILL.md covers Scene, Viewer contract, Core rules and Source references, plus 3 more sections
  • Runs JavaScript scripts from its folder; calls brew, pdftoppm and apt; reaches arxiv.org

What it does

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.

When your agent uses it

  • Explaining cosmos.json and grounded graph projections
  • Tasks that involve Knowledge graphs

Example prompts

  • “/pneuma-cosmos”

Requirements

  • Node.js

Workflow steps

2 steps, taken from the first numbered list in SKILL.md.

  1. The viewer's INFO tab renders an "Open project root in editor"
  2. **Relative path / file values on CosmosSourceRef resolve

What it can do on your machine

Read from SKILL.md and the folder at commit 0023d3c. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Ships script files (JavaScript), which the agent can run.

    Shell commands in SKILL.md call:

    • brew
    • pdftoppm
    • apt
    • ffmpeg

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • arxiv.org

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

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.

Always · name and description, kept in context so the agent knows when to use it
~56
When it runs · the whole SKILL.md, loaded when a task matches
~11k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~42k

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.

Safety

Auto-check passed

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.

SKILL.md

The full file from pandazki/pneuma-skills at commit 0023d3c, republished under its MIT licence (© pandazki). 5,644 words, ~10,560 tokens.

Download SKILL.mdSave it as .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.
name
pneuma-cosmos
description
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.

Cosmos

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 -->

Scene

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.

Viewer contract

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.

What the user can select

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.

ViewerAddress vocabulary
KeyKindMeaning
nodeIdcoarseA specific concrete node in the cosmos (e.g. { nodeId: "c-eliot" }).
layerIdcoarseA layer slice (e.g. { layerId: "clues" }). Use this for layer-level operations like focus-layer.
perspectiveIdcoarseA 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.
subgraphIdcoarseA 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.

Actions you can invoke
  • 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.
Commands the user can trigger from the viewer
  • 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.

Core rules

  • 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:

    1. The viewer's INFO tab renders an "Open project root in editor" affordance — one click opens the whole project; subsequent file source-chip clicks activate the file inside the open editor window (Cursor / VS Code behaviour).
    2. Relative 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.

Source references

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.

The six kinds
kindShapeOpens 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.

Per-domain examples

Codebase node — typically one or more file refs, often with ranges narrowing to the relevant span:

json
{
  "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:

json
{
  "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):

json
{
  "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" }
  ]
}
Discipline
  • Cite first, narrate second. If you can't point at something that produced a node, you're inventing. Add a source even when the source is your own previous reasoning ("conversation, turn 15") — write that as a passage ref into a saved transcript.
  • Multiple refs are fine. Real nodes usually have 1–3; over four feels like the node is doing too much. Split it.
  • Don't pad refs. A 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.
  • Order matters. Put the most authoritative ref first; the chip strip preserves order, and the user reads left to right.
  • Excerpt > chip. When you can crop a real visual extract from the source, do it — chips are functional, excerpts are persuasive.
Legacy schema note

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.

Visual anchoring — every node deserves a way home

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.

The excerpt rule — non-negotiable

Every excerpt.path MUST be a real extract from the source.

  • ✅ Cropped PDF page, figure lifted from a paper, screenshot of a UI region, video frame at a moment, scan of a manuscript page, diagram from the docs.
  • ❌ AI-generated illustrations. Decorative graphics. Stock images. "Conceptual visualisations" of what the node is about.

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.

Locator everywhere

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 transcript

Whatever 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.)

Shell commands — populate excerpts without leaving the agent

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.

  • PDF page → PNG: 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.
  • Image crop: 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).
  • Video frame at t seconds: 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.
  • Web page region: don't count on capturing a live URL yourself. Fall back to a chip + locator only, or ask the user to drop the screenshot they want into the workspace and reference its path in excerpt.
Per-domain guidance
  • Research / academic paper — every claim / evidence / method node gets a PDF page or figure 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.
  • Codebase — primary cite is a 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).
  • Fiction / long-form prose — 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.
  • UI / product analysis — screenshot of the UI region, crop tightly, 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.
  • Video / talk — frame at the moment in question + 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.
  • Conversation / transcript — passage ref with quote + locator like "turn 14". Excerpts only when the conversation includes shared images you want to lift.
Where excerpts live on disk

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.

Edges with sources

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:

  • Codebase: an 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.
  • Research: a supports edge can cite the section that establishes the support — different from citing the supporting claim's source, which lives on the node.
  • Fiction: a 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.

Workflow

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.

Choosing a projection path

The first decision each projection is which of two paths produces it:

  • Path A — Workflow-backed (large codebases, Claude Code). When the input is a codebase or a folder too large to read well in one context, AND you have the 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.
  • Path B — in-context (everything else). A short story, a paper, a conversation, a small folder — or any input when the 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.

Path A — Workflow-backed projection
  1. 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.
    • a draft layers[] table (3–6, by architectural concern), a vocabulary ({ nodeTypes, edgeTypes }), the working language, the absolute sourceRoot, and a projectName.
  2. 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).

  3. 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.

  4. 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.

  5. 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.

Show full SKILL.md (2,332 more words)Show less
Path B — in-context projection
  1. 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.

  2. 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.

  3. 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).

  4. 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.

  5. 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.

  6. 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:

    jsonc
    "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).

  7. 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.

  8. 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.

  9. fit-view() then drop a <viewer-locator> card pointing to the most striking node. Make the user's first click satisfying.

Refinement

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.

Re-projection (responding to 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.

Guided tour (responding to 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.

Perspective tours — variant walks through the cosmos

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.

Two "steps", two different shapes — don't conflate them

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.

FieldOne beat's shapeNode reference
Overall tourcosmos.tour[]{ step: number, nodeId: string, narrative }nodeId — a single string
Perspective walkcosmos.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.

The discipline

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.

Lenses — vocabulary, not a checklist

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):

  • Orthogonality — two axes that vary independently. Watch for: pairs of enums that never co-occur; modules that share a data path but never each other's caller.
  • Cybernetic loop — a subsystem holding [property] against [perturbation]. Watch for: explicit retries, idempotency tags, feedback edges, "watchdog" / "reconcile" naming.
  • Entropy gradient — where chaos grows in the system, where it's resisted. Watch for: directories with sprawling tests vs. tight cores; layers that accumulate config; "drift" / "stale" in TODOs.
  • Self-similarity (fractal) — the same structure at multiple scales. Watch for: a Plan that mirrors a Project that mirrors a Task; an Agent that itself contains a swarm of sub-agents.
  • Causal chain — X causes Y causes Z, not just correlated. Watch for: dependency chains where each step is the because of the next, not just a precondition.
  • Tension — two forces pulling the design opposite directions, consciously held. Watch for: contradictory constraints documented as ADRs; classes whose comments argue with each other.
  • Convergence point — many concerns funnel through one node. Watch for: high in-degree, "the place where everything lands"; a single file every other layer reaches.
  • Layered translation — raw → structured → semantic → action, each layer translating from previous. Watch for: pipelines where adjacent stages don't share a vocabulary.
  • Hidden hand — an offstage agent shapes events. Watch for: nodes with no outbound edges that are referenced everywhere; a policy file no one calls but everyone honors.
  • Paradigm shift / Succession — the work is mid-migration from one set of axioms to another. Watch for: v1 + v2 living side by side; type names with "Legacy" / "v0" suffixes; ADRs that reverse earlier ADRs.

When none of these lens names fit, invent. perspectives[].lens is open vocabulary like node types are. The list above is help, not grammar.

When to write perspectives, when not to

Do reach for perspectives when:

  • The user has lived with the facts cosmos for a beat and is asking meta questions ("what's the shape of this thing?", "where would you place a new feature?").
  • You re-project an evolving system and the same patterns keep re-emerging — name them.
  • The cosmos is large enough (≥ ~25 nodes) that the overall tour alone misses material the user would benefit from walking.

Don't reach for perspectives when:

  • The cosmos is small (< 15 nodes). The overall tour covers it.
  • You haven't read enough. Premature perspectives are the worst kind — slogans wearing a node-list.
  • The user asks a concrete question. Answer it with concrete nodes. Perspectives are for "what does it all add up to" / "what's another way to read this", not "what does this function do".
Schema note

The field is cosmos.perspectives[]. Each entry:

jsonc
{
  "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.

Drill-down — user-driven subgraphs

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.

Recognizing a drill request

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:

xml
<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.

What you write

Append a new entry to cosmos.subgraphs[] with the full subgraph:

jsonc
{
  "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:

xml
<viewer-locator label="Open the new drill: <title>"
                address='{"subgraphId": "subgraph-<slug>"}'/>

The user clicks the card → canvas swaps into the subgraph view.

Discipline
  • Take the prompt seriously. The <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.
  • Anchor nodes are first-class context. Read each anchor's full summary (and sources[] if relevant) before authoring the subgraph. The drill expands from what the user pointed at.
  • Anchors stay; new nodes scope. Subgraph nodes can reference the anchors by id (edges link back to the main graph); ids unique to the subgraph render as new content scoped to this drill only. The viewer shows anchor nodes alongside subgraph nodes when it renders the drill, so the user reads "what's new here + where it attaches".
  • Cite sources for every new node. Drills are inquiry — the user will want to verify your claims. sources: [{kind: "file", path: "...", range: [...]}, ...] is non-negotiable for code; for prose, use passage refs with quote. See the Source references chapter.
  • One subgraph per request. Don't try to satisfy a drill with five subgraphs. If the user's question is too broad to answer in one focused expansion, write one subgraph that names the branches and let the user re-drill into whichever they want next.
  • Recursive depth is fine. When <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.
  • When you can't, say so. If you genuinely can't answer the drill (you don't have the source material, the anchors don't share a coherent relationship, etc.), write a status: "failed" entry with a short message explaining why. Don't fabricate.
When to drill autonomously

Most drills come from the user clicking the button. But the agent can also write subgraphs unprompted when:

  • The user asks a chat question whose answer is naturally a small graph rather than a paragraph ("walk me through how X depends on Y depends on Z").
  • A perspective walk reaches a point where the next beat would need its own mini-graph — emit a subgraph linked from the perspective's last step instead of cramming all the nodes into the main graph.

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.

References

TopicFile
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 domainreferences/projection-workflows.md
Perspective-lens catalog — mental models for variant toursreferences/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

Files

SKILL.md and 5 other files (references) in modes/cosmos/skill of pandazki/pneuma-skills.

  • SKILL.md
  • references/cosmos-schema.md
  • references/node-type-vocabularies.md
  • references/perspective-lenses.md
  • references/projection-workflows.md
  • references/projection.workflow.js

Open the folder on GitHubat commit 0023d3c

Compare with similar skills

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.

Pneuma Cosmos compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Pneuma Cosmos this skillpandazki/pneuma-skills161—~11kAutomated safety check: PassMIT
Obsidian Canvas BoardsAgriciDaniel/claude-obsidian15k—~1.4kAutomated safety check: PassMIT
Ontology1mancompany/OneManCompany4422 repos~1.5kAutomated safety check: PassApache-2.0
Knowledge Graphgnomeria/usbtree691—~1.5kAutomated safety check: PassMIT
Graphagenticnotetaking/arscontexta3.5k—~4.9kAutomated safety check: NotesMIT
LLM Wiki Knowledge GraphEgonex-AI/Understand-Anything86k—~1.5kAutomated safety check: PassMIT

Similar skills

  • 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.

    15k GitHub stars~1.4k tokensUpdated 1 mo ago
    Knowledge ManagementAuto-check passed
  • Ontology

    1mancompany/OneManCompany

    Typed knowledge graph for structured agent memory and composable skills.

    442 GitHub starsUsed in 2 repos~1.5k tokens
    Knowledge ManagementAuto-check passed
  • Knowledge Graph

    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…

    691 GitHub stars~1.5k tokensUpdated 1 mo ago
    Knowledge ManagementAuto-check passed
  • Graph

    agenticnotetaking/arscontexta

    Interactive knowledge graph analysis. An agent skill from agenticnotetaking/arscontexta.

    3.5k GitHub stars~4.9k tokensUpdated 7 mo ago
    Knowledge ManagementAuto-check: notes
  • LLM Wiki Knowledge Graph

    Egonex-AI/Understand-Anything

    Detects a Karpathy-pattern LLM wiki and builds an interactive knowledge graph with entities, implicit relationships and topic clusters.

    86k GitHub stars~1.5k tokensUpdated today
    Knowledge ManagementAuto-check passed
  • Gitnexus Guide

    aws-samples/sample-kolya-br-proxy

    Official

    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.

    106 GitHub starsUsed in 11 repos~867 tokens
    Knowledge ManagementAuto-check passed

More from pandazki/pneuma-skills

All 30 skills in this repo
  • Pneuma Bansho

    pandazki/pneuma-skills

    Explain something by writing it on a board. An agent skill from pandazki/pneuma-skills.

    161 GitHub stars~6.9k tokensUpdated 2 days ago
    Auto-check passed
  • Pneuma Clipcraft

    pandazki/pneuma-skills

    AI-orchestrated video production on @pneuma-craft. An agent skill from pandazki/pneuma-skills.

    161 GitHub stars~7.5k tokensUpdated 2 days ago
    Auto-check: notes
  • Pneuma Lucid

    pandazki/pneuma-skills

    Pneuma Lucid Mode workspace guidelines. An agent skill from pandazki/pneuma-skills.

    161 GitHub stars~4.6k tokensUpdated 2 days ago
    Auto-check: warnings
  • Pneuma Plotwise

    pandazki/pneuma-skills

    Pneuma Plotwise workspace guidelines. An agent skill from pandazki/pneuma-skills.

    161 GitHub stars~8.9k tokensUpdated 2 days ago
    Auto-check passed
  • Pneuma Sprite

    pandazki/pneuma-skills

    Pneuma Sprite Mode workspace guidelines. An agent skill from pandazki/pneuma-skills.

    161 GitHub stars~16k tokensUpdated 2 days ago
    Auto-check passed
  • Pneuma Webcraft

    pandazki/pneuma-skills

    Pneuma WebCraft Mode workspace guidelines with Impeccable.style design intelligence.

    161 GitHub stars~7.5k tokensUpdated 2 days ago
    Auto-check: notes

Questions about Pneuma Cosmos

What does Pneuma Cosmos do?

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.

When should I use Pneuma Cosmos?

Pneuma Cosmos fits situations like: explaining cosmos.json and grounded graph projections; tasks that involve Knowledge graphs.

How do I install Pneuma Cosmos in Claude Code?

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.

How do I install Pneuma Cosmos in Codex?

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.

Can I use Pneuma Cosmos in Cursor, Gemini CLI or GitHub Copilot?

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.

What does Pneuma Cosmos need to run?

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.

Does Pneuma Cosmos access the network?

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.

Is Pneuma Cosmos safe to install?

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.

What licence does Pneuma Cosmos use?

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.

How many tokens does Pneuma Cosmos use?

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.

What are the alternatives to Pneuma Cosmos?

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.

Who maintains Pneuma Cosmos?

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.