Sleeper Hit Studio

CLI

Install, configure, and automate Sleeper Hit Studio from a terminal.

@sleeperhit/cli

Command-line client for the Sleeper Hit Studio B2B Story API (/api/v1). It maps 1:1 onto the documented endpoints — create projects, attach sources, generate and approve a StoryPlan, run a job, watch it to completion, and open the live table-read theater.

The endpoints, auth, error envelope, and flow mirror docs/agents/ (README, quickstart, concepts, api-reference). Nothing here contradicts those docs — the CLI is a thin, scriptable wrapper around the same HTTP surface.

Requirements

  • Node.js >= 20 (uses the built-in global fetch and node:crypto.randomUUID).
  • A Sleeper Hit Studio customer API key. Create one at https://sleeperhit.studio/dashboard/api.
  • Recommended scopes for the full flow: story:read, story:write, source:write, credits:read, artifact:read.

Install

From the monorepo root (the package lives at packages/cli and is picked up by the existing packages/* workspace glob):

pnpm install pnpm --filter @sleeperhit/cli build # compiles src -> dist
cd packages/cli pnpm link --global # now `sleeperhit` is on your PATH sleeperhit --help

Run without building (dev)

# from packages/cli pnpm dev -- projects list # or directly with a TS-aware runner: pnpm exec tsx src/index.ts projects list

Configuration

Env varRequiredDefaultPurpose
SLEEPERHIT_API_KEYyesBearer key, sh_<prefix>_<secret>. Sent as Authorization: Bearer <key>.
SLEEPERHIT_BASE_URLnohttps://sleeperhit.studioOrigin to target. /api/v1 is appended automatically. Point at https://stage.sleeperhit.studio or a local dev origin when testing.
export SLEEPERHIT_API_KEY="sh_xxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # optional export SLEEPERHIT_BASE_URL="https://sleeperhit.studio"

The CLI auto-generates an Idempotency-Key (UUID) for every POST. Override it with --idempotency-key <key> when you want a stable key tied to your own job record for safe retries.

Errors are printed in the standard { error: { code, message, requestId } } form. On rate_limited the exact Retry-After is surfaced; jobs watch honors it automatically. The CLI exits non-zero on any error (1 API/runtime, 64 usage, 2 for a planned endpoint that is not deployed yet).

Commands

capabilities                          Live capability manifest
credits                               Studio Credit balance

projects create --name <name> [--description <text>] [--metadata <json>]
projects list [--limit N] [--cursor C]
projects get <projectId>

sources add <projectId> --type text|markdown|url|pdf
        [--content <text> | --file <path>]   (text / markdown)
        [--uri <http(s) url>]                (url / pdf)
        [--label <text>] [--retention EXTRACTED_ONLY|STORE_ORIGINAL|METADATA_ONLY]
sources list <projectId> [--limit N] [--cursor C]
sources get <projectId> <sourceId>

plans create <projectId>
        --target audience=...,objective=...,outcome=...   (repeatable)
        --artifact type=table_read,mode=podcast|documentary|drama[,narrationPolicy=auto|include|suppress][,durationSeconds=N]   (repeatable)
        [--source <sourceId> ...] [--title <text>] [--auto-approve]
        [--json '<full payload>']    power-user escape hatch
plans get <planId>
plans approve <planId>
plans reject <planId> [--reason <text>]

jobs create <planId> [--project <projectId>] [--artifact type=...,mode=...]
jobs list [--project <id>] [--plan <id>] [--limit N] [--cursor C]
jobs get <jobId>
jobs watch <jobId> [--interval <ms>]   Poll (~5s) until terminal; print theater/audio/video URLs on READY
jobs cancel <jobId>

artifacts get <artifactId>
artifacts render-video <artifactId>    Opt-in MP4 render (separate Studio Credit charge)

music generate <artifactId> [--coverage <0..1|0..100>]   Generate adaptive music in place
music update <artifactId> --scene <n> [--prompt <text>] [--summary <text>]
        [--weight <0..2>] [--mute | --enable]             Tune or mute one scene
music get <artifactId>
music watch <artifactId> [--interval <ms>]

refine <artifactId> <instruction...>   Planned endpoint — wired forward-compatibly
finalize <artifactId>                  Planned endpoint — wired forward-compatibly

Run sleeperhit --help for the same reference at the terminal.

Planned (forward-compatible) commands

refine and finalize are documented in docs/agents/concepts.md as coming soon. They are wired against POST /api/v1/artifacts/{artifactId}/refine and POST /api/v1/artifacts/{artifactId}/finalize. Until those ship, the commands detect a 404/405/501 and print a clear "coming soon" note describing the current workaround (refine → create a new plan; finalize → approve + job + render-video) and exit with code 2.

End-to-end example

Copy-pasteable. Replace the captured IDs as you go (or pipe through jq).

export SLEEPERHIT_API_KEY="sh_..." # 1. Confirm the table read is available and you have credits sleeperhit capabilities | jq '.artifacts.table_read.availability' sleeperhit credits | jq '.credits.balance' # 2. Create a project PROJECT_ID=$(sleeperhit projects create --name "Q3 Launch Story" \ --description "Product launch table read" | jq -r '.project.id') # 3. Attach an inline text source (instant READY) SOURCE_ID=$(sleeperhit sources add "$PROJECT_ID" \ --type text --label press-release \ --content "Acme Corp launches its next-gen platform in Q3 2026, cutting onboarding time 60%." \ | jq -r '.source.id') # 4. Generate the plan and auto-approve it (skips the human hold) PLAN_ID=$(sleeperhit plans create "$PROJECT_ID" \ --target audience="enterprise buyers" \ --target objective="introduce the Q3 platform launch" \ --target outcome="book a demo within 7 days" \ --target tone="confident, specific" \ --artifact type=table_read,mode=documentary \ --source "$SOURCE_ID" \ --auto-approve | jq -r '.plan.id') # 5. Poll the plan until APPROVED (auto-approve usually lands here directly) sleeperhit plans get "$PLAN_ID" | jq '{status:.plan.status, total:.plan.quote.total}' # 6. Create the job (reserves credits) and watch it to completion JOB_ID=$(sleeperhit jobs create "$PLAN_ID" | jq -r '.job.id') sleeperhit jobs watch "$JOB_ID" # On READY, watch prints: # Theater: https://sleeperhit.studio/share/table-read/<token> # Theater (full): https://sleeperhit.studio/share/table-read/<token>?view=fullscreen # Audio (live): https://sleeperhit.studio/share/table-read-audio/<token> # Video render URL: /api/v1/artifacts/<artifactId>/render-video # 7. (Optional) opt into a durable MP4 ARTIFACT_ID=$(sleeperhit jobs get "$JOB_ID" \ | jq -r '.job.artifacts[] | select(.type=="table_read") | .id') sleeperhit artifacts render-video "$ARTIFACT_ID"

The shareToken baked into the theater/audio URLs authorizes them — not your API key — so you can hand those URLs directly to end users.

Use it in your own agent workflow

The CLI emits JSON on stdout and human progress on stderr, so it composes cleanly inside scripts or an agent's tool layer:

#!/usr/bin/env bash set -euo pipefail export SLEEPERHIT_API_KEY="${SLEEPERHIT_API_KEY:?set your key}" ARTICLE_URL="$1" PROJECT_ID=$(sleeperhit projects create --name "Agent run $(date +%s)" | jq -r '.project.id') # Async URL source — poll to READY before planning SOURCE_ID=$(sleeperhit sources add "$PROJECT_ID" --type url --uri "$ARTICLE_URL" | jq -r '.source.id') until [ "$(sleeperhit sources get "$PROJECT_ID" "$SOURCE_ID" | jq -r '.source.status')" = "READY" ]; do sleep 3 done PLAN_ID=$(sleeperhit plans create "$PROJECT_ID" \ --target audience="general" --target objective="summarize the article" --target outcome="share a 90s table read" \ --artifact type=table_read,mode=podcast,narrationPolicy=include,durationSeconds=90 \ --source "$SOURCE_ID" --auto-approve | jq -r '.plan.id') # wait for the async planner until [ "$(sleeperhit plans get "$PLAN_ID" | jq -r '.plan.status')" = "APPROVED" ]; do sleep 4; done JOB_ID=$(sleeperhit jobs create "$PLAN_ID" | jq -r '.job.id') sleeperhit jobs watch "$JOB_ID" # blocks, streams progress, prints share URLs on READY

For a power-user payload that exactly matches the API schema, bypass the flag helpers with --json:

sleeperhit plans create "$PROJECT_ID" --auto-approve --json '{ "title": "Launch narrative", "target": { "audience": "enterprise buyers", "objective": "introduce the launch", "outcome": "book a demo" }, "artifactRequests": [{ "type": "table_read", "mode": "drama", "narrationPolicy": "suppress", "durationSeconds": 120 }], "styleConstraints": { "voicePreference": "authoritative, not salesy" }, "sourceIds": ["'"$SOURCE_ID"'"] }'

See also