All notable changes to this project will be documented in this file.
- CI test failures — updated test expectations for Codex
modelSwitch: trueand backend-aware skill install (noCLAUDE.mdfor Codex sessions)
- Codex agent backend — full OpenAI Codex integration via
app-serverstdio JSON-RPC transport, including session lifecycle, streaming, permission approval, and file change tracking - Dynamic model switching for Codex — fetches available models from Codex
model/listAPI, applies selected model per-turn viaturn/startparams - Codex slash commands — fetches skills from Codex
skills/listAPI and populates the composer's "/" menu dynamically - Backend availability detection — launcher checks if CLI binaries (
claude/codex) exist on PATH and grays out unavailable backends in session cards and launch dialog - Backend-aware skill installation — skills install to
.agents/skills/withAGENTS.mdfor Codex,.claude/skills/withCLAUDE.mdfor Claude Code
- Codex session crash — adapter's partial session state (missing
agent_capabilities) was broadcast directly to browser, causing React crash in ModelSwitcher; now merges with server's full state before broadcasting - Cross-platform PATH delimiter — Codex CLI launcher now uses
node:pathdelimiter instead of hardcoded:
- ModelSwitcher — rewritten to be backend-agnostic with dynamic model list support from
SessionState.available_models - Launcher backend picker — compact pill-style buttons with backend logos, auto-selects first available backend
- Session cards — show unavailable overlay with reason when backend CLI is not found
- Dependency upgrades — Electron 35→41, Vite 6→7, chokidar 4→5, @vitejs/plugin-react 4→5, electron-builder and electron-updater to latest
- Thumbnail capture quality — rewrote image capture strategy to use high-resolution source images (e.g. slide thumbnails at native 2560×1440) instead of compositing from small display sizes
- Evolve mode fails to launch — launcher now passes
targetModevia initParams so the evolve CLI knows which mode to analyze - Vite 7 HMR — updated
server.ws.sendtoserver.hot.sendfor workspace file change notifications
- Windows ARM64 desktop build — electron-builder config listed both x64 and arm64 under one target, causing the x64 CI job to build both archs and the ARM64 job to fail on duplicate asset upload; each CI job now builds only its own arch
- Desktop app fails to start — CLI update checker blocked Electron startup with an interactive prompt; now skipped in non-interactive mode (
--no-prompt)
- CI actions — upgraded
actions/checkoutandactions/setup-nodefrom v4 to v5 for Node.js 24 compatibility
- Desktop frameless launcher — hidden title bar with macOS traffic lights, custom drag region on header
- Tray icon redesign — logo intaglio (white circle + logo cutout), high visibility on both light and dark menu bars
- Tray session switcher — live running session list fetched from launcher API, click to activate window
- Close window → kill session — closing a mode window in Electron automatically kills the corresponding session process
- Window reuse — opening the same session URL reuses the existing window instead of creating duplicates
- Splash loading screen — solid-background splash with animated logo while launcher starts
- Production image 404 — SPA fallback was intercepting
/content/*requests, returningindex.htmlinstead of workspace files; added path exclusions for/content/,/api/,/ws/,/export/ - Production logo 404 — static file catch-all now serves all
dist/files, not just/assets/* - Desktop tray icons missing in packaged app — added tray icon files to
extraResourcesin electron-builder config
- Tray menu — left-click and right-click both show menu (previously left-click opened launcher directly)
- Desktop icons — regenerated all icons (icns, ico, png, tray) from new logo
- Launcher redesign — editorial layout with mode showcase system (carousel images per mode), light/dark theme toggle, sticky header with animated close button
- Smart thumbnail capture — generic 3-tier strategy (canvas → img elements → snapdom) eliminates per-viewer captureViewport implementations; works for Excalidraw, React Flow, and DOM-based viewers automatically
- Session card animations — framer-motion powered transitions for running/recent state changes in Continue section
- Mode showcase system —
showcase/directories with curated images for each builtin mode, displayed in LaunchDialog carousel
- Gallery card expand/collapse — replaced janky grid-template-rows with height-based animation using RAF measurement for silky smooth transitions
- LaunchDialog — theme-aware showcase captions, vertically centered form layout, streamlined button styling
- Overlay system — Gallery and AllSessions render below sticky header with Escape key dismissal and animated header close button; removed redundant per-overlay close buttons
- Thumbnail refresh — debounce reduced from 30s to 10s with dedup (skip upload if identical to last capture)
- UI polish — globally disabled image dragging, focus outlines, and logo text selection; light/dark aware running badge; compact header with centered content
- Slide skill reference restructuring — merged
style_reference.mdandaesthetics.mdinto a singlereferences/design-guide.mdfollowing progressive disclosure pattern; extracted refinement practices intoreferences/refinement.md; movedlayout_patterns.mdanddesign_outline_template.mdintoreferences/for consistency - Slide SKILL.md — rewritten Supporting Reference Documents section with clear "when to read" guidance for each reference file; all internal cross-references updated to new paths
- Redundant slide skill files — deleted
style_reference.md,references/aesthetics.md, top-levellayout_patterns.md, anddesign_outline_template.md(content merged into new reference structure)
- Slide mode aesthetics guide — new
references/aesthetics.mdwith design thinking for typography selection, OKLCH color theory, visual hierarchy, presentation writing, and AI image usage (conditionally loaded when image generation is enabled) - Slide refinement workflow — six refinement practices (critique, polish, distill, bolder, quieter, colorize) adapted for the fixed-viewport slide context, triggered by natural language requests
- Slide style reference — default color palettes and font stacks now reference the aesthetics guide for intentional customization; design philosophy reframed from prescriptive ("Apple HIG minimalism") to principle-based ("intentional and coherent")
- Slide core principles — added "Design with intention" as a first-class principle with link to aesthetics reference
- Mode Maker play on
bunx— seedpackage.jsonVite toolchain moved todependencies(not devDeps) so they're installed;vite.config.tsReact alias usesrequire.resolvefor hoisted node_modules; all frontend deps restored to rootdependencies(Vite dev mode needs them at runtime) - macOS desktop build — switched from universal to arm64-only; universal merge fails with native binaries (esbuild) because
prepare-depsruns on a single architecture; also removed.bin/symlinks from bundled node_modules - macOS desktop build failure —
prepare-deps.mjsrecursively removes all.bin/directories from production node_modules; broken symlinks in nested.bin/crashed electron-builder's universal merge - Desktop
.gitignoretypo — removed duplicate trailing slash inpneuma-node-modules//
- Mode Maker play crash on
bunx—vite.config.tsReact alias used hardcodednode_modules/reactpath which doesn't exist when dependencies are hoisted; switched torequire.resolvefor correct resolution in any install layout
- Mode Maker play/test 404 on
bunx— moved Vite toolchain fromdevDependenciestodependenciesin seedpackage.jsonso they're actually installed when creating a new mode; addedsrc/andvite.config.tsto npmfilesarray so Vite dev server can resolve the entry point - Desktop
.gitignoretypo — removed duplicate trailing slash inpneuma-node-modules//
- Dependency hygiene — moved mode-specific deps (
@xyflow/react,@excalidraw/excalidraw,@dnd-kit/*,@zumer/snapdom,@tailwindcss/typography) from rootdependenciestodevDependencies; they're bundled intodist/at publish time and don't need runtime installation
- Windows ARM64 desktop build — NSIS installer for Windows on ARM (Snapdragon laptops etc.)
- Illustrate skill not activating — updated SKILL.md description to use the "Use for ANY task in this workspace" trigger pattern, so Claude Code's skill matching loads it on first interaction
- Illustrate claudeMdSection too thin — added Architecture and AI Image Generation sections with command reference so the agent has enough context even without the skill loaded
- Blog-heroes seed images — regenerated all 5 images with cinematic Pneuma aesthetic (dark background, orange particles, glassmorphism, volumetric lighting)
- Illustrate mode — new builtin mode with React Flow canvas viewer, AI image generation skill (OpenRouter/fal.ai), 3 seed content sets (pneuma-brand, feature-cards, blog-heroes) with 16 generated images
- Viewer locator system —
<viewer-locator>tags in agent messages render as clickable navigation cards; supports cross-content-set navigation with auto-detection and prefix stripping - Resilient manifest parsing —
useResilientParsehook catches JSON parse errors and notifies agent instead of crashing viewer - Debug locator payload — collapsible JSON payload display under locator cards in
--debugmode
- Binary seed file corruption — seed copy now skips UTF-8 template param processing for image/font/media files
- Illustrate image error handling — shows "Not yet generated" placeholder instead of infinite "Loading..." when images are missing
- Slide context fallback —
extractContextfalls back to first slide when no selection exists - Content set context filtering —
ws.tsfilters files by active content set and strips prefixes before passing to viewer
- Desktop setup wizard — larger window (720x600), platform-specific install instructions
- React Flow fitView —
requestAnimationFramewrapper ensures internal store sync beforefitViewcalls
- Content set context — active content set (label + prefix) is now injected into
<viewer-context>for all modes, so the agent knows which content variant the user is viewing
- Mode Maker fork — builtin mode import now rewrites escaping relative imports (
../../../src/store.js) to correct paths, so forked viewers resolve correctly - Mode Maker play — always use Vite dev mode to prevent Zustand store duplication from Bun.build bundling
src/store.tsseparately - External mode resolve — Vite plugin and Bun.build plugin now redirect both
/src/and/core/imports to pneuma project root (previously only/core/) - react-dom vendor shim — export
createPortal,flushSync,createRoot,hydrateRootas named exports for production external mode bundles - Mode name validation — sanitize input to only allow lowercase letters, numbers, and hyphens
- macOS code signing — set
identity: nullto skip code signing in CI (no Apple Developer certificate)
- Desktop version sync —
prepare-depsscript now auto-syncs rootpackage.jsonversion into desktoppackage.json, ensuring local and CI builds use the correct version
- Windows desktop build — replaced
renameSyncwithcopyFileSyncin Bun download script to avoidEXDEVcross-device error on CI - Linux deb package — added required
authorandhomepagefields to desktoppackage.json
- Desktop CI — added missing
tsupbuild step to compile Electron main/preload TypeScript before packaging
- Desktop production build — pruned node_modules to production-only dependencies (8 packages / 5MB instead of 551 / 230MB), fixing missing transitive deps and bloated DMG size
- App icons — added proper icon set (icns/ico/png) and tray icons generated from helix logo
- macOS desktop build — replaced deprecated
macos-13runner with universal build onmacos-latest(single DMG for both ARM64 and Intel)
- Desktop CI — merged desktop build into
release.ymlas a dependent job (GitHub Actions tokens can't trigger cross-workflow events)
- Electron desktop client — cross-platform native app wrapping the full Pneuma runtime
- Bundles Bun binary per platform — no runtime install required for end users
- Claude CLI detection with guided setup wizard
- System tray app: left-click opens launcher, right-click shows sessions/updates/quit menu
- Launcher window (80% screen) + maximized mode session windows
- Native OS folder picker for workspace selection (Electron), fallback to in-page browser (web)
- macOS app menu with About dialog and GitHub link
- Auto-updater via
electron-updater+ GitHub Releases (download progress bar, restart prompt)
- Desktop CI workflow —
desktop.ymlbuilds on GitHub Release for macOS arm64/x64, Windows x64, Linux x64- DMG + ZIP (macOS), NSIS installer (Windows), AppImage + deb (Linux)
- Artifacts uploaded to the same GitHub Release as the npm package
- Export white screen —
</script>in page HTML no longer breaks the export preview's JSON script block - Download HTML — returns the original page with inlined assets instead of the export wrapper
- Vite proxy for
/export— export routes now correctly proxied in dev mode
- Viewer position persistence —
activeContentSet+activeFilesaved to.pneuma/viewer-state.jsonand restored on session resume
- WebCraft Mode — new builtin mode for live web development with Impeccable.style AI design intelligence
- 17 AI design commands: Audit, Critique, Polish, Bolder, Colorize, Animate, Distill, Clarify, Optimize, Harden, Delight, Extract, Adapt, Onboard, Normalize, Quieter, Teach Impeccable
- Responsive viewport presets (Mobile/Tablet/Desktop/Full), element selection, annotation mode
- Export: Download HTML (self-contained with inlined assets), Download ZIP, Print/PDF
- Two seed sites: Pneuma project showcase (dark/light toggle, parallax, scroll-reveal) and The Gazette (newspaper editorial with AI-generated illustrations)
- Centralized viewer context enrichment — all message paths to CLI agent auto-prepend
<viewer-context>with active content set, file, and viewport info - Content set import guidance — agent instructions for webcraft & slide: imported content always goes into a new content set to preserve seeds and enable switching/comparison
- False "Scheduled task" labels on history page reload
- Content set ordering now preserves filesystem discovery order (not alphabetical)
- Impeccable commands now include viewer context (content set + active file)
- Annotate mode in WebCraft works correctly (popover UI for contextual comments)
- Launcher widened to 4 cards per row, builtins reordered: webcraft > slide > doc > draw
- Updated all mode descriptions to highlight key features and positioning
- Unread indicator on content set selector when files change in inactive sets
- Schedules tab — view and manage cron/loop scheduled tasks from a dedicated top-level tab
- Job list with prompt, schedule, recurring/one-shot/durable badges
- Cancel and refresh buttons (agent-mediated)
- Badge count on tab header
- Cron trigger visual indicator — "SCHEDULED TASK" bubble before each cron-triggered turn showing the job's prompt
- Claude Code version check — warns in Schedules tab if CC version is below 2.1.0 (cron minimum)
- Cron protocol documentation — full reverse-engineered docs for CronCreate/CronDelete/CronList
- Cron job extraction — use optimistic tool_use extraction since SDK stream does not forward tool_result blocks
- Skill effectiveness optimization — all 5 builtin skills refined based on Anthropic skill-creator best practices
- Added Pneuma identity to claudeMdSection (doc/draw/slide) for co-creation workspace context
<system-info>tag in greetings for natural skill association at session start- Trimmed generic knowledge from SKILL.md bodies, extracted heavy references to
references/files - Added "why" explanations to constraints for better LLM compliance
- Broadened SKILL.md descriptions for wider trigger coverage
- Slide content set workflow — new presentation tasks create a new top-level directory instead of overwriting seed content
- Evolution agent — embeds current skill content in system prompt, briefing-first interaction protocol, installs target mode skill in evolve workspace
- Evolution Agent — AI-native continuous skill learning system. Analyzes cross-session conversation history to extract user preferences, generates proposals with evidence citations, and augments skill files. Modes declare an
evolution.directivein their manifest to guide the analysis direction.pneuma evolve <mode>CLI command to launch the evolution agent- Evolve Mode (
modes/evolve/) with dashboard viewer for proposal review - Proposal lifecycle: pending → apply/rollback/discard/fork
- Fork proposals into standalone custom modes (
~/.pneuma/modes/<name>-evolved-<date>/) - Automatic CLAUDE.md sync — "Learned Preferences" section injected on apply, removed on rollback
- Session analysis tools: list sessions, search messages, session digest, tool flow extraction
- Evolution API routes (
/api/evolve/*) for proposal management
EvolutionConfigcontract — new optionalevolutionfield onModeManifestwithdirectiveandtools- Skill effectiveness optimization — standardized
claudeMdSectionacross all built-in modes following Anthropic best practices (identity → skill reference → core rules pattern) - YAML frontmatter on doc and draw SKILL.md files for Claude Code native skill discovery
- Mode-maker seed improvements — expanded skill template with structured sections, YAML frontmatter placeholders, and claudeMdSection best practices guidance
- Slide mode claudeMdSection directs agent to use native skill tool instead of file path reference
- Doc mode SKILL.md expanded from 24 to ~95 lines with workflow patterns and markdown conventions
- Chat input IME conflict: Enter key now checks
isComposingto avoid sending messages while selecting Chinese/Japanese/Korean IME candidates
- Bun.build resolve plugin bundles React: The
onResolveplugin with/.+/filter was resolving React/ReactDOM to file paths viarequire.resolve, bypassing theexternaloption and bundling them into the output (89KB → 34KB)
- Third-party dependency support for custom modes: Modes can now use any npm package; dependencies auto-installed on seed and inlined at publish via
Bun.build() - Mode build pipeline (
snapshot/mode-build.ts): Shared build module used by both UI publish and CLI publish to produce self-contained bundles - CSS support in production mode serving: Compiled mode bundles can include CSS files, served with correct content type and injected via
<link>tags - Network topology documentation (
docs/network-topology.md): Comprehensive developer reference for ports, scenarios, and connection diagrams - Seed
package.jsonfor mode-maker: New modes start withreact-markdownandremark-gfmas default dependencies
- Production mode-maker Play: Play subprocess no longer forces
--devin production; usesBun.build()compilation instead of Vite when parent is not in dev mode - Bun.build resolve plugin: Handles macOS
/tmp→/private/tmpsymlinks viarealpathSync, uses/.+/filter for reliable bare specifier matching, and resolves imports from both mode workspace and projectnode_modules - Pre-built bundle detection: Skips recompilation when
.build/pneuma-mode.jsalready exists (published modes) - Publish pre-build step: Both UI and CLI publish now build viewer bundle before creating archive, then clean
.build/from workspace
- Protected directories:
.build/added to mode-maker's protected dirs to prevent accidental deletion - Mode-maker skill docs: Added "Third-Party Dependencies" section explaining npm package usage in modes
- External mode import resolution in Vite:
pneumaWorkspaceResolveplugin now handlesPNEUMA_EXTERNAL_MODE_PATHin addition to mode-maker workspace, fixing white screen when Play loads external mode files with relativecore/imports
- Mode-maker Play port collision: Play subprocess now uses dedicated ports (backend 18997, Vite 18996) to avoid conflicts with the parent instance
- Play subprocess hang: Added
--no-promptflag to prevent interactive prompt blocking when stdout is piped - Play fallback URL: Fixed fallback URL to use Vite port instead of backend port
- Launcher dialog: Added explicit close button, timestamp in default workspace path, auto-sync displayName from modeName
- Vite dev watcher: Excluded
.claude/worktrees/from file watching to prevent spurious reloads
- Viewer action curl uses
$PNEUMA_APIenv var: no more hardcoded port in CLAUDE.md; base URL injected at agent launch time, works across port changes and session resume - Scaffold scoped to current view: doc mode only clears viewed files, draw mode only clears active canvas (not all files matching glob)
- Scaffold protects system files:
.claude/,.pneuma/,CLAUDE.md,.gitignore,.mcp.jsonare never deleted by scaffold clear - Scaffold content set support: optional
contentSetparam scopes clear and file writes to a subdirectory (slide mode passesactiveContentSet) - Doc mode hardcoded port:
saveFileand scaffold API calls useVITE_API_PORTinstead oflocalhost:17007
- ScaffoldConfirm not visible in launcher: use
createPortaltodocument.bodyin slide/draw/doc modes to escapebackdrop-filtercontaining block - Slide navigator crash: remove leftover
getSrcdocreference from vertical layout (pre-existing bug from Safari fallback cleanup) - Duplicate React key warnings: deduplicate assistant messages in server
messageHistoryto prevent duplicate entries on page load/reconnect - Doc mode edit not saving in launcher: use
VITE_API_PORTinstead of hardcoded17007forsaveFileand scaffold API calls
- Slide export 404 in launcher: use
VITE_API_PORTinstead of hardcoded17007so child processes resolve the correct backend port - Slide export trailing blank page: add
break-after: autoon last slide to prevent extra page when printing - Slide export print guard: disable Print button while image conversion is in progress
- Debug payload display: replace modal with inline collapsible panel to avoid
backdrop-filtercontaining block issue
- Launcher: Mode Maker card — special full-width card with shimmer border animation between built-in and local modes
- Launcher: GitHub link — repo link in header area
- Launcher: Directory browser — Browse button on workspace path inputs with inline directory navigator (breadcrumbs, dir list, Select)
- Launcher: Existing workspace detection — auto-loads config params and locks them read-only when selecting a directory with
.pneuma/session.json - Launcher: "Open in Mode Maker" button — local mode cards have a wrench icon to open in Mode Maker
- Mode Maker: Import dialog upgrade — card-based UI with icons and source badges, Modes + URL tabs
- Mode Maker: URL import — download tar.gz from URL, extract to
~/.pneuma/modes/, and fork into workspace - Server:
GET /api/browse-dirs— filesystem directory browsing for workspace path picker - Server:
GET /api/workspace-check— detect existing sessions and load config
- Mode Maker seed templates — synced with latest architecture: icon placeholder, serveDir, topBarNavigation, resolveItems, createEmpty
- Mode Maker SKILL.md — added icon format docs, workspace model section, supportsContentSets, updated mode examples
- Mode Maker import —
GET /api/mode-maker/modesnow scans both builtin and~/.pneuma/modes/local modes - Mode Maker version — bumped to 1.1.0 with icon
- Local mode workspace path — extract mode name from path instead of using full absolute path
- LaunchDialog init params — hidden when defaultWorkspace is provided (existing content won't be re-seeded)
- Inline AskUserQuestion — moved from floating overlay into the chat message stream; interactive picker when pending, collapsed
<details>summary when answered, with per-question-answer pair rendering - Mode icons as manifest property —
iconfield onModeManifest(inline SVG string), parsed viaextractBacktickString()in manifest-parser, served through/api/registry; Launcher renders data-driven icons viaModeIconcomponent - Custom Warm Craft CodeMirror theme — editor panel uses project design tokens instead of default dark theme
- TopBar redesign — floating pills layout, agent status indicator moved to chat area
- Launcher visual overhaul — gradient animations, glassmorphism cards, hover micro-interactions
- Registry endpoint refactored — builtins now dynamically parsed from manifest.ts files instead of hardcoded metadata
- README refresh — updated positioning, built-in modes table, screenshot
- Slide seed overflow — dark/light theme h1 line-height, slide-02 content trimming across all 4 variants (en/zh × light/dark)
- Curly quote sanitization — smart quotes in HTML attributes sanitized at render time
- Slide export with content sets — correct workspace resolution for content set directories
- Print CSS Chrome hang — strip expensive CSS effects (box-shadow/filter) that caused Chrome print renderer to hang; softer fallback preserving glass effects
- Doc mode gray icon — key mismatch
"document"vs"doc"caused fallback; now driven by manifest data - Launcher --dev/--debug passthrough — child processes spawned by launcher inherit dev mode and debug flags
- AskUserQuestion stale replay — prevent ghost questions on page refresh, hide empty assistant bubbles
- Launcher process management — track child pneuma processes spawned by
/api/launch; newGET /api/processes/childrenandPOST /api/processes/children/:pid/killendpoints; launcher SIGINT/SIGTERM handlers kill all tracked children (no more orphaned processes) - Running panel — launcher UI shows running instances alongside recent sessions in a side-by-side grid layout, with RunningCard component (green pulse indicator, Open/Stop actions, 3s polling)
- Next-gen visual design — darker zinc palette (
#09090bbg), neon orange primary (#f97316), glassmorphism surfaces with backdrop-blur, mesh gradient backgrounds, refined animations across all components - Visual design spec — added
docs/visual-design-spec.mddocumenting the new design system
- AskUserQuestion bypass —
AskUserQuestionnow always requires user interaction even inbypassPermissionsmode
- Content Set system — directory-based workspace variants (e.g. slide decks in
en-dark/zh-light), auto-selected by user locale/theme preferences, switchable via TopBar dropdown - Unified TopBar navigation — workspace items and content sets rendered in TopBar left side, driven by each viewer's
topBarNavigationflag; Doc mode's internal FileTabBar removed createEmptyprotocol — "+" button in TopBar creates new content per mode: new file (doc/draw) or new deck directory (slide, inherits theme from existing deck)- Draw mode multi-file — upgraded from single-file to multi-file workspace with file selector and "+" support
- Slide seed content sets — seed restructured into 4 variants: en-dark, en-light, zh-dark, zh-light
- Windows: launcher default path — use absolute
homeDirinstead of~/which Windows shells can't expand - Windows: slide blank screen — normalize file paths to forward slashes at server source points (
path.relative()andBun.Globreturn backslashes on Windows); all frontend path matching silently failed - File watcher missed .json/.css —
extractWatchExtensionsnow correctly handles glob patterns like**/manifest.json - Hidden dirs in content sets — content set resolver skips
.-prefixed directories (.pneuma,.claude)
- Windows compatibility — added
win32platform branches across 9 core files: PATH resolution (delimiter,where, Windows candidate dirs), terminal shell (COMSPEC/cmd.exe), browser opener (cmd /c start), process management (graceful degrade), path security checks (case-insensitive),/dev/null→NUL,basename()for cross-platform path extraction
- Launcher default URL — bare URL (
http://localhost:17996/) now opens the Launcher directly, no?launcher=1param needed - Launch in new tab — launching a mode from Launcher opens it in a new tab instead of navigating away, keeping the Launcher available
- "Launching..." state stuck — SessionCard now properly resets its loading state after launch completes
- Frontend deps moved to devDependencies — reduced
bunxinstall from ~500 packages to ~7 (all frontend code already bundled indist/)
- Slide auto-fit zoom — slide viewer now defaults to continuous auto-fit mode, adapting zoom to container size via ResizeObserver. Fixes horizontal scrollbar on small screens (#28)
- Panel ratio — adjusted default split to 65/35 (viewer/chat) for more preview space
- Mode Marketplace Launcher — running
pneumawith no arguments opens a browsable UI for discovering and launching modes from the registry --no-promptCLI flag — skip interactive prompts, used internally by the marketplace launcher to streamline mode launch- Registry index auto-update —
pneuma mode publishnow automatically updatesregistry/index.jsonwith the published mode metadata - Launcher server routes — new
/api/registry,/api/launch/prepare,/api/launchendpoints for marketplace browsing and mode launch orchestration - Launcher UI component —
Launcher.tsxmarketplace interface with search, mode cards, and launch configuration dialog - Local mode management — scan
~/.pneuma/modes/and display user-installed modes in Launcher with inline delete pneuma mode add <url>— CLI command to download and install remote modes locally- Session history — track launched sessions in
~/.pneuma/sessions.json, display "Recent Sessions" in Launcher with one-click resume - Skill update detection — on session resume, detect mode version changes and prompt for skill update (with dismiss/skip support)
--skip-skillCLI flag — skip skill installation on launch, used when resuming sessions with dismissed skill updates- Warm Craft design theme — updated UI with warm copper/sand palette, rounded corners, and refined typography
- JSX dev runtime shim — Bun.build v1.3+ emits
jsxDEV(dev runtime) even in production builds. The vendor shim now mapsjsxDEVtojsxfrom the production runtime, fixing "jsxDEV is not a function" errors in external mode viewers. - Dev mode compatibility — added Vite plugin to mark
/mode-assets/and/vendor/URLs as external during dev transforms, preventing import analysis errors.
- Production external mode loading — viewer no longer shows "Loading" forever when running published modes via
bunx. External mode viewer components are now pre-compiled withBun.build()at startup, served as ES modules with React resolved via import maps and vendor shims.
- Mode publish API —
POST /api/mode-maker/publishendpoint with structured error codes (VALIDATION_ERROR, NO_CREDENTIALS, VERSION_EXISTS) - CLI mode subcommands —
mode publishandmode listfor publishing and listing mode packages on R2 - URL mode resolution — run published modes via
https://*.tar.gzspecifier - Mode archive utility —
createModeArchive()for packaging mode source files
- Overview tab redesign — AI-native Package Structure cards with content-aware summaries, expandable detail panels (Manifest fields, Mode Definition bindings, Skill heading outline), and click-to-navigate (Viewer → Preview, Seed → Preview)
- Default workspace path in run command:
~/pneuma-projects/{mode-name}-workspace - Publish success UI shows copyable run command instead of raw URL
- Mode Maker — builtin mode for creating new Pneuma modes, with live dashboard viewer, skill reference, seed templates, and Vite workspace resolve plugin
- MCP server declarations — modes can declare MCP tool servers in manifest; auto-installed to workspace
.mcp.jsonwith idempotent managed-entry tracking - Skill dependencies — modes can bundle external skills; auto-copied to
.claude/skills/with template params and CLAUDE.md injection - File attachments — chat input accepts any file type (not just images); files saved to
.pneuma/uploads/, small text files inlined in agent message - System Bridge API —
/api/system/open,/api/system/open-url,/api/system/revealendpoints for viewer-triggered OS operations with path traversal protection - Smart init defaults — derive
modeName/displayNamefrom workspace directory name - Agent env mapping — pass
envMappinginit param values as agent process environment variables
- CLI parses Vite stdout for actual port instead of assuming fixed port
- Snapshot archive excludes
.mcp.json(regenerated on startup)
- Doc annotate mode — popover-based comment UX for markdown elements with CSS selector path, human-readable label, and nearby text context
- Doc user action tracking — line-level diff tracking for markdown editor edits (additions, deletions, changes)
- Draw annotate mode — select Excalidraw elements to add comments via popover, with element thumbnail capture
- Draw user action tracking — element-level diff tracking for canvas edits (additions, deletions, text changes)
- Draw richer select context — human-readable labels for selected Excalidraw elements
- Draw view mode — use Excalidraw native
viewModeEnabledfor proper pan/zoom (was blocked by overlay div)
- Doc and draw
extractContextupdated with annotation and label-based context support - All three built-in modes (slide, doc, draw) now have consistent View / Edit / Select / Annotate modes
- Workspace scaffold actions — modes can declare initialization actions (e.g. "Create slide deck"), with confirmation UI and template-based workspace creation
- User action event stream — user operations (text edits, slide reorder, deletions) tracked via
pushUserAction()and injected as<user-actions>XML into agent messages - Viewer → agent notification channel — viewer can proactively push notifications to the agent (e.g. content overflow warnings) via WebSocket bridge
- Slide auto-fit — automatic CSS transform scaling when slide content overflows the viewport
- Slide select mode — click elements in iframe to get rich context (tag, classes, CSS selector, thumbnail, nearby text, accessibility info)
- Slide annotate mode — popover-based comment UX for marking up elements across multiple slides, structured annotation extraction for agent context
- Slide edit mode — inline contentEditable text editing inside iframes, debounced save with diff-formatted action descriptions, two-click slide deletion pattern
--devCLI flag — force dev mode even whendist/exists, avoiding stale build issues- Shared iframe selection module (
core/iframe-selection/) — modular selection script with classify, identify, selector, thumbnail, context, and message-handler sections
ViewerSelectionContextextended withannotations,selector,label,nearbyText,accessibilityfields- Slide mode
extractContextgenerates structured context for select, annotate, and viewing modes
- Suppress React 19 peer dependency warnings via
overridesin package.json
- Auto-update check on startup — queries npm registry for latest version, prompts to update when major/minor differs, re-executes via
bunx pneuma-skills@{version}on confirmation (3s timeout, silent skip on network failure)
- Upgraded CLI TUI from raw console.log/readline to @clack/prompts — modern terminal UI with styled intro/outro, step indicators, confirm/text prompts, and graceful cancel handling
- Release workflow changelog extraction — awk regex treated
[x.y.z]as character class; switched toindex()for literal matching
- GitHub Actions CI workflow for automated releases (GitHub Release + npm publish via OIDC Trusted Publishing)
repository,homepage,bugsfields in package.json
- Draw mode text rendering — replace
updateScenewith key-based remount to prevent Excalidraw Virgil font initialization issues - Draw mode seed content switched to English (Virgil font lacks CJK glyph support)
- Draw mode viewing card and seed content font alignment
- ViewerContract v2 — Agent-Human alignment protocol with perception alignment (
<viewer-context>XML enrichment, viewport tracking, selection screenshots) and capability alignment (ViewerActionDescriptor, bidirectional action execution channel) - File workspace model —
FileWorkspaceModelstandardizes how modes organize files ("all"/"manifest"/"single"), withWorkspaceItemnavigation andresolveItemsruntime resolver - Viewer action protocol —
ws-bridge-viewer.tsroutes action requests from agent to viewer and responses back;POST /api/viewer/actionHTTP endpoint - Skill template engine —
{{viewerCapabilities}}auto-injects Viewer self-description into skill prompts; dual CLAUDE.md markers for skill and viewer-api sections - CLI debug mode —
--debugflag enables payload inspection; each user message shows a{ }icon to view enriched content + images sent to Claude Code - Draw mode selection screenshots — selected elements exported as PNG via
exportToBlob, including bound text, excluding connected arrows
- Draw mode text vanishing — skip redundant first
updateScenethat disrupted Excalidraw's Virgil font initialization - Draw mode view/edit/select — CSS overlay for view mode instead of toggling
viewModeEnabledprop; auto-switch to selection tool on entering Select mode
- Server layer test coverage:
skill-installer,file-watcher,ws-bridge-replay,ws-bridge-controls,ws-bridge-browser(105 new tests, 186 total)
- Added
@vite-ignoreto dynamic imports incore/mode-loader.tsto suppress Vite warnings for external mode loading - Added 30s timeout to
runGit()incore/mode-resolver.tsto prevent GitHub clone commands from hanging indefinitely
- Slide skill workflow: scaffold all empty slides + manifest first so the viewer shows the full deck structure immediately, then fill content slide-by-slide
- Updated CLAUDE.md, README.md with draw mode, mode-resolver, snapshot module, and accurate component/test counts
- Draw mode not registered in builtin mode tables (
mode-loader.tsandmode-resolver.ts)
- Draw Mode — Excalidraw whiteboard mode for
.excalidrawfile editing with live preview - Remote mode loading — load custom modes from local paths (
pneuma /path/to/mode) or GitHub repositories (pneuma github:user/repo#branch) - New
core/mode-resolver.tsfor mode source resolution and GitHub clone caching (~/.pneuma/modes/) - External mode registration in
core/mode-loader.tswith support for both Bun backend and browser frontend (Vite/@fs/imports) /api/mode-infoserver endpoint for frontend external mode discovery- Vite config
server.fs.allowsupport for external mode directories - AskUserQuestion interactive UI with option cards in PermissionBanner
- Slide image generation script rewritten from Python (
generate_image.py) to Node.js (generate_image.mjs) — zero external dependencies
- Slide sandboxed iframe image reload — uses meta tag injection instead of
location.reload()
- Self-contained HTML download for slide export — "Download HTML" button inlines all local assets (images, CSS, fonts) as base64 data URIs for fully offline viewing
- Export page slides not centered in viewport — body width moved to
@media printonly - Export download failing with non-ASCII titles — RFC 5987 Content-Disposition encoding
- Slide navigator thumbnails not showing images — proper URL resolution and base64 inlining for SVG foreignObject (#10)
- Grid view selected slide ring extending beyond thumbnail — removed redundant ring wrapper (#12)
- Export page losing styles: preserves
<head>resources,<body>attributes, and theme background colors (#15) - Export/print CJK text invisible — inject explicit CJK system fonts (PingFang SC, Noto Sans CJK SC, Microsoft YaHei) into
--font-sansbeforesans-serif - Export print missing backgrounds — add
print-color-adjust: exactandbreak-inside: avoidfor slides
- Slide skill font guidance:
style_reference.mdandSKILL.mdnow require CJK system fonts in--font-sans
- Element thumbnail capture: selected elements shown as SVG snapshots in ChatInput chip and SelectionCard
- CSS selector displayed in selection UI labels (replaces
<tag.class>format) - SVG icons directly selectable (added to semantic element list)
- Simplified context sent to Claude Code: just
[User selected: <css-selector>]instead of verbose 4-line format - Selection bubble-up threshold lowered from 150×80 to 40×40 for better small element selection
- Clicking X on selection chip now clears highlight in viewer iframe (#13)
selectorfield properly passed through full chain (iframe → store → extractContext)- Selection with CSS selector but empty text content no longer silently dropped
- Slide thumbnails missing viewport meta and base href, causing lost padding and broken assets
- Default slide outline position to bottom for narrow screens (was left sidebar)
- Chat panel narrowed to 40% (from 45%), preview widened to 60%
- Arrow keys no longer captured by slide navigation when typing in input fields (#7, #8)
pneuma snapshot push/pull/listcommands for workspace distribution via Cloudflare R2--include-skillsflag to optionally bundle.claude/skills/in snapshotsInitParam.sensitivefield in ModeManifest — sensitive config values stripped on snapshot push- Pull prompts before overwriting existing directory
- Pull offers to launch immediately after extraction
- Auto port retry on EADDRINUSE (up to 10 consecutive ports)
- Skill editing workflow: scope determination step (deck-wide vs single slide)
- Slide API key params (
openrouterApiKey,falApiKey) marked assensitive: true - CLI hint commands now use
bunx pneuma-skillsprefix