vessica-studio

module
v0.7.51 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: Apache-2.0

README

Vessica Studio

A local-first, agent-driven presentation studio built on ordinary files.

Documentation · Install the CLI and Codex plugin · Web editor guide · Architecture · Vessica voice agent

Vessica Studio turns a directory of HTML slide fragments and Markdown companions into a live, editable presentation. Use the vstd CLI to create, serve, review, fork, export, and deploy decks. Use Codex or another coding agent to work directly on the same transparent file format.

The result is a presentation workflow that is inspectable, diffable, forkable, and deployable with Git—without locking the deck inside a proprietary editor.

Contents

Why Vessica Studio

  • File-native authoring. Every slide is an HTML fragment paired with a Markdown companion containing intent, evidence, sources, visual direction, talk track, and edit history.
  • Agent-ready workflows. Six canonical authoring workflows are embedded in the vstd binary and shared across Codex and other agent runtimes.
  • Live editing. The studio watches files, rebuilds decks, reloads connected browsers, and supports direct canvas, companion, sticky-note, and voice edits.
  • Editable output. Download PDF or PowerPoint from the player. PowerPoint export preserves supported text, shapes, chart labels, and images as editable objects instead of flattening every slide into one image.
  • Reusable media. Generate images, ingest video, maintain a shared asset manifest, paste images onto slides, and sync large video files to S3-compatible storage.
  • Source-aware creation. Attach PDFs, PowerPoint files, documents, spreadsheets, or images to a slide companion so an editing agent can inspect the original source. Source-backed redesigns can run a separate visual critic pass against the reference.
  • Forkable decks. Create audience- or client-specific variants while retaining upstream provenance and detecting later parent changes.
  • Organized and reusable work. Keep a personal one-level folder view of owned and shared presentations, then send one or many slides to another deck as editable copies or read-only linked snapshots.
  • Presentation and audience modes. Present locally, publish a read-only audience surface, mint expiring deck links, and optionally enable chat, voice, SMS, email, and live audience pulse.
  • Local-first, cloud-capable. Author without a hosted service, connect or clone a Cloud workspace, synchronize revisions, and publish a selected revision without managing Git credentials or branches.
  • Single-team collaboration. Invite teammates by email, keep per-user private catalogs, share selected decks read-only, and fork shared work before editing it.

Installation

For the visual setup path, including Codex desktop and CLI plugin installation, see the installation guide.

Requirements

Prebuilt Linux/macOS binaries and SHA256SUMS are distributed with the GitHub releases. They retain immutable source revision metadata for release-build. Verify the downloaded binary against the release checksums before running it. The Go requirement below applies when building from source.

  • Go 1.26 or newer; the module selects patched Go 1.26.9 automatically when needed
  • Git, if you want version control or hosted content sync

Optional tools unlock additional features:

Tool Used for
Chrome or Chromium PDF export, editable PowerPoint export, chart-text migration, and visual review
FFmpeg and FFprobe Video normalization, metadata inspection, and poster extraction
LibreOffice and Poppler Rendering attached PowerPoint/PDF sources for visual comparison
OpenAI API key Image generation, Vessica voice, transcription, audience chat, and agent tools
Railway CLI Hosted deployment and service management
S3-compatible bucket Storage for video bytes that should not live in Git
Install with Go
go install github.com/vessica-labs/vessica-studio/cmd/vstd@latest
vstd version

If vstd is not found after installation, add Go's binary directory to your PATH:

export PATH="$(go env GOPATH)/bin:$PATH"
Build from source
git clone https://github.com/vessica-labs/vessica-studio.git
cd vessica-studio
make build
./vstd version

Use make install PREFIX="$HOME/.local" for a user-local installation, or make go-install to install through Go.

Optional OpenAI setup

The core file, build, serve, and presentation workflows do not need an API key. To enable AI-backed features:

export OPENAI_API_KEY="sk-..."
vstd key check

For a key that does not remain in shell history or a repository, use a secret manager and set openai.api_key_cmd in studio.yaml. A macOS Keychain example is included under Configuration.

Five-minute quickstart

Create a content repository and its first deck:

vstd init my-studio
cd my-studio
vstd new product-story --title "Our Product Story"
vstd serve product-story

Optional Vessica Studio Cloud workflow

These additive commands require a compatible hosted native-client API. The private service integration is tracked in VES-74; fake-cloud tests do not imply the public hosted service is available yet.

Local authoring, builds, serving, export, and skill discovery do not require a Cloud account or network connection. To use a Cloud workspace, first sign in with the native device flow:

vstd cloud login
vstd cloud account
vstd cloud presentation list

login prints a verification URL and user code. Renewable session material is stored in the operating system credential store; access tokens are kept only in memory. If secure credential storage is unavailable, login fails instead of writing a plaintext fallback. Concurrent native CLI processes serialize refresh credential rotation with an OS file lock, released automatically if a process exits. The per-endpoint lock in the user cache directory contains no credentials; refresh credentials remain in the OS credential store.

From any Codex chat or terminal directory, open an existing presentation by ID, exact title, or one unambiguous partial title. Without --root, the CLI creates or reuses an account-scoped managed checkout and reconciles it with the latest Cloud revision:

vstd cloud presentation open "Acme strategy" --json
vstd cloud presentation create --title "New client story" --json

Both commands return the local root used by the file-native authoring skills. The list marks known view-only presentations, and open refuses them before creating a checkout. Agent edits should run through vstd worktree begin and vstd worktree finish so concurrent visual-editor changes are reconciled before the result is saved to Cloud. A shared viewing link by itself does not grant authoring permission.

Clone a workspace into a directory that does not yet exist, or connect a valid existing studio:

vstd cloud workspace clone WORKSPACE_ID --target my-studio
vstd cloud workspace connect WORKSPACE_ID --root my-studio

The connection is recorded as non-secret local state in .vstd/cloud-workspace.json. It does not change the studio.yaml, deck.yaml, or paired slide-file contract and is excluded from synchronized content and build output.

From a connected studio, inspect and synchronize revisions with:

vstd cloud workspace status
vstd cloud workspace pull
vstd cloud workspace sync --message "Update product story"

status reports the recorded base revision, Cloud head, and whether the local files are synchronized, unsynced, behind Cloud, or offline. Both pull and sync checkpoint local work, reconcile against the latest Cloud version, and update the local files directly. No GitHub repository or Git credentials are needed for presentation storage. Cloud uses Postgres for durable writer journals and revision heads, and private object storage for immutable source checkpoints.

Complete revision downloads have a five-minute deadline so large presentations can refresh over slower connections. Other native API requests retain their two-minute deadline. An interrupted or timed-out transfer reports an offline read error, preserves local work, and does not replay a mutation automatically. Automatic Cloud synchronization during authoring worktree begin/finish shares the five-minute allowance for the whole sync operation.

Publish the current synchronized revision, or select a revision explicitly:

vstd cloud publish create
vstd cloud publish create --revision REVISION_ID
vstd cloud publish status PUBLICATION_ID

Browser writes are acknowledged after durable Cloud persistence, independently of background integration. A device outbox retries interrupted requests with the same operation ID. Compatible HTML properties, Markdown sections, and deck ordering changes merge automatically. Overlapping agent changes yield to direct human edits; original submitted checkpoints are retained rather than discarded. Device-draft recovery shares the original operation ID with the outbox, including across tabs and reloads. Slide reordering refreshes the open Grid immediately, preserving its scroll and zoom and an open companion draft. A move that finishes during a background refresh queues another refresh instead of leaving stale thumbnails. The synchronized file contract includes the scaffold's root .gitignore; credentials, .git/, and .vstd/ remain excluded.

Isolated editor-session workers can read the selected deck's cached raster at GET /api/app/decks/NAME/thumbnail.png; other catalog routes remain excluded. The host must authorize access and run rendering in its disposable content sandbox. Install Chromium and Poppler (pdftoppm) in raster workers. The engine gives its headless browser a temporary loopback-only, keyed print surface; the externally reachable editor remains bearer-protected throughout rendering.

For trusted supervisors, editor-transform accepts root instead of files to read a validated, materialized snapshot directory without base64 transport. The input directory is never modified. Optional delta: true returns only changed files plus deleted paths, with delta: true identifying the response format. An unchanged read returns empty arrays. Original full-snapshot callers remain compatible. The supervisor must never accept a caller-supplied host path.

Cloud visual editing can use vstd editor-transform: a bounded JSON input with deck, canonical files (path/base64 content), method, path, headers, and base64 body produces the HTTP-shaped result and resulting canonical files. It renders the same embedded HUD and applies the same structured slide and companion operations as local Studio. It never starts a listener, executes slide scripts, resolves credentials, invokes export tools, or calls providers. Unsupported execution routes fail closed; exports and agent work stay isolated. The caller owns authorization, durable operation IDs, acknowledgement, and reconciliation. Temporary files are scoped to one transform and removed afterward.

Run vstd worktree begin --root STUDIO before agent editing, work in the returned directory, then run vstd worktree finish --root WORKTREE. These commands sync connected presentations before/after reconciliation. Add --local-only to both commands for fully offline work. Worktrees and checkpoints remain under .vstd/. vstd serve synchronizes connected local workspaces every two seconds while running; otherwise run sync before opening files to fetch Cloud changes.

Pull keeps a durable, private local recovery journal before replacing files. If interrupted, the next sync restores the pre-pull projection before reconciliation. vstd cloud workspace recover --root DIR is also available for offline recovery. Do not delete the recovery journal manually. Unrelated Git and local state are preserved. Directory durability depends on the host filesystem (Windows lacks directory fsync); recovery is not a substitute for backups.

Cloud sessions are isolated by normalized endpoint. Keep VSTD_CLOUD_ENDPOINT consistent with the workspace association; a mismatch fails before content work. Snapshots reject credential commands and custom credential-bearing provider endpoints in studio.yaml; configure those providers locally via environment variables instead. These restrictions affect cloud exchange only, not local use.

Publishing without --revision is refused when local changes or a conflict are pending. The command reports the publication ID, selected revision, service status, and URL. Run vstd cloud diagnostics for sanitized endpoint and protocol compatibility details, and vstd cloud logout to revoke the session when reachable and remove the local credential.

Open http://localhost:4400/d/product-story/. The starter deck contains one cover slide. Edit its paired files under decks/product-story/slides/, or ask Codex to build out the deck. The server rebuilds on file changes and refreshes connected browsers.

In a second terminal:

cd my-studio
vstd list
vstd build product-story

The static build is written to decks/product-story/build/index.html. Build output is disposable; edit the source files under slides/, never build/.

From the player HUD you can:

  • navigate or present the deck;
  • enter slide-edit mode and edit supported elements;
  • open and edit the current slide's Markdown companion;
  • attach or inspect source files;
  • paste an image from the clipboard onto the slide;
  • leave a sticky-note instruction for the redesign agent;
  • download PDF or editable PowerPoint.

Use Vessica Studio with Codex

Vessica Studio keeps its authoring instructions in seven canonical skills:

Skill Use it for
cloud-presentation Open or create a Cloud presentation from any Codex chat
deck-new Frame, outline, create, and visually review a new deck
slide-add Insert one or more context-aware slides into an existing narrative
slide-edit Edit content or layout while preserving the companion contract
deck-fork Tailor a deck for a client, audience, industry, or event
deck-review Run whole-deck visual, narrative, and companion QA
market-refresh Re-research dated claims and update time-sensitive slides

The skill files are embedded in vstd; the CLI can list or print them at any time:

vstd skill
vstd skill conventions
vstd skill slide-edit
Install the Codex plugin

Add the repository's marketplace, then install Vessica Studio:

codex plugin marketplace add vessica-labs/vessica-studio --ref main
codex plugin add vessica-studio@vessica-studio

Start a new Codex task after installation so the seven plugin skills are discovered. In Codex CLI, /plugins opens the plugin browser; in Codex desktop, use the Plugins surface. Verify the install with codex plugin list.

The repository also retains legacy thin prompt launchers for environments that do not support plugins. Clone the repository and run ./codex/install.sh; it copies launchers into ${CODEX_HOME:-$HOME/.codex}/prompts. The launchers call vstd skill at runtime and require a new Codex session after installation.

Use a launcher explicitly:

/vstd-cloud-presentation Open the Acme strategy presentation from Cloud and edit slide 40
/vstd-deck-new Build a 12-slide board presentation about our product strategy
/vstd-slide-add Add a customer proof slide after 0040
/vstd-slide-edit Redesign slide 0060 around the attached source PDF
/vstd-deck-review Review the entire deck before tomorrow's presentation
/vstd-deck-fork Fork product-story for Acme's executive team
/vstd-market-refresh Refresh every market statistic through August 2026

You can also ask Codex naturally. A useful request names the studio root or deck, the audience, the desired outcome, and any constraints:

Use the Vessica Studio slide-edit workflow to simplify slide 0070 in the
product-story deck. Preserve its evidence and talk-track transition, keep the
chart editable, and run a visual critic pass.

Codex should read vstd skill conventions before deck work and the relevant workflow before acting. Copy codex/AGENTS.md into a studio content repository to make those rules persistent for that repository. The guide tells Codex to preserve slide/companion pairs, use the canonical skills, and avoid generated build output.

Plugin skills may be invoked explicitly from Codex's skill picker or with the $ skill syntax, for example $vessica-studio:slide-edit. Codex can also select a skill implicitly from its description. See the Codex plugin documentation and Codex skills documentation for current installation, discovery, and invocation behavior.

What the skills enforce

The workflows are more than prompt templates. They preserve the authoring contract:

  1. Read the companion before changing a slide.
  2. Keep factual claims aligned with evidence and sources.
  3. Update the talk track and its transition to the next slide.
  4. Record the completed change in the companion log.
  5. Give every generated slide a meaningful visual.
  6. Run a visual critic pass after layout or design changes.
  7. Compare source-backed slides directly with the attached original.

The source of truth lives in plugin/skills and plugin/docs/conventions.md. The Codex launchers do not duplicate those instructions.

Claude Code and Cowork

The same workflows are packaged as a Claude plugin:

/plugin marketplace add vessica-labs/vessica-studio
/plugin install vessica-studio@vessica-studio

Start a new session, ask naturally for a deck task, or invoke a workflow such as /vessica-studio:deck-new. Both integrations ultimately read the same files embedded in vstd.

How a studio is organized

my-studio/
├── studio.yaml                    # engine, model, port, and storage settings
├── themes/
│   └── default/
│       ├── theme.css              # presentation styling
│       └── tokens.json            # design tokens
├── library/
│   ├── manifest.json              # shared image and video catalog
│   ├── img/                       # generated or uploaded images
│   ├── video/                     # local video bytes; keep out of Git
│   └── video-posters/             # generated poster frames
├── requests/                      # asynchronous media and redesign requests
├── site/                          # optional public homepage and assets
└── decks/
    └── product-story/
        ├── deck.yaml              # title, theme, visibility, fork provenance
        ├── deck.css               # deck-specific style overrides
        ├── sources/               # original PDFs, PPTX files, images, and documents
        ├── build/
        │   └── assets/powerpoint/    # disposable per-slide PowerPoint cache
        └── slides/
            ├── 0010-cover.html    # one root <section class="slide">
            ├── 0010-cover.md      # companion evidence, intent, talk track, and log
            └── 0010-cover.link.yaml # optional Vessica-managed slide link provenance
The slide pair

Each slide has two source files with the same basename:

  • NNNN-slug.html contains exactly one root <section class="slide">. Slide order follows the numeric filename prefix; sparse numbering such as 0010, 0020, and 0030 leaves room to insert.
  • NNNN-slug.md contains frontmatter plus Intent, Key ideas, Evidence & sources, Talk track, Visual direction, and Log sections.

The companion is part of the content model, not optional documentation. It is the agent's context, evidence record, and presenter cue sheet.

A linked slide still has the normal HTML/Markdown pair as a durable snapshot. Its optional .link.yaml sidecar points to the source deck and slide and records source hashes and the last refresh. Linked target slides are read-only until detached. When the target owner retains source access, Studio refreshes changed HTML, companion content, and source attachments. If the source disappears or access is revoked, the last snapshot continues to render and is marked stale to presenters; audience views and exports show only the slide. Copying a linked slide flattens its latest snapshot into an ordinary editable slide.

Source files used to create a slide live in decks/<deck>/sources/ and are declared in companion frontmatter:

attachments:
  - name: source-deck.pptx
    path: sources/0030-source-deck-a1b2c3.pptx
    media_type: application/vnd.openxmlformats-officedocument.presentationml.presentation
    page: 3
Engine-owned player, theme-owned presentation styling

The player and HUD are embedded in the engine. Themes provide theme.css and design tokens; they do not replace the player markup. This keeps navigation, editing, export, Vessica, video controls, and audience behavior consistent across themes.

Slides use a fixed 1280×720 canvas. Mark an element with data-current-month-year to render the viewer's current month and year, such as August 2026, at runtime and in browser-backed exports.

CLI manual

Run vstd help for the installed command summary. Examples below assume the current directory contains studio.yaml. Most studio commands also accept --root DIR; it is a per-command flag, not a global flag.

Create and inspect studios
vstd init [dir]

Scaffold a studio root without overwriting existing files:

vstd init quarterly-presentations

Creates studio.yaml, the default theme, an empty asset manifest, decks/, library/, and requests/.

vstd new <deck> [--title T] [--root DIR]

Create a deck with metadata, deck CSS, and a paired starter cover slide:

vstd new operating-model --title "The AI Operating Model"

Deck names use lowercase letters, digits, and hyphens.

vstd list [--root DIR]

List every deck, slide count, title, and fork parent:

vstd list
Build, serve, and present
vstd build <deck> [--root=DIR]
vstd build --all [--root=DIR]

Assemble one deck or every deck into generated build/index.html files:

vstd build operating-model
vstd build --all
vstd release-build [deck] --output DIR [--root DIR]

Build one deck for immutable hosted delivery through the public engine contract. The command requires a revision-identifiable, unmodified vstd binary and an empty output directory. It writes a self-contained index.html, only the referenced release assets, and release-manifest.json with the exact engine version/revision plus deterministic artifact and manifest SHA-256 checksums. When deck is omitted, the studio must contain exactly one deck.

vstd release-build product-story --output /tmp/product-story-release

Optional delivery flags preserve editable originals and produce host-ready artifacts:

vstd release-build product-story --output /tmp/product-story-release --delivery-template --optimize-delivery
vstd delivery-resources --output /tmp/vstd-platform-assets

--delivery-template emits typed vstd-asset:<sha256>:<base64url-path> slots. An authorized host must replace only manifest members with its delivery URLs; vstd-session:keepalive accepts a cookie-authenticated renewal URL or an empty string. Image and CSS background references, including quoted URLs in inline styles, use the same manifest-scoped delivery paths. Templates are not directly browsable until these slots are resolved. Ordinary release-build remains self-contained and needs no Cloud account or network.

--optimize-delivery requires cwebp for raster images and FFmpeg for videos. It emits transparent WebP variants up to 640/1280/1920 pixels without upscaling, responsive srcsets, sanitized SVG, minified HTML/CSS/JS, H.264 MP4 capped at 1080p with fast-start, and WebP posters. Variants and dimensions are optional artifact fields; delivery settings and variant rules participate in the deterministic manifest checksum. Original studio files are retained unchanged. Encoder versions should be pinned consistently across build workers.

delivery-resources exports only compiled-in engine/default-theme CSS named by its digest. Hosts install this trusted output independently of tenant uploads; custom themes and deck overrides remain presentation scoped. A host must not trust a tenant-provided path as permission to populate its shared namespace.

The data-only editor-transform protocol also accepts optional asset_urls (logical /library/... or /assets/video/... paths mapped to HTTPS URLs) and asset_session_url. The engine applies these at render time, uses direct video URLs, and restores logical paths on saves. Hosts provide access metadata; the engine continues to own rendering, progressive loading and editor serialization.

The release output contains no companion Markdown or authoring source. Missing, unsafe, symlink-escaped, oversized, or mutable assets fail the build rather than producing a partial release.

Consumers installing directly from an immutable Git revision must embed the same full revision so the binary can verify and report it. For example, with REVISION set to a 40-character commit SHA:

go install -ldflags "-X main.releaseBuildRevision=$REVISION" \
  "github.com/vessica-labs/vessica-studio/cmd/vstd@$REVISION"

Running vstd build without a deck also builds all decks. When building from outside the studio directory, use the --root=DIR form so the deck name remains unambiguous to the current command parser.

vstd serve [deck] [flags]

Build, watch, live reload, and expose the player and HTTP editing surface:

vstd serve operating-model
vstd serve operating-model --port 4500
vstd serve --mode present
vstd serve --mode public
vstd serve operating-model --agent

Flags:

Flag Meaning
--root DIR Studio root; default .
--port N Override studio.yaml, PORT, and the default port
--mode studio|present|public Select the authorization and editing mode
--agent Run the optional redesign worker alongside the server

Serving modes:

Mode Intended use Content writes Access model
studio Local authoring Yes Local operator is the presenter
present Local presenting No Local operator is the presenter
public Hosted presenting Presenter-only when content sync is enabled GitHub-allowlisted presenter or signed audience link

Do not expose studio mode to an untrusted network. Its write routes trust the local operator.

PDF and PowerPoint export

Start vstd serve, open a deck, choose Entire deck or Current slide in the Download menu, and then choose PDF, visual-exact PowerPoint, or editable PowerPoint. Presenters receive all three formats; audience sessions receive PDF only. Browser-backed export requires Chrome or Chromium on the machine running vstd; visual-exact PowerPoint rasterization also requires Poppler. Editable capture uses a disposable loopback DevTools connection and waits for the object model to finish, including asynchronous image and CSS background decoding.

The HTTP routes accept an optional non-parked slide ID, for example /api/deck/operating-model/export.pdf?slide=0030-economics and /api/deck/operating-model/export.pptx?mode=editable&slide=0030-economics. Without slide, they preserve the existing whole-deck behavior.

PDF is a fixed-layout document and is regenerated per request. PowerPoint stores disposable per-slide artifacts and a manifest under decks/<deck>/build/assets/powerpoint/. Repeating an export reuses unchanged slides; changing a fragment, referenced local asset, theme CSS, or deck CSS invalidates only the affected entries (theme/deck CSS naturally affect the whole deck). The cache is excluded from Git, content sync, file-watcher reloads, bundles, and source-asset manifests. Delete that directory at any time to force a clean rebuild. Editable PowerPoint converts supported rendered elements into native PresentationML objects. Text retains browser wrapping, padding and inline styles; SVG paths retain editable subpaths, Bézier controls, gradient stops and dash patterns. Generated CSS bullets and arrows are included. Complex CSS backgrounds, masks and shadows become individual pictures, while text and ordinary shapes remain editable. The installed font that Chromium actually uses is recorded; the same font should be available on the PowerPoint machine.

Registered MP4 assets are embedded with their posters in editable exports. In PowerPoint slide show, the first advance on a video slide starts playback using the native click sequence; the media remains a selectable video object. Source bytes must exist under library/video/ or in the configured storage bucket and match the manifest digest and size. Missing or corrupt media fails export explicitly. The unique video budget is 512 MiB; repeated media is packaged once. Hosts with isolated execution can first request the same editable export URL with media=plan to get { "videos": ["registered-id"] } for the browser-measured selection. Materialize those manifest-verified MP4 files into the same content root, then request the ordinary editable export. The plan uses the same presenter authorization and cached DOM capture. Simulator bundles retain their static backdrop only. Complex browser effects may still differ, so review the downloaded deck before delivery.

vstd bundle <deck> [--root DIR]

Create a portable folder containing index.html and the referenced local media:

vstd bundle operating-model

Output is written to decks/<deck>/build/bundle/. Keep the folder together when presenting offline. This is the preferred static export for video-bearing decks.

Fork and maintain deck variants
vstd fork <deck> <client> [--root DIR]

Create decks/<deck>--<client> with fork provenance and per-slide parent hashes:

vstd fork operating-model acme
vstd diff-upstream <fork> [--root DIR]

Report slides added, removed, or changed in the parent since the fork:

vstd diff-upstream operating-model--acme

This is a detection tool, not an automatic merge. Use the deck-fork or slide-edit workflow to port upstream improvements while preserving client customizations.

Images and the shared asset library
vstd asset gen

Generate and register an image:

vstd asset gen \
  --prompt "Editorial illustration of human and AI collaboration" \
  --family editorial \
  --tags workforce,collaboration \
  --size 1536x1024 \
  --slug human-ai-team

Flags:

Flag Meaning
--prompt P Required image prompt
--family F Style family from library/manifest.json
--tags a,b Comma-separated retrieval tags
--size WxH Requested image size; default 1024x1024
--slug S Stable asset ID slug
--dry-run Show the resolved prompt and ID without calling the API
--root DIR Studio root

Generated files are cataloged in library/manifest.json and referenced from slides as /library/<file>. Reuse an existing asset before generating a near duplicate. Image registration preserves existing image source attribution and unknown asset metadata in library/manifest.json. Adding a generated image does not discard metadata on existing references.

vstd asset list and vstd asset find

Browse the manifest or search by family and tags:

vstd asset list
vstd asset find --tags workforce,collaboration
vstd asset find --family editorial

Tag matching is “any of” the supplied tags. find prints a generation hint when no asset matches.

Interactive application bundles

Use a self-contained ZIP for a simulator or other interactive slide application:

vstd asset add-bundle ./simulation.zip --slug simulation --entrypoint index.html --poster img/simulation.jpg
vstd asset inspect-bundle ./simulation.zip --entrypoint index.html --json

The library manifest stores a bundles entry with id, content-addressed file (bundle/<sha256>.zip), hash, bytes, entrypoint, expandedBytes, and fileCount, plus optional poster and created. Keep library/bundle/ out of Git. ZIPs stay outside the canonical Cloud snapshot; native sync uploads verified bytes separately, using the additive asset.bundle.write capability, before syncing their manifest. Import the original ZIP for local offline use; Cloud-only checkouts may retain references without the local archive.

A slide launches a bundle explicitly:

<div data-vstd-bundle="simulation" style="position:relative;width:100%;height:100%" aria-label="Simulation">
  <button data-bundle-launch>Start simulation</button>
  <span data-bundle-status role="status"></span>
</div>

Version 1 supports inline application JavaScript and CSS with relative data and image files. Bundle module dependencies into inline code before importing; external scripts, import maps, embedded frames, network services, workers and parent-document access are unsupported. The app runs in an opaque-origin allow-scripts sandbox. Archives download only after launch, including in Cloud, and leaving the slide destroys the frame. Thumbnails and exports show the slide's authored static preview. Limits are 128 MiB compressed, 256 MiB expanded, 512 files and an 8 MiB HTML entrypoint. Paths, entry types, collisions, CRCs, sizes and manifest integrity are validated without executing the app.

Immutable releases include the ZIP and an engine-generated download shell marked bundle-relay-v1; the authored presentation remains sandboxed in presentation.html. The shell preserves the viewer query and slide fragment when opening that document, so unlisted links remain authorized. Hosts may give only that verified entrypoint authority to fetch declared release assets and transfer bytes into its opaque child. Never give application frames cookies, delivery URLs or a credentialed null-origin CORS allowance. Serve ZIPs as binary attachments, never application HTML from a credentialed Studio origin.

Video assets and object storage
vstd asset add-video <file>

Inspect, optionally normalize, posterize, hash, and register a video:

vstd asset add-video ./demo.mov --slug product-demo --tags demo,product

Flags:

Flag Meaning
--slug S Asset ID; defaults from the filename
--tags a,b Comma-separated retrieval tags
--no-transcode Keep the original bytes while still hashing and posterizing
--root DIR Studio root

When storage is configured, ingestion also uploads missing bytes. Reference a cataloged video by ID, never by a hard-coded source path:

<video class="vid" data-vstd-video="product-demo" data-autoplay data-loop></video>

The player owns source resolution and playback. Video slides include a persistent sound on/off control for editing and presenting.

vstd asset push and vstd asset pull

Synchronize manifest-referenced video files with an S3-compatible bucket:

vstd asset push
vstd asset pull

push uploads missing objects. pull restores video bytes missing from a fresh checkout. Keep library/video/ out of Git; commit the manifest and posters.

Editable chart migration

Charts should use a hybrid structure by default: inline SVG for plotted geometry and positioned HTML for human-readable text. The chart can be selected as a group while labels remain editable and export as PowerPoint text boxes.

vstd chart promote-text <deck> <slide>

Preview and migrate text from an existing inline SVG chart:

vstd chart promote-text operating-model 0060-growth --dry-run
vstd chart promote-text operating-model 0060-growth

Additional flags are --root DIR and --chromium PATH. The command uses rendered browser geometry, appends a companion log entry, and refuses partial writes when it encounters unsupported curved or zero-size text. It does not migrate raster charts.

Agent and skill commands
vstd skill [name]

List embedded skills or print one workflow/reference document:

vstd skill
vstd skill conventions
vstd skill deck-review

The output is plain Markdown designed to be read by any coding agent.

vstd agent [--root DIR]

Run one synchronous sweep of queued redesign requests:

VSTD_AGENT=1 vstd agent

Use vstd serve --agent or VSTD_AGENT=1 vstd serve for a continuous background worker. The default coding agent is Claude pinned to claude-opus-5-5; set VSTD_AGENT_CMD or the related agent environment variables to use another command and tune limits. Hosted Codex workers must set VSTD_AGENT_SANDBOX=railway: the API service dispatches each pass to a disposable, network-isolated Railway Sandbox and refuses to run Codex in-process in public mode. The dispatcher requires a project-scoped RAILWAY_TOKEN, RAILWAY_ENVIRONMENT_ID, and the Railway JavaScript SDK at VSTD_RAILWAY_SDK (default /opt/vstd-sandbox/node_modules/railway/dist/index.js). The sandbox receives only the requested deck, its theme and referenced library assets, matching asset requests, the vstd binary, and an OpenAI credential resolved by Railway variable reference.

vstd key check [--root DIR]

Confirm that an OpenAI key resolves without printing the key or its source:

vstd key check
vstd qr <deck>

Mint an expiring, signed, deck-scoped audience URL and save a QR image:

vstd qr operating-model --ttl 24
vstd qr operating-model --ttl 72 --host https://decks.example.com

The signing secret comes from VSTD_SECRET or share_secret_cmd. The QR image is saved to decks/<deck>/build/share-qr.png.

Railway commands
vstd railway up

Configure and deploy a content repository that already contains its deployment files:

vstd railway up --dry-run
vstd railway up --client-id GITHUB_OAUTH_CLIENT_ID --allowed octocat

Flags:

Flag Meaning
--root DIR Studio root
--client-id ID GitHub OAuth app client ID with Device Flow enabled
--allowed a,b Comma-separated presenter GitHub logins
--github-token TOKEN Read token for cloning a private engine repository
--with-openai-key Copy the locally resolved OpenAI key without prompting
--dry-run Print the deployment plan without calling Railway

The command ensures the Railway CLI is available, signs in if needed, links or creates a project, sets core variables, deploys, obtains a domain, and stores the public host in studio.yaml. It requires a Dockerfile and the related deployment files in the content repository.

vstd railway status and passthrough
vstd railway status
vstd railway logs
vstd railway variables

status reports the linked service and saved public host. Any other arguments are passed to the Railway CLI from the studio root.

Help and version
vstd help
vstd version

help prints the installed command and environment summary. version is useful when reporting a bug or confirming which engine build a hosted studio runs.

Studio and player features

Direct editing, the ribbon, and the slide panel

Press E (or choose Edit in the player HUD) to enter edit mode. The bottom HUD gives way to a ribbon across the top of the window: home, deck title, slide stepper, new slide, grid, agenda, notes, sticky, companion, knowledge base, Vessica, a save indicator, download, share, Present, and Done. Every ribbon control shows its name and keyboard shortcut in a tooltip on hover or focus. A slide panel on the left lists thumbnails of every slide: click one to jump to it, drag one to reorder, and use New slide at the bottom to insert after the current slide. The panel collapses from its header button and remembers that choice.

Select a supported text, shape, image, or chart element on the slide and an object bar slides in under the ribbon with the controls that apply to that object: edit text, bold, italic, underline, text size, text/fill/line color, picture crop and zoom, video playback options, reset, and delete. It disappears again when nothing is selected, so the canvas stays clear.

Edit-mode shortcuts: Enter edits the selected text, ⌘B / ⌘I / ⌘U toggle bold, italic, and underline, ⌘⇧> and ⌘⇧< change text size, ⌘D duplicates the selection, C toggles crop on a picture, Delete removes the selection, arrow keys nudge (Shift for larger steps), ⌥ while dragging disables snapping, ⌘Z / ⌘⇧Z undo and redo, ⌘S saves now, and Esc deselects, then leaves edit mode. Keyboard shortcuts are suppressed while typing in sticky notes, companion fields, dialogs, or editable elements. Edits are also saved automatically when you leave edit mode; the ribbon indicator shows Saved, Unsaved, Saving…, or Conflict when a slide changed on disk after the page loaded.

Pictures include both <img> elements and elements whose CSS uses a background image. Select a picture and choose Crop to drag the image within its fixed frame; the arrow keys provide fine positioning. CSS background pictures also expose Zoom − and Zoom + controls to loosen or tighten the crop. These position and size changes are saved with the slide fragment like other direct edits.

Drag across blank slide canvas to draw a marquee around multiple objects. The selected objects receive one combined outline; drag any selected object to move the group, use the arrow keys to nudge it, or press Delete to remove every selected object in one undoable edit. Object-specific formatting, resizing, and picture cropping remain available when exactly one object is selected.

Companion drawer and source attachments

The companion button opens the current slide's Markdown in a side drawer. The drawer renders the document for reading and supports direct editing. Vessica can open the companion and apply dictated narrative edits.

Attach a PDF, PPT/PPTX, document, spreadsheet, or image to the companion. The file becomes part of the slide's source record and is available to the editing agent. A source-aware request can be as direct as:

Look at exhibit A on page 12 of the attached PDF and add the missing customer
segment detail to this slide.
Images from the clipboard

Enter slide-edit mode, copy an image, and paste it onto the slide. Vessica Studio adds the image to the library, content-hash deduplicates it, and creates an editable canvas element.

Hybrid editable charts

Use one data-chart-group container containing:

  • an SVG .chart-art layer for axes, gridlines, lines, bars, areas, dots, and decorative geometry; and
  • absolutely positioned .chart-label[data-edit] HTML elements for ticks, legends, values, annotations, and other text.

Keep an accessible description on the chart geometry with aria-label, <title>, or <desc>. Vessica can highlight a chart when the spoken topic matches its accessible description or visible labels. Slide titles are excluded from Vessica highlighting.

Interactive simulation controls

Vessica can launch/resume, pause, jump to a checkpoint, change playback speed, select a camera, or request the actual state of an opted-in simulation on the active slide. For example: “Vessica, pause the simulation” or “Vessica, switch to the cockpit.” control_simulation accepts action (start, stop, checkpoint, speed, camera, or status), plus the matching checkpoint, speed, or camera argument. Stop pauses and retains position. Only explicit simulator requests trigger these controls; stopping the flight does not end the conversation.

An iframe opts in with its supported values and a same-origin launch URL:

<iframe data-vstd-simulation='{"name":"Flight","checkpoints":["Dzong"],"speeds":[1,2,4],"cameras":["director","cockpit"]}'
        data-vstd-simulation-src="/site/flight/" srcdoc="Launch screen"></iframe>

An optional comma-separated data-vstd-simulation-hosts restricts availability to named hosts, useful while a runtime is local only. Thumbnails, hidden slides, and audience clients cannot issue commands. Launching requires start; subsequent commands return the simulator's confirmed state, or an error after a bounded wait.

For cataloged applications, put data-vstd-simulation on the data-vstd-bundle container instead of an iframe. The tool uses the existing bundle loader, verifies the archive, and controls only that container's opaque application frame. The bootstrap supplies window.VSTDSimulationHost.origin for validating parent messages without accessing parent credentials or DOM. An opaque child replies with origin null; the player checks its exact window identity as well as that origin. Leaving the slide destroys this sandbox and returning starts a fresh session, as with manually launched bundles.

The embedded application listens for parent postMessage requests with type vstd:simulation:command, a unique id, action, and its matching argument. It must validate the parent source/origin and permitted values, and respect lifecycle; deduplicate by id; and pause rendering/playback when its slide is inactive. Reply to the exact parent origin with vstd:simulation:accepted while loading, then vstd:simulation:result with the same id and either {ok:true,state:{...}} or {ok:false,error:"..."}. The player verifies frame source and origin, cancels requests on slide/auth changes, and includes the capability catalog in Vessica's current-slide instructions. No arbitrary code or iframe URL is supplied by the voice tool. This contract controls an available runtime; it does not upload or host application assets.

Video playback

The player starts and stops cataloged videos as slides enter and leave. Video slides expose a small persistent sound switch so editing does not repeatedly trigger audio. Use data attributes such as data-autoplay, data-loop, data-unmuted, and data-keep-time to control behavior.

Configuration

A new studio.yaml starts with:

theme_default: default
port: 4400
openai:
  image_model: gpt-image-2
  realtime_model: gpt-realtime-2
  base_url: https://api.openai.com/v1

Other supported top-level settings include app_host, public_host, share_secret_cmd, and storage. In hosted collaboration mode, app_host is the authenticated catalog/team origin and public_host is the separate player and audience origin.

OpenAI

Key resolution order is:

  1. OPENAI_API_KEY
  2. VSTD_OPENAI_KEY
  3. openai.api_key_cmd in studio.yaml

Example using macOS Keychain:

security add-generic-password -U -s vessica-openai -a "$USER" -w 'sk-...'
openai:
  image_model: gpt-image-2
  realtime_model: gpt-realtime-2
  base_url: https://api.openai.com/v1
  api_key_cmd: security find-generic-password -s vessica-openai -w

Run vstd key check after configuring the resolver.

S3-compatible storage

Storage can be configured in YAML:

storage:
  endpoint: https://s3.example.com
  bucket: presentation-media
  region: us-east-1
  access_key_cmd: security find-generic-password -s vstd-s3-access -w
  secret_key_cmd: security find-generic-password -s vstd-s3-secret -w

Or with environment variables:

Variable Purpose
VSTD_S3_ENDPOINT S3-compatible API endpoint
VSTD_S3_BUCKET Bucket name
VSTD_S3_REGION Region
VSTD_S3_ACCESS_KEY Access key
VSTD_S3_SECRET_KEY Secret key

Environment variables take precedence over YAML.

Runtime and hosted environment variables
Variable Purpose
PORT Override the configured HTTP port; Railway sets this
VSTD_MODE studio, present, or public
VSTD_CHROME / VSTD_CHROMIUM Browser executable for exports and migration
VSTD_SECRET Sign presenter sessions and audience links
VSTD_GITHUB_CLIENT_ID GitHub OAuth application with Device Flow enabled
VSTD_ALLOWED_GITHUB Comma-separated presenter login allowlist
VSTD_COLLABORATION Set to 1 to enable PostgreSQL-backed single-team collaboration
DATABASE_URL PostgreSQL connection URL; required in collaboration mode
VSTD_APP_ORIGIN Exact HTTPS origin for marketing, authentication, catalogs, and team administration
VSTD_PLAYER_ORIGIN Separate exact HTTPS origin for deck execution, audience links, and player APIs
VSTD_DOCS_URL Documentation-site URL opened from the presentation catalog; defaults to https://studio-docs.vessica.ai
VSTD_OWNER_GITHUB_LOGIN GitHub login that may bootstrap and administer the team
PUBLIC_URL Public base URL for audience and action links
VSTD_CONTENT_SYNC Set to 1 to enable authenticated hosted editing
VSTD_GIT_REPO Git content repository URL
VSTD_GIT_BRANCH Content branch to push and poll
VSTD_GIT_TOKEN Repository-scoped content write token
VSTD_GIT_DEBOUNCE_SECONDS Delay before batching hosted edits into a push
VSTD_GIT_POLL_SECONDS Remote polling interval
VSTD_AGENT Set to 1 to enable the redesign worker
VSTD_AGENT_CMD Agent command or supported agent name
VSTD_AGENT_SANDBOX Set to railway for hosted Codex execution; required for Codex in public mode
VSTD_AGENT_SANDBOX_SECRET_SERVICE Railway service name that owns the Codex credential; defaults to RAILWAY_SERVICE_NAME
VSTD_AGENT_SANDBOX_SECRET_VARIABLE Railway variable referenced as the sandbox Codex credential; defaults to OPENAI_API_KEY
VSTD_RAILWAY_SDK Absolute path to the Railway JavaScript SDK entrypoint
RAILWAY_TOKEN Project-scoped Railway token used only by the sandbox dispatcher
VSTD_AGENT_TIMEOUT Redesign timeout, such as 30m
VSTD_AGENT_CRITIC_TIMEOUT Source-critic timeout, such as 20m
VSTD_AGENT_CONCURRENCY Maximum concurrent redesign jobs
VSTD_AGENT_MAX_PER_HOUR Hourly redesign-job limit
VSTD_GIT_PUSH Set to 1 to commit and push completed redesign passes
VSTD_GIT_REMOTE Bootstrap remote used by the legacy redesign-worker Git path
VSTD_TOOLS_MODEL Model used for Vessica tools
VSTD_TRANSCRIBE_MODEL Model used for transcription
TELNYX_API_KEY, TELNYX_FROM_NUMBER, TELNYX_CONNECTION_ID Optional SMS and calling actions
RESEND_API_KEY, RESEND_FROM, VSTD_CONTACT_TO Optional email and public contact actions

Never place credentials in slide files, deck metadata, built output, manifests, fixtures, or Git history.

Hosted deployment

public mode keeps audiences read-only. Presenters authenticate through GitHub Device Flow and must appear in VSTD_ALLOWED_GITHUB. Successful sign-in opens the non-cacheable /presentations index so a public marketing homepage at / cannot mask the authenticated presenter session.

When VSTD_CONTENT_SYNC=1, an authenticated presenter can use sticky-note, direct-edit, companion, attachment, and pasted-image controls in the hosted player. A save updates the running instance immediately. A background worker then batches content-only commits to the configured Git repository and polls the branch for remote changes.

The Git token is sent through an ephemeral authorization header; it is not written into the remote URL, command arguments, or .git/config. Scope it to Contents read/write on the content repository only.

To keep content saves from redeploying the application, configure Railway watch paths around deployment and engine files rather than the deck content paths. Video bytes remain outside Git and are synchronized through object storage.

Without content sync, public mode remains read-only. Audiences enter through expiring deck-scoped links created by vstd qr.

Team collaboration mode

Collaboration mode is additive and disabled by default. It requires public mode, PostgreSQL, and separate app/player origins:

app_host: https://studio.example.com
public_host: https://present.example.com
VSTD_MODE=public
VSTD_COLLABORATION=1
DATABASE_URL=postgresql://...
VSTD_APP_ORIGIN=https://studio.example.com
VSTD_PLAYER_ORIGIN=https://present.example.com
VSTD_OWNER_GITHUB_LOGIN=octocat

Startup runs additive schema migrations under a PostgreSQL advisory lock and reconciles filesystem decks into the catalog. The first matching GitHub login becomes the owner and claims previously unowned decks as private. The owner can invite members from /team; invitation and password-reset email uses RESEND_API_KEY and RESEND_FROM.

The owner signs in through a guided GitHub device flow. Vessica opens GitHub in a new tab, keeps the temporary code visible with its remaining lifetime, and copies it when the code is clicked. The in-progress flow is retained in tab sessionStorage, so a reload or temporary network interruption does not force the owner to race for or lose the code.

Each user owns their decks. Team visibility grants other active members View, Present, export, and Fork access, but never Edit or sharing authority. Forks are private copies with upstream hashes and provenance. Removing a member revokes their sessions immediately and transfers their decks to the owner without changing visibility.

The presentation directory adds one-level personal folders plus All, Mine, Shared, and Recent views. Folder placement belongs only to the signed-in user: moving a shared deck does not change its owner, visibility, team permissions, or any teammate's organization. A permanent personal Trash folder keeps removed presentations intact and out of the normal catalog views; moving them to another folder restores them. Trash cannot be renamed, deleted, or emptied. Deleting a regular folder returns its presentations to the root. Local serving persists the same organization as an atomic mode-0600 JSON file in the OS user-config directory, keyed by the canonical studio root, so it never enters deck content or Git.

Slide transfer requires Fork access to the source and Edit access to an owned target. Copy creates a normal target-themed slide pair and content-deduplicated copies of companion attachments. Link creates a target-themed, read-only live snapshot; link-to-link chains are rejected. Player-grid selections cross to the app picker through a five-minute single-use intent bound to the authenticated user, carried only in the URL fragment. Retained linked snapshots intentionally remain in the target after source access is revoked; detach them if that continuity behavior is not appropriate for a particular deck.

The account cookie is host-only on the app origin and is never player authorization. App launches exchange a 60-second, single-use handoff for a 12-hour deck/mode bearer kept in tab sessionStorage; every player request revalidates membership, deck ownership, visibility, and mode. Native media uses a separate player-host-only HttpOnly cookie accepted only by media handlers. Keep the deployment at one application replica while its writable Git checkout remains a single-writer process.

Owner monitoring

Collaboration mode also enables an owner-only /observability workspace, linked from the presentation catalog immediately above Documentation. It shows 7-, 30-, and 90-day audience summaries, named QR-chat participants, anonymous privacy-preserving visitor labels, presentation and slide views, team activity, sanitized HTTP 5xx routes, and model token usage from both direct OpenAI API requests and Codex agent runs dispatched to Railway Sandboxes.

Audience and player requests never wait for analytics writes. Events enter a bounded in-process queue and are flushed to PostgreSQL in small background batches; if that queue reaches capacity, events are dropped and the count is shown to the owner. Viewer records use a random first-party HttpOnly identifier. The engine does not store viewer IP addresses, user agents, share tokens, prompts, model responses, or error response bodies in observability data. OpenAI API totals come from response usage and authenticated Realtime events. Codex totals come from the privacy-safe model, session, and total-token summary printed by each CLI run. Sandbox execution metadata records the disposable sandbox identifier for attribution; the CLI does not report an input/output split, so that breakdown is intentionally left blank in the dashboard. The owner route and its JSON API re-check the permanent team-owner capability on every request; ordinary team members and the player origin cannot access them.

To roll back application behavior without discarding collaboration data, disable VSTD_COLLABORATION, restore the former canonical public_host, and redeploy. Migrations are additive and are not reversed.

See docs/THREAT_MODEL.md for trust boundaries, existing controls, and hardening recommendations.

Architecture

Package Responsibility
cmd/vstd CLI parsing and orchestration, including Railway operations
internal/studio Configuration, deck/slide persistence, builds, forks, and export
internal/library Shared image/video catalog types and manifest persistence
internal/oai OpenAI authentication and API calls
internal/video Video inspection, normalization, poster extraction, and registration
internal/s3 S3-compatible storage and request signing
internal/server HTTP routes, modes, auth, editing, exports, audience tools, sync, and workers
plugin Canonical agent skills and authoring conventions

The CLI and server adapters depend on domain packages. The neutral studio and library models do not depend on OpenAI, S3, Railway, or agent runtimes.

Development and contributing

Issues and focused pull requests are welcome. Preserve the file contract and public compatibility surfaces, keep credentials out of fixtures and logs, and add tests for behavior changes.

Build and run the standard checks:

make build
go test ./...
go test -race ./...
go vet ./...

The full contributor guide, package ownership map, and validation contract are in AGENTS.md. Tests use local fixtures and do not require live OpenAI, GitHub, Railway, Telnyx, Resend, or S3 credentials.

License

Apache License 2.0 © Vessica Labs

Hosted browser editor transport

Hosted services can run the existing player/HUD through vstd editor-session in an isolated disposable content sandbox. This additive gateway-authenticated transport provides canonical snapshots; the host remains responsible for tenant authorization and committing saved revisions. It does not change local vstd serve or read-only delivery.

When Cloud advertises workspace.sync.incremental, sync and pull transfer only changed file bytes. Unchanged assets use verified SHA-256 references to the exact base revision or captured local snapshot. Deletions and online edits still use the normal reconciliation rules; older servers retain full-snapshot sync. See the incremental sync protocol.

Native Cloud commands default to https://studio.vessica.ai. Set VSTD_CLOUD_ENDPOINT to use another service (including an existing connection created against a different endpoint). vstd cloud login prints the service's prefilled device approval link when available; approve the displayed code in your browser. Renewable credentials stay in the OS credential store.

For connected Cloud presentations, the plugin pulls only a clean local workspace before editing and syncs validated edits afterward, unless you requested local-only or no-sync work. Publishing remains a separate request.

Create a Cloud presentation from local files

With vstd 0.5.0 and a Cloud service advertising workspace.create, build and review a studio containing exactly one deck, then run:

vstd cloud login
vstd cloud workspace create --title "My presentation" --root ./my-presentation

The selected workspace from device approval owns the new presentation. The command uploads canonical files, creates the first revision, and connects the local directory for future pull and sync commands. It does not publish. An uncertain response leaves a non-secret .vstd/cloud-create.json retry journal; retry the same title and files, preserving the journal, to avoid duplicates. Local-only authoring continues to work without an account.

File-backed editor-transform requests with delta: true support the canonical 128 MiB snapshot budget (16 MiB per file, at most 2,000 files). Inline snapshot transforms retain their 20 MiB transport bound. Unchanged media is omitted from delta responses.

Hosted audience elements use data-vstd-audience-share on their container, data-vstd-audience-qr on an image, and data-vstd-audience-url on the URL text. Cloud supplies the destination rather than copying a standalone public_host. editor-transform accepts optional audience_url; release-build accepts --audience-url HTTPS_URL. An explicitly empty value disables those elements, while omission preserves standalone behavior. Hosted QR images are embedded PNGs, so immutable releases require no sharing API or third-party image service.

Display images without changing source files

vstd image-delivery --input original.png --output display.webp creates a new WebP using the same deterministic webp-v1-1920 recipe as optimized releases (maximum width 1920, no enlargement, quality 82, alpha preserved). It requires cwebp; PNG, JPEG, and WebP inputs are limited to 16 MiB and 40 million pixels. The output must not already exist. JSON stdout records sourceSha256, sha256, bytes, width, height, mediaType, and recipe. Hosted adapters may cache this disposable display copy while retaining original bytes and logical paths for editing. Authorization remains the host's responsibility.

In both editing and presentation mode, the player preloads all slide images, CSS backgrounds, and video posters after the visible slide's initial load. Background work uses two low-priority requests at a time and follows the current navigation position; visible images become eager/high priority immediately. Video streams retain their separate playback policy.

Hosted coordinators can read redesignRequests from the deck status endpoint. Each item contains an engine-owned slide ID and fingerprint of actionable companion requests. vstd agent --deck NAME --slide ID executes only that slide; it does not start other queued edits. Cloud dispatch and billing remain control-plane owned.

Hosted callers may add --image-api https://BROKER/v1 --image-model gpt-image-1 to a selected sweep. The engine processes at most one matching image request, registers its returned bytes in the normal library, and runs the landing pass. Placement receives the exact generated asset ID, URL, and hash from the engine. A sweep fails if the selected HTML still uses the previous image, only mentions the new URL in a comment, or leaves the placement request unresolved; clearing the companion alone cannot report successful image delivery. Each pass includes the selected companion's content checkpoint in its opening request. Planning and placement therefore have distinct request identities, while repeating the same file state retains a stable identity for host replay checks. The host supplies a scoped image capability through VSTD_OPENAI_KEY; no provider key is required inside an isolated guest. Other slides' requests stay queued, and failed generation is never retried inside the same sweep.

An ephemeral host job that already owns sandbox isolation and canonical result integration may add --isolated-workspace to its selected sweep. Both agent passes edit that job snapshot directly, avoiding redundant worktree/checkpoint copies of its image library. This requires --deck and --slide and disables Git push. Its worker is instructed to edit that isolated snapshot directly and leave worktree creation, further agent dispatch and Cloud intake to the host. Ordinary local sweeps keep their independent worktrees and recovery checkpoints. The flag provides no isolation itself; its caller must supply it.

Interactive simulation bundles use a bounded browser archive cache and a bounded cache of verified unpacked files. Returning to a simulator slide checks current asset access with HEAD and reuses prepared files; reloading the deck reuses the archive without another ZIP transfer. SHA-256 and inventory checks still apply. Cloud gateways can advertise 4 MiB archive parts; large bundles then download four parts concurrently, with each part independently cacheable by the CDN. The assembled archive must pass the same SHA-256 check. Other servers retain ordinary delivery. Storage denial falls back to ordinary downloads. Leaving the slide destroys the application frame, so inactive simulations stop using CPU/GPU. Existing published releases retain their loader; publish a new release with vstd 0.7.32 to upgrade.

Cloud voice and release consumption

The engine player supports an authenticated host returning a GPT-Live transport descriptor from POST /api/realtime/token. It then exchanges an ICE-complete SDP offer plus the selected presenter context and local tool definitions through POST /api/live/session. The host owns admission, model selection, provider credentials and usage accounting. Both presenter voice and silent dictation use Responses delegation; local Realtime sessions retain their existing protocol.

Hosted GPT-Live input transcripts open the speaker on the wake word independently of backend tool execution. The speaker starts muted, returns to mute on a stop-speaking request, and ignores assistant output transcripts for wake detection. Press V to start or stop Vessica's voice session; it starts listening silently. While connected, Shift+V toggles between conversation and silent listening, equivalent to saying “Vessica” and “that's all.” The spoken commands continue to work alongside the shortcut. In Logi Options+, configure the Spotlight 2 Action button's Single click → Keyboard shortcut → Shift+V. Keep the presenter player focused; voice shortcuts are ignored while typing in text fields. Shift+V does not start a microphone session when Vessica is off.

Wake and sleep control speech only: explicit navigation and highlighting commands execute while Vessica is connected, whether awake or silently listening.

Presenter voice reads the current page number and title from the player, using the same numbering as navigation (parked slides have no page number). It loads the selected slide's full companion Markdown and a presentation-wide table of contents with page numbers, titles, and topic summaries. Ask “what page are we on?”, “present this page”, or “go to the page about decision rights”. The agent reads fresh context before answering these questions or selecting a topic match; manual navigation, voice navigation, and companion saves refresh the context. Concurrent voice context reads wait for the latest selected-page refresh before updating the agent, preserving the companion during navigation and saved edits. GPT-Live receives a concise selection update as well as the backend context.

GET /api/deck/{deck}/voice-context?slide={id} returns current (page, title, summary, full companion) and pages (ID, page, title, summary, hidden/parked flags). It requires presenter access and is not cached. Hidden pages retain their numbers; parked pages use 0. Companions are loaded through this API, never embedded in exported presentation HTML. Exceptionally large context is marked explicitly in the initial prompt and remains available in full through the agent's get_presentation_context tool.

Playback is checked explicitly. If the browser blocks sound, click the Vessica status pill to enable audio without ending the session. Hosts embedding the presenter across origins must delegate autoplay alongside microphone permission.

A version bump merged to main publishes four immutable binaries and SHA256SUMS only after the engine security and compatibility workflow passes. Existing versions are never overwritten. Cloud consumes a released version and its exact revision/checksums through engine.lock.json; a Cloud pin update deploys through its own CI and GitHub-linked Railway services.

Hosted Live Responses lifecycle/function events are relayed through authenticated GET /api/live/events; context updates use POST /api/live/context. Browser audio continues directly over WebRTC. Cloud owns the backend model pin and billing.

Optional Vessica avatar overlay

Set LIVEAVATAR_API_KEY in the engine server environment to enable the optional LiveAvatar overlay. Keep this provider key out of studio.yaml, decks and built HTML. In the Presentation HUD, Avatar on/off selects video or voice-only mode. The switch defaults off and remembers your choice in this browser across presentations and sessions. Switching it off during conversation immediately stops the renderer and restores direct voice; switching it on starts the avatar if Vessica is already awake. If browser storage is unavailable, the selection lasts for the current page only. Embedded hosts can retain it on a stable app origin using vstd:avatar-preference messages with action: read (plus id) or action: write (plus boolean enabled). Read replies use vstd:avatar-preference-result, echo id, and include boolean enabled. Hosts must check the exact editor origin and frame source. The player checks parent source and the pending read ID, and ignores stale replies after a manual choice.

Voice-only mode uses the direct voice stream without loading the avatar SDK, creating an audio capture/worklet, allocating a provider session, or buffering audio for avatar synchronization. V starts Vessica silently listening; Shift+V and the Logitech Action button mapped to Shift+V wake/sleep conversation in either mode.

With Avatar on, no avatar session starts when a deck loads or while Vessica silently listens. Saying “Vessica”, pressing Shift+V, or the presenter conversation button starts a LITE session using Alessandra in Black Suit (portrait green-screen studio avatar). Sleep/“that's all”, voice shutdown and leaving the page stop the provider session and remove its video, audio and processing resources.

Video becomes visible as soon as the renderer video and control channel are ready, even if its audio track arrives later. The avatar appears without a background in the lower-right corner. The browser removes green pixels on a transparent canvas. Ordinary voice continues while the avatar connects; synchronized LiveAvatar audio takes over at a pause to avoid repeating speech. Missing configuration, blocked sound, SDK/network failure or session expiry falls back to ordinary voice. Wake again to start another avatar session. This optional feature loads the pinned livekit-client@2.22.4 browser module from jsDelivr only on wake; core presentation and voice operation do not require it.

The presenter-only, same-origin host contract is POST /api/avatar/start, POST /api/avatar/keepalive and POST /api/avatar/stop, with JSON { "id": "<browser-generated UUID>" }. Start returns ws_url, livekit_url and a scoped livekit_client_token; it never returns the provider API key or provider session token. Hosts must scope IDs to the authenticated presenter, cancel late starts, and explicitly stop the provider. A 15-second browser heartbeat refreshes a 45-second cleanup lease. Provider sessions have a 120-second hard cap, matching the existing LiveAvatar prototype; expiry returns to ordinary voice. Active, hidden or silent sessions still consume LiveAvatar credits (LITE: 1/minute). A host stop failure is retried; the lease and provider cap bound abnormal exits.

Cloud owns its authenticated gateway, provider credentials and admission. Its avatar adapter must be enabled separately and the released engine pinned before this becomes available in Cloud. Static exports and audience views cannot start sessions. No Cloud credential is installed in an editing sandbox.

Offline avatar checks: go test ./internal/avatar ./internal/server ./internal/studio. The optional browser acceptance fixture uses Playwright: VSTD_PLAYWRIGHT_MODULE=/absolute/path/to/node_modules/@playwright/test node internal/studio/testdata/avatar-browser.cjs. It generates its own green-screen media and checks transparent pixels, lower-right placement, audio forwarding, wake/sleep requests and teardown without consuming provider credits. It writes a test-figure screenshot to /tmp/vessica-liveavatar-qa.png. Run internal/studio/testdata/avatar-mode-browser.cjs with the same Playwright module to verify the full player HUD switch and persistence across page sessions. Real avatar edge quality, account access and end-to-end lip sync still require a provider trial.

AV handoff and private presenter controls

Vessica Studio Cloud can grant temporary, read-only AV access to one saved revision and keep the owner's phone controller separate. The public engine supports this through editor-transform with presentation_only: true: its identity is presenter/read-only and every write is rejected. Voice exposes only presentation tools, and attempted editing tools are refused before execution.

The shared player opts into the hosted controller transport only when its trusted /api/me response includes remote_control: true, a screen name, revision and show_expires_at. It reports actual slide, voice, microphone, playback and avatar state to POST /api/presenter/poll; commands use monotonic sequence numbers and receipts. Local operation remains offline-capable and does not use this transport. POST /api/presenter/end closes the screen. The host owns authentication, fixed revision storage, expiry, revocation, command admission and provider cleanup.

On the AV computer, use Enable show, allow microphone access, select the venue microphone, and check the system audio output. Fullscreen and audible playback remain subject to browser permission and local user gestures. Phone controls do not capture a microphone or play presentation audio. Rehearse voice, avatar, screen selection and venue routing before the show. A normal HID clicker continues to navigate with Page Up/Page Down.

Directories

Path Synopsis
cmd
vstd command
vstd — the Vessica Studio engine.
vstd — the Vessica Studio engine.
internal
avatar
Package avatar manages optional LiveAvatar renderers.
Package avatar manages optional LiveAvatar renderers.
bundle
Package bundle validates and registers bounded, immutable application ZIPs.
Package bundle validates and registers bounded, immutable application ZIPs.
catalog
Package catalog owns personal presentation organization that is independent of deck ownership and sharing permissions.
Package catalog owns personal presentation organization that is independent of deck ownership and sharing permissions.
chart
Package chart contains chart-authoring migrations that operate on the Studio file contract without introducing a charting runtime dependency.
Package chart contains chart-authoring migrations that operate on the Studio file contract without introducing a charting runtime dependency.
chromium
Package chromium resolves the optional browser binary used by visual exports, source critics, and chart migration tools.
Package chromium resolves the optional browser binary used by visual exports, source critics, and chart migration tools.
cloud
Package cloud implements the public, versioned Vessica Studio Cloud HTTP boundary.
Package cloud implements the public, versioned Vessica Studio Cloud HTTP boundary.
cloudauth
Package cloudauth manages native cloud sessions without exposing renewable credentials to callers or persisting short-lived access tokens.
Package cloudauth manages native cloud sessions without exposing renewable credentials to callers or persisting short-lived access tokens.
cloudpublish
Package cloudpublish selects synchronized revisions and orchestrates publication through the versioned cloud boundary.
Package cloudpublish selects synchronized revisions and orchestrates publication through the versioned cloud boundary.
library
Package library owns the shared image and video asset catalog stored in a studio root's library/manifest.json.
Package library owns the shared image and video asset catalog stored in a studio root's library/manifest.json.
oai
Package oai wraps the OpenAI HTTP APIs the engine needs: image generation (gpt-image-2) for the visual library, and ephemeral client-secret minting for gpt-realtime-2 presentation sessions.
Package oai wraps the OpenAI HTTP APIs the engine needs: image generation (gpt-image-2) for the visual library, and ephemeral client-secret minting for gpt-realtime-2 presentation sessions.
reconcile
Package reconcile owns three-way presentation reconciliation for every writer.
Package reconcile owns three-way presentation reconciliation for every writer.
s3
Package s3 is a minimal S3-compatible client for the video pipeline: PUT/HEAD objects (library sync) and presigned GET URLs (hosted serving).
Package s3 is a minimal S3-compatible client for the video pipeline: PUT/HEAD objects (library sync) and presigned GET URLs (hosted serving).
server
Agent worker: executes queued redesign requests by running a headless coding-agent session inside the studio root.
Agent worker: executes queued redesign requests by running a headless coding-agent session inside the studio root.
studio
Package studio implements the Vessica Studio content model: a root folder containing themes/, library/, requests/ and decks/, where each deck is a directory of slide fragments (NNNN-slug.html) paired with companion markdown files (NNNN-slug.md) carrying the research, evidence and talk track behind the slide.
Package studio implements the Vessica Studio content model: a root folder containing themes/, library/, requests/ and decks/, where each deck is a directory of slide fragments (NNNN-slug.html) paired with companion markdown files (NNNN-slug.md) carrying the research, evidence and talk track behind the slide.
video
Package video implements the video asset pipeline: ingest (normalize with ffmpeg when available, extract a poster frame, probe metadata), the library manifest entries, and content-addressed storage under library/video/.
Package video implements the video asset pipeline: ingest (normalize with ffmpeg when available, extract a poster frame, probe metadata), the library manifest entries, and content-addressed storage under library/video/.
Package plugin embeds the agent skill definitions so the vstd binary can serve them to any agent runtime (`vstd skill <name>`).
Package plugin embeds the agent skill definitions so the vstd binary can serve them to any agent runtime (`vstd skill <name>`).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL