Install
$ agentstack add skill-pandazki-pneuma-skills-create-mode ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Create Mode
A guided journey for adding a new mode to Pneuma Skills. The journey has three phases — Discovery (ask the right questions), Brief (write down every key choice with rationale and get the user's confirmation), Implementation (generate files). Each phase has a clear handoff to the next; never skip Brief. Pneuma already has twelve modes and a stable contract layer; the cost of a thoughtful 10-minute design brief is much smaller than the cost of building the wrong viewer.
The reference material in references/ is where the knowledge lives — go read the relevant one whenever you're about to make a meaningful decision. SKILL.md is the journey, not the textbook.
When to use
Trigger this skill when the user asks for any of:
- "create a new mode for X"
- "fork slide / webcraft / … for a different domain"
- "scaffold a mode"
- "add a [mindmap | spreadsheet | timeline | annotator | …] mode"
- "design the viewer for a mode that …"
If the user only asks about an existing mode's behavior, this skill is not the right tool — direct them to docs/reference/viewer-agent-protocol.md or the mode's own SKILL.md.
Phase 1 — Discovery interview
Goal: extract enough signal that you can fill every field of the design brief without further interrogation. Ask one question at a time with AskUserQuestion; let each answer shape the next. Don't dump a 20-question survey on the user.
Discovery questions (ask in this order, branch as noted)
- Identity — name (kebab-case), one-line displayName, two-line description, intended icon style. This is the only question you can pose as a single multi-line form.
- Domain in one sentence — what is the user creating with this mode? A document? A canvas of objects? A timeline? Let the user answer free-form before you offer Source-kind options. Read
references/domain-and-sources.mdwhile they think. - Inspiration vs original — does this mode borrow content (commands, references, design language, taxonomy) from an existing tool, library, or project? If yes, ask the upstream's name + URL + license. This determines whether you'll write
NOTICE.mdand setinspiredBy. Readreferences/external-integrations.mdfor the borrow-vs-inspiration line. - Source kind (branch on Q2 + Q3) — present
file-glob/json-file/aggregate-file/memorywith the one that fits Q2's domain pre-selected as "Recommended". Explain why it fits in the option'sdescription. Ifaggregate-filewins, note that you'll also generatedomain.ts. - Workspace model (when Q4 is not
memory) —"all"/"manifest"/"single"; do users author many independent files, an ordered/structured set, or one main document? Seereferences/viewer-contract-patterns.mdfor the FileWorkspaceModel matrix. - ViewerAddress vocabulary — "what's the smallest thing the user can point at?" Propose a draft
{ contentSet?, ... }based on Q2's domain noun (slide / page / row / node / heading). Confirm with the user; explicitly name the coarse "where" key and any fine "within" key. Seereferences/viewer-contract-patterns.md::ViewerAddress. - Initial action space — propose 2–5 actions with id / label / category / agentInvocable. Almost every viewer needs a
navigate-to(navigate); adduiandcustomonly if the user names a concrete need. Don't listcapture— it's framework-built-in. - External integrations (conditional — only ask if Q2 or Q3 implied an external API / SDK / CDN / library / API key) — does the viewer fetch external APIs (→
proxy)? does the agent or viewer need API keys (→init.paramswithsensitive: true+envMapping)? does this need an MCP server (→skill.mcpServers)? Readreferences/external-integrations.mdfor the proxy / Babel-JIT / NOTICE patterns. - Seed strategy — single file, multiple use-case content sets, or language×theme matrix? What's the first seed's narrative — what story does it tell to a brand-new user? See
references/seed-and-showcase.md. - Evolution directive — give the evolve agent a one-sentence "what should it learn for this mode?" (e.g., "Learn the user's slide design preferences: typography, palette, density, structure"). This is what makes the mode personalize over time.
What to read while interviewing
| When you're about to ask … | Read first | |---|---| | Q2 / Q4 (domain → source kind) | references/domain-and-sources.md | | Q5 / Q6 / Q7 (workspace / address / actions) | references/viewer-contract-patterns.md | | Q3 / Q8 (inspiration / external deps) | references/external-integrations.md | | Q9 (seed strategy) | references/seed-and-showcase.md | | Q10 (evolution directive) | references/skill-md-patterns.md (evolution section) |
If you ever find yourself stuck choosing between two patterns, open references/case-studies.md — it indexes which existing mode made which choice, so you can read that mode's manifest as a concrete precedent.
Phase 2 — Design brief & user confirmation
Goal: write down every key choice with a one-line rationale, in one place, and get the user's explicit yes before any file is written. The brief is what you'll work from in Phase 3 — if a question wasn't resolved here, don't fudge it in Phase 3; loop back to Phase 1.
Brief structure
Render the brief inline in the conversation (not as a file — the conversation is the canonical place to confirm). Use exactly this structure so you don't drift:
# Mode design brief —
## Identity
- name:
- displayName:
- description:
- icon:
## Domain
## Source layer
- kind:
- domain type T:
- why this kind:
- domain.ts needed:
## Workspace model
- type:
- multiFile:
- ordered:
- hasActiveFile:
- supportsContentSets:
## ViewerAddress vocabulary
- coarse keys:
- fine keys:
- example address: `{ contentSet: "en-light", slide: 3 }`
- documented in: skill/SKILL.md (will write a sub-section)
## Action space
| id | label | category | agentInvocable | params |
|----|-------|----------|----------------|--------|
| navigate-to | Go to … | navigate | true | { address: object } |
| … | … | … | … | … |
(framework provides `capture` automatically — not listed)
## Seed strategy
- shape:
- content sets:
- first seed narrative:
## External integrations
- proxy:
- init.params:
- skill.mcpServers:
- viewer.refreshStrategy:
- NOTICE.md required:
- inspiredBy:
## Launcher surface
- visibility:
- featured-eligible:
## Evolution directive
>
## Open questions / deferred
-
Confirmation gate
After rendering the brief, ask plainly: "Does this brief look right? Anything to change before I generate files?" If the user adjusts anything, update the brief inline and re-confirm. Do not start Phase 3 without an explicit "go" / "yes" / equivalent.
Phase 3 — Implementation
Once the user confirms the brief, generate files in this order. Use templates from assets/templates/; replace the TODO: placeholders against the brief. Don't ad-lib structure — the templates encode the conventions extracted from existing modes.
Step 1 — Scaffold the directory
modes//
├── manifest.ts ← from assets/templates/manifest.ts.template
├── pneuma-mode.ts ← from assets/templates/pneuma-mode.ts.template
├── domain.ts ← only if Source kind is aggregate-file; from domain.ts.template
├── skill/
│ └── SKILL.md ← from assets/templates/SKILL.md.template
├── seed/
│ └──
├── viewer/
│ └── Preview.tsx ← scaffold a stub PreviewComponent
└── showcase/
└── showcase.json ← from assets/templates/showcase.json.template (with concept descriptions)
NOTICE.md ← only if brief said "NOTICE.md required: yes"; from NOTICE.md.template
Step 2 — Wire up file-by-file
For each file, fill in templates against the brief. Specifics:
- manifest.ts — every brief field maps to a manifest field. The template has marked sections (
// TODO: identity,// TODO: sources, etc.) — fill each from the brief. Don't add fields the brief doesn't have; brevity over completeness for v0.1.0. - pneuma-mode.ts — the
ModeDefinitionbinding: import manifest, wire it to a stubViewerContractthat imports the PreviewComponent and implementsextractContext,workspace.resolveItems,workspace.createEmpty. Seereferences/viewer-contract-patterns.md::pneuma-mode.tsfor the binding pattern. - domain.ts (aggregate-file only) — write the
load(files) → T | nullandsave(value, current) → { writes, deletes }pair as pure functions. Read existing modes'domain.tsfor the pattern (slide / illustrate / kami use this). - skill/SKILL.md — follow
references/skill-md-patterns.md: Scene → Viewer Contract → Core Rules → Workflow → Commands → References. Include a## ViewerAddress vocabularysub-section that names every key from the brief and a one-line meaning per key. - viewer/
Preview.tsx— stub. Renders a placeholder ("Mode initialized — start authoring"). Imports the Source fromprops.sourcesviauseSource. The user (or you in a follow-up) will flesh this out. - seed/ — write the first content set's files per the brief's narrative.
- showcase/showcase.json — from template, with brief's tagline + 3 highlight concept descriptions. Images are generated in Step 4.
- NOTICE.md (if required) — pin upstream name + URL + license + version + sync date; include the "what we borrowed / what we adapted / what we dropped" mapping table. Template at
assets/templates/NOTICE.md.template.
Step 3 — Register the mode (three places, all required)
A new builtin mode needs to be registered in three separate files for the runtime to find it. Skipping any one leaves it in a half-installed state — the dev server might run, but the launcher won't list it, or imports will fail in the frontend bundle. The three files are deliberately separate because they're consumed by different processes (backend / frontend / docs).
Before adding code, ask the user whether the mode should appear in the launcher gallery at all, or be hidden (internal-only, like evolve, project-evolve, project-onboard). Hidden modes still need the first two registrations below but skip the README + gallery treatment.
3a. Frontend dynamic-import registry — core/mode-loader.ts
Add an entry to the builtinModes: Record map so the frontend can dynamic-import the mode's manifest and viewer. Without this, the mode 404s when a user opens its URL ("Unknown mode: ").
// core/mode-loader.ts — inside `const builtinModes = { ... }`
: {
loadManifest: () => import("../modes//manifest.js").then((m) => m.default),
loadModeDefinition: () => import("../modes//pneuma-mode.js").then((m) => m.default),
},
3b. Launcher gallery registry — server/index.ts
Add the mode's name to the builtinNames array (search for const builtinNames = [...]). This array drives /api/registry, which the launcher's marketplace UI and ProjectPanel's mode-tile grid both consume. Skipping this is the #1 way a freshly-built mode silently fails to appear in the launcher gallery even though bun run dev works fine.
// server/index.ts — search for "const builtinNames"
const builtinNames = [..., ""];
The launcher filters out modes whose manifest declares hidden: true, so hidden modes go in the array but get hidden at render time. (Authoring choice: include them so the omission-list pattern stays out of code.)
3c. Docs — CLAUDE.md and AGENTS.md
Add the mode name to the **Builtin Modes:** line in CLAUDE.md, then cp CLAUDE.md AGENTS.md (they must be byte-identical per the release contract). If the mode is not hidden, also add a row to README's "Built-in Modes" table. Hidden modes don't go in the README.
Featured vs. hidden — confirm with the user
After the three registrations land, ask the user one more question:
> Should I propose this mode be eligible for the launcher's > featured slot? The launcher randomly picks one builtin with > showcase highlights to feature on its main page. Saying yes > means we'll make sure manifest.hidden stays unset (default) > and that showcase.json has at least one highlight. Saying no > means we should set hidden: true in the manifest so the mode > exists but doesn't surface in the gallery.
Record their answer in the design brief's "Featured" line. Today's launcher has no per-mode pin (any showcase-bearing builtin gets a random chance); a "always feature this one" affordance would be a v0.4 enhancement and shouldn't block mode creation.
Step 4 — Generate showcase imagery
Hand off to the existing showcase workflow. Read .claude/commands/showcase.md and execute its Step 3 (Generate Showcase Images) for the new mode — hero + 3 highlight images, 1376×768, "Ethereal Tech Dark Mockup" style, saved to modes//showcase/. The descriptions you put in showcase.json during Step 2 become the briefs for image generation.
> This is the only Phase-3 step that takes appreciable time. If image generation isn't available right now (no API key, offline), surface that to the user and let them decide whether to defer — showcase.json with the right descriptions but missing images is a valid intermediate state.
Step 5 — Sanity check
Don't claim the mode is ready until you verify these:
modes//manifest.tstype-checks againstcore/types/mode-manifest.ts(bunx tsc --noEmitruns clean inmodes//).bun run devstarts without error (you may not be able to run this — if not, say so explicitly and ask the user to verify).- The launcher's
/api/registryincludes the new entry. Test viacurl -s http://localhost:17996/api/registry | jq '.builtins[].name'(or whatever port the launcher is on). If the name isn't there, you skipped Step 3b (server/index.ts builtinNames) — go fix it before continuing. - The launcher's mode gallery shows the new entry (same — say so if you can't run the launcher).
- There are no lingering
TODO:comments from the template you didn't address.
Closing principles
These show up in every existing mode; honor them in the one you're creating too.
- Domain-first, transport later. Define the domain type
Tbefore choosing how it serializes. Source kind is a consequence of T, not a prior decision. - One noun for "which object" —
ViewerAddress. Every action that takes an object reference, every notification that reports one, every locator card that points to one, must use the same address shape. Mode owns the vocabulary; framework owns the slot. - Action space is small. Two to five actions covers almost every mode. If you're proposing seven, you're either modeling the wrong unit or surfacing UI as actions (Commands → ⑥ — handle there).
manifest.tsdeclares;pneuma-mode.tsimplements. Keep the split. Manifest is read by skill-installer + backend;pneuma-mode.tsis read by the frontend mode-loader. Don't put React imports inmanifest.ts.- **
SKILL.mdis the agent's project guide for this mode** — it follows the same "scene → contract → rules → examples → references" rhythm as the rootCLAUDE.mddoes for the project. Put depth inskill/references/.mdfiles, not in the main body. - Borrowed content needs a
NOTICE.md; borrowed ideas don't. Direct transcription, license excerpts, command tables, font subsets → declare upstream + license + version. Architectural metaphors, aesthetic direction, workflow philosophy → no notice needed. - Showcase is mandatory, but imagery can defer.
showcase.jsonwith descriptions and a tagline is the minimum bar (so the launcher gallery has copy); imagery generation can happen later via the existing/showcaseflow.
References
Open the matching file when you're about to make the corresponding decision. Don't load them all eagerly — progressive disclosure.
| File
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: pandazki
- Source: pandazki/pneuma-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.