This guide is for people who want to change Deejay without first reverse-engineering the whole hackathon build.
server/
index.js HTTP API, Spotify, OpenAI resolver, queueing, local request log
spacebase.js Spacebase1 resolver identity, DPoP, ITP framing, scan/post
public/
index.html attendee surface
attendee.js human intent -> promise -> accept/revise -> complete flow
host.html host surface
host.js ready check, QR, pause, test queue, recent requests
styles.css shared UI styles
spacebase-client.js browser-side Spacebase1 client
deejay-agent-client.mjs standalone clean-room agent helper
agent-instructions.md static agent guide
scripts/
doctor.js
deejay-watchdog.sh
data/
.gitkeep runtime files are created here and ignored by Git
Human-led request:
- Browser signs up to Spacebase1 commons with a local DPoP key.
- Browser posts a top-level commons
INTENTaddressed to Deejay. - Server watcher sees the intent, resolves the song, searches Spotify, and posts a
PROMISE. - Browser shows the promised track.
- User approves or rejects/revises.
- On approval, server queues the Spotify track and posts
COMPLETE.
Agent-led request:
- Agent reads
/agent-setup. - Agent signs up to Spacebase1 commons.
- Agent posts one song
INTENT. - Agent scans the request subspace.
- Agent accepts a plausible Deejay
PROMISE. - Agent waits for
COMPLETE.
Fast-path agent command:
curl -sS http://127.0.0.1:5177/deejay-agent-client.mjs -o /tmp/deejay-agent-client.mjs
node /tmp/deejay-agent-client.mjs "that sabrina espresso song"- Spotify queueing is the primary actuator. Do not add mouse/keyboard Spotify automation unless the API path is deliberately being replaced.
- The human UI should remain step-by-step. The point is to demonstrate the verbs, not hide them.
- The agent doorway should stay concise and runnable by agents without local repo access.
- Do not add attendee accounts, moderation, voting, or heavy duplicate logic in v1.
- Do not queue before an
ACCEPT. - Keep runtime state local under
data/.
server/index.js is intentionally broad but the responsibilities are grouped:
- Express routes and static surfaces.
- Request creation and local log persistence.
- AI interpretation and Spotify search/selection.
- Spotify auth, status, queueing, and playlist logging.
- Spacebase watcher and recovery.
- Rendered agent docs.
If this grows, the first useful split is:
server/spotify.jsserver/resolver.jsserver/requests.jsserver/agent-docs.js
Avoid splitting just to make the file count look nicer. Split when a change is hard to reason about.
Spacebase1 uses framed ITP messages, not ordinary JSON REST calls. The mechanics live in two places:
server/spacebase.jsfor the resolver-agent.public/spacebase-client.jsfor attendee browsers.
DPoP proofs are single-use. Generate a fresh proof for each signup, continue, scan, and post request. Reusing a proof can trigger replay errors.
Song request subspaces use the song intentId as the space id.
Required scopes:
user-read-playback-stateuser-modify-playback-stateplaylist-modify-privateplaylist-modify-public
The queue call is followed by a short queue verification loop. If the track does not appear quickly, Deejay retries a small number of times. Spotify's queue UI can lag or hide upcoming tracks, so the app treats API verification as the source of truth.
If OPENAI_API_KEY is missing, Deejay falls back to a simpler resolver. That keeps local Spotify testing possible without AI, but the hackathon demo is better with the AI resolver enabled.
The resolver should prefer popular canonical tracks when requests are vague. Keep failures graceful: fail only when Spotify returns no plausible results or the selected result is clearly unrelated.
Run:
npm run doctor
npm run checkManual smoke test:
- Start
npm run dev. - Open
/host. - Connect Spotify.
- Make this computer the active Spotify device.
- Open
/. - Submit
that sabrina espresso song. - Approve the promise.
- Confirm the UI reaches
COMPLETE.
Agent smoke test:
curl -sS http://127.0.0.1:5177/deejay-agent-client.mjs -o /tmp/deejay-agent-client.mjs
node /tmp/deejay-agent-client.mjs "King Kunta by Kendrick Lamar"Before pushing to GitHub:
.envis ignored and not committed.data/only contributesdata/.gitkeep.node_modules/is ignored.npm run checkpasses.npm run doctordoes not show unexpected failures.- README examples use placeholders, not event-specific domains or personal paths.
- Temporary Cloudflare/ngrok config is not committed.