Configuration

A key is only needed for what the agent cannot do itself.

The walk is driven by an agent, and an agent is already a model. It writes the persona bios, the step descriptions and the findings with no API key at all — asking a second model to do that would be paying twice for the same sentence. The gaps are the things a coding agent genuinely cannot produce from a tool call: a PNG of a face, and an MP3 of a voice. Those, and only those, are what a provider is for. An agent that CAN produce them — a host with native image generation — should produce them and skip the key entirely. When a key is needed it is one key, OPENAI_API_KEY, covering both.

It depends who is driving

The walk is run by an agent, and agents differ in exactly one way that matters here: whether they can hand back an image file. That single difference decides whether this repo needs an image provider at all.

HostMakes images?Detected bySo
Claude Code NoCLAUDECODE

Set to 1 for every child process Claude Code spawns, so a script started by the agent sees it. Verified in this environment.

Needs an image provider for persona art and a TTS provider for narration. Everything else runs with no key.
Codex Ask itCODEX_SANDBOX

Codex sets CODEX_SANDBOX (and CODEX_SANDBOX_NETWORK_DISABLED) for sandboxed child processes — confirmed by inspecting the shipped binary. It is NOT set when Codex runs with the sandbox bypassed, so absence proves nothing; use WALKTHROUGH_IMAGE_PROVIDER to state it outright.

If the host can produce an image file itself, it should write the plate directly and no image provider is needed.
A shell, CI, or an agent that sets no marker Nonothing

No marker found. Nothing is assumed about what the caller can do.

Treated as a plain shell: capabilities come from configured providers only.

Detection is a hint and never a claim: a host that sets no marker is not assumed to lack a capability, and one that sets a marker can still be wrong about itself. Say it outright to settle it — WALKTHROUGH_IMAGE_PROVIDER=host to make the agent draw the plates, =api to force the provider, or =none to opt out of generated art entirely, after which its absence stops being reported as a gap.

Checking your own machine

This is the published hub. It holds no credentials and needs none — it reads committed artifacts and renders them, and never calls a model. So there is nothing here to report on, and a page that claimed otherwise would be reporting on someone else’s laptop.

Run it against your own checkout to see live status, including a button that verifies each key against the real endpoint:

pnpm run doctor    # the same report, in the terminal
pnpm dev           # then open /setup

Every capability, and its fallback

One of these is required. The rest degrade — and degrading means the page says what is missing, never that it quietly publishes something weaker and lets you assume it is complete.

Capture

Required

Driving the app and photographing it. This is the walk.

Satisfied by

  • Playwright ChromiumLocal tool

    The default. The only backend that does video and a pinned clock.

    npx playwright install chromium

  • A Chrome on port 9222Local tool

    The way past an SSO or MFA gate: it reuses a browser a human already signed into.

  • iOS SimulatorLocal tool

    Real MobileSafari. The only backend where lvh − svh is the actual URL-bar height.

  • Android platform-toolsLocal tool

    adb screencap and screenrecord against an emulator or a tethered device.

Without it

Nothing can be walked. This is the only hard requirement.

Writing

Optional

Persona bios, step descriptions, captions, findings, the narration script.

No key needed — the agent running the walk already does this.

Satisfied by

  • The agent running the walkNo key — the agent does it

    Always available, by definition. This is why the system asks for no key to produce prose.

  • OpenAI text modelNeeds a key

    Only for the unattended scripts that run with no agent in the loop. Override the model with OPENAI_TEXT_MODEL.

    OPENAI_API_KEY

Without it

Nothing degrades when no key is set — the agent writes it.

the skill, inline · pnpm persona:story (script only)

Generated illustration

Optional

Persona portraits, scene-setters, moment shots and the shared stipple plates. All invented, all labelled 'illustration' in the UI, none of it evidence.

Satisfied by

  • The agent running the walkNo key — the agent does it

    A host that can generate an image writes the plate directly to public/walkthroughs/<slug>/personas/ and no provider is configured at all.

  • OpenAI image modelNeeds a key

    One key, one endpoint. The default model is checked against /v1/models rather than remembered — ids move, and a stale one fails only at generation time. Override with OPENAI_IMAGE_MODEL.

    OPENAI_API_KEY

Without it

A persona card renders as a typographic panel carrying the two facts that actually identify one — where they enter the product, and how many of their journeys have been walked — and the journey masthead simply omits the portrait. Every page still works, and none of them claims a face that was never drawn.

pnpm persona:art · pnpm persona:moments · pnpm creatives

Narration

Optional

The spoken track on a persona story video.

Satisfied by

  • OpenAI gpt-4o-mini-ttsNeeds a key

    Chosen automatically the moment OPENAI_API_KEY is present. The same key as illustration — there is only one.

    OPENAI_API_KEY

  • Local Kokoro modelLocal tool

    Weights download on first use to ~/.cache/walkthrough-studio. No key, no account. The ffmpeg on PATH must also have been built with text rendering — Homebrew ships builds without libfreetype, and the story renderer burns its caption into the frame.

    needs uv, ffmpeg on PATH

Without it

The story video is not rendered. The journey page it summarises is unaffected, and the walk's own screen recording is still attached to it.

pnpm persona:story · pnpm tts:sample

Target-app credentials

Optional

Reaching gated features in the app being walked.

Satisfied by

  • A $VAR placeholder in projects.jsonNeeds a key

    projects.json is committed, so it names the variable and .env.local holds the value.

Without it

The gated feature is recorded as pending with the reason, and a finding is filed. It is never unblocked by editing the app.

any walk against an app with an auth gate

Credentials the registry asks for

projects.json is committed, so it names a variable and never holds a value. A missing one does not stop a walk: the gated feature is recorded as pending with the reason, and a finding is filed. It is never unblocked by editing the app being walked.

  • ADMIN_PASSWORDopenstageadmin

    Unset in the local environment; see issues.json — the middleware gate fails open when it is missing.

Where a key is, and is not

  • A key lives in .env.local on the machine that runs the walk. That file is gitignored and is the only place a value exists.
  • The hub never calls a model. Nothing it serves needs a credential, in development or in production.
  • No key is ever sent to the browser. This page renders variable names and states; the values stay in the process that reads them.
  • No command in this repo prints a key — not a prefix, not a length. A fingerprint of a key is still a fact about a key, and this output gets pasted into issues.
  • projects.json names variables with a $VAR placeholder because it is committed. A literal password in it is the one configuration mistake that cannot be undone by rotating a file.

Installing the skill on your own app: use it on your own app.