Files
firehose/.pi/skills/demo/SKILL.md
T
Willem van den Ende a0692056bc demo skill: read the dev port from config; make deps installs JS packages
The skill assumed port 4000, but config/dev.exs serves on 8056 (and honours
$PORT), so a fresh demo run failed its liveness check and every rodney URL
pointed at the wrong port.

- demo skill: resolve DEMO_PORT from the app config with
  `mix run --no-start -e 'Application.get_env(:firehose,
  FirehoseWeb.Endpoint)[:http][:port]'` (Endpoint.config/1 raises without a
  started endpoint), derive $DEMO_BASE_URL from it, start the server on that
  port from app/, and use $DEMO_BASE_URL in every rodney example. The skill
  also points at .tmp/phx-demo.log and names the assets/node_modules
  highlight.js failure as a diagnosable cause.
- app/Makefile: new `assets` target that runs `npm install` only when
  node_modules/.package-lock.json is missing, and `deps` now depends on it.
  A fresh clone gets a working JS bundle from `make deps`/`make test`; later
  runs never touch the network, so offline runs keep working.

Verified: guard skips with node_modules present and installs after moving it
aside; the skill's DEMO_PORT command prints 8056 and follows PORT=9999;
make check and make test (179 + 162) green.
2026-10-26 21:08:00 +00:00

8.0 KiB

name, description, allowed-tools
name description allowed-tools
demo Generate a living demo document proving a feature works. Uses showboat for Markdown assembly with captured command output and rodney for Chrome browser screenshots. Use when the user says "demo this", "show me it works", "create a demo", or after /build completes. Read Write Glob Grep Bash

Demo Skill

Role: worker. This command generates a standalone Markdown demo document that proves a feature works, using showboat for document assembly and rodney for browser automation.

You have been invoked with the /demo command. Parse Arguments

Arguments: $ARGUMENTS

Positional: <feature-name> (required) - short name or description of the feature to demo
--scenario <description>: Explicit demo scenario describing what to show. If omitted, infer from the plan and recent commits.
--plan <path>: Path to the plan file. If omitted, search plans/ for the most recently modified .md file with status implemented or approved.

Steps

  1. Check tool availability

Verify showboat and rodney are installed:

showboat --help 2>/dev/null && echo "showboat: ok" || echo "showboat: missing" rodney --help 2>/dev/null && echo "rodney: ok" || echo "rodney: missing"

If either tool is missing, tell the user:

One or more demo tools are missing. Install them with:

go install github.com/simonw/showboat@latest
go install github.com/simonw/rodney@latest

Do not proceed until both tools are confirmed available. 2. Gather feature context

Build an understanding of what to demo from these sources (in priority order):

Explicit scenario (--scenario): If provided, use as primary guide.
Plan file: Read the plan's Goal, Acceptance Criteria, and completed Steps.
Recent commits: Run git log --oneline -15 and git diff main...HEAD --stat to identify changed files and commit messages.
Route map: Cross-reference changed files against known LiveView routes in the router (lib/hub_web/router.ex).

From these sources, produce a demo outline:

Narrative: 2-3 sentence description of what the feature does
Backend evidence: mix commands, test output, or database queries to run
UI pages: which routes to visit and what to look for
Interactions: any clicks, form fills, or navigation sequences to perform

If no plan exists and commits are ambiguous, ask the user for a brief description of what to demo. 3. Resolve the dev port, then check the server

Never assume a port. The port lives in the project config: app/config/dev.exs sets port: String.to_integer(System.get_env("PORT") || "8056"), so $PORT wins and the config default is the fallback. Ask the app, from the repo root:

DEMO_PORT=$(cd app && mise exec -- mix run --no-start -e \
  'IO.puts(Application.get_env(:firehose, FirehoseWeb.Endpoint)[:http][:port])')
DEMO_BASE_URL="http://localhost:${DEMO_PORT}"

curl -s -o /dev/null -w "%{http_code}" "$DEMO_BASE_URL/"

Use Application.get_env/2, not FirehoseWeb.Endpoint.config(:http): with --no-start the endpoint's ETS table does not exist and config/1 raises.

If the server is not reachable:

The Phoenix dev server is not running. Start it now?

mkdir -p .tmp && (cd app && PORT=$DEMO_PORT mise exec -- mix phx.server \
  > ../.tmp/phx-demo.log 2>&1 &)

Then poll $DEMO_BASE_URL for up to 10 seconds. If it still fails, read .tmp/phx-demo.log: a bundle error about highlight.js (or any module) means app/assets/node_modules is missing - run make -C app assets (root make deps does it too). Only when the server really cannot come up, proceed with backend-only evidence (skip all browser screenshots) and note the limitation in the demo document.

Use $DEMO_BASE_URL for every URL below - there is no default port to fall back on. 4. Handle authentication

The app requires authentication for LiveView routes. Before capturing UI screenshots:

Ensure a demo user exists:

mix run -e "
  alias Hub.Accounts
  case Accounts.get_user_by_email(\"demo@example.com\") do
    nil -> Accounts.register_user(%{email: \"demo@example.com\", password: \"demodemo1234\"})
    user -> {:ok, user}
  end
"

Log in via rodney:

rodney start
rodney open "$DEMO_BASE_URL/users/log-in"
rodney wait "input[name='user[email]']"
rodney input "input[name='user[email]']" "demo@example.com"
rodney input "input[name='user[password]']" "demodemo1234"
rodney click "button[type='submit']"
rodney waitidle

If login fails, warn and proceed with backend-only evidence. 5. Initialize the demo document

Slugify the feature name (lowercase, hyphens, no special chars). Then:

showboat init "demos/demo-$(date +%Y%m%d-%H%M%S)-.md" "Demo: "

Store the demo file path for use in all subsequent steps. 6. Narrative introduction

showboat note "## Feature Overview

<2-3 sentence description derived from the plan or commits.>

Branch: $(git branch --show-current) Commits: commits ahead of main Plan: <plan file path or 'none'> "

  1. Backend evidence

Capture backend proof via showboat exec. Always include relevant tests. Add narrative notes between evidence blocks explaining what each proves.

Test output (always include):

showboat note "## Test Suite" showboat exec bash "mix test --color" showboat note "All tests pass, confirming ."

Compilation check:

showboat note "## Compilation Check" showboat exec bash "mix compile --warnings-as-errors"

Database state (if relevant to the feature):

showboat note "## Database State" showboat exec bash "mix run -e ''"

  1. UI screenshots

For each UI page identified in step 2, navigate with rodney, screenshot, and embed via showboat.

Static page capture:

rodney open "$DEMO_BASE_URL/" rodney waitidle rodney screenshot demos/screenshots/-.png

showboat note "###

"

showboat image ''

Interactive flow (form submissions, navigation):

showboat note "### Interactive Flow: "

Before state

rodney screenshot demos/screenshots/-before.png showboat image 'Before: '

Perform interaction

rodney click "" rodney input "" "" rodney click "" rodney waitidle

After state

rodney screenshot demos/screenshots/-after.png showboat image 'After: '

  1. Acceptance criteria checklist

If a plan file exists, map each acceptance criterion to evidence:

showboat note "## Acceptance Criteria Verification

  • <Criterion 1> -- see Test Suite output above
  • <Criterion 2> -- see screenshot
  • <Criterion 3> -- see Database State output "

If no plan, summarize what was demonstrated and what it proves. 10. Clean up

rodney stop 2>/dev/null || true

  1. Report results

Display:

Demo Complete

  • Document: demos/.md
  • Screenshots: captured in demos/screenshots/
  • Evidence: backend commands, UI screenshots
  • Acceptance criteria: / demonstrated

Error Handling

Tools not installed: Show go install commands. Do not proceed without them.
Dev server not running: Offer to start. If startup fails, produce backend-only demo and note the limitation.
Authentication failure: Proceed with backend-only evidence. Note skipped UI screenshots in the document.
Screenshot failure: Log the error as a note in the demo document, continue with remaining screenshots.
No plan found: Infer from git commits and changed files. Ask the user for a description if commits are ambiguous.
Rodney/Chrome crash: Run rodney stop then rodney start to reset. Retry once. If it fails again, degrade to backend-only.