Verified agent setup
- Open DJCLIPZ in normal Chrome.
- Complete the existing email and consent flow.
- Attach a browser-capable agent to that same Chrome tab.
- The human clicks Start Agent Performance.
- Choose either visible UI control or direct controller access according to the agent's verified browser capabilities.
- The human retains Pause, Resume, Take Over, and Stop Performance.
Verified for Controller v1.1.0: Normal Chrome with the ChatGPT/Codex browser extension attached to the active DJCLIPZ tab.
Not supported in this release: For Controller v1.1.0, the separate Codex in-app browser is not a supported DJCLIPZ playback runtime. This is a measured release result, not a permanent claim about future runtimes. See the official OpenAI browser-extension documentation for the distinction between an attached browser profile and the separate built-in browser.
Two distinct control modes
Mode A — Visible UI control
A browser agent operates only the rendered DJCLIPZ interface. Page-owned JavaScript access is not required.
- Wait for the human to select Start Agent Performance.
- Continue only while the visible Agent Performance status reads active.
- Stop immediately when the visible status changes to agent paused, human takeover, stopped, or inactive, or when the page reloads.
Mode B — Direct controller access
A browser agent with verified access to page-owned JavaScript uses window.DJCLIPZ.controller. Page-owned JavaScript access is required and must be verified before use.
- Confirm window.DJCLIPZ.controller exists and inspect its version and capabilities.
- Continue only while controller.session.getState().state is active.
- Check every command result before reading its value or issuing a dependent command.
- Stop immediately on agent-paused, human-takeover, stopped, inactive, terminal authority errors, or reload.
Current compatibility
- Controller
- 1.1.0
- Status
- CURRENT — EXPERIMENTAL, HUMAN-AUTHORIZED
- Verified
- August 27, 2026
- Supported transport
- Browser-local, same active tab
- Human authorization
- Required
- Remote command service
- No
- MCP
- No
- A2A
- No
Direct-controller authority and entrypoint
A human must enter through the current email and consent flow and select Start Agent Performance. No public start method exists. The human retains Pause, Resume, Take Over, and Stop Performance; those controls suspend, restore, revoke, or end delegated authority immediately.
const controller = window.DJCLIPZ.controller;
controller.version; // "1.1.0"
controller.session.getState();
Authority and the controller queue are page-session state. Reload creates a fresh inactive controller with an empty queue.
Human Stop Performance: The visible Stop Performance control remains available to the human whenever the session can be stopped and immediately revokes delegated authority.
Agent session.stop(): While delegated authority is active, an authorized agent may call controller.session.stop() to terminate its own performance. The method cannot activate or resume a session and rejects after Pause, Take Over, Stop, or reload.
This interface controls only the current page. Server-assisted media search is not a remote mixer-command API. Remote control, MCP, and A2A support are all unsupported.
Public methods
Root methods
| Method | Result |
|---|---|
getState() | ControllerState |
session methods
| Method | Result |
|---|---|
session.getState() | SessionState |
session.stop() | CommandResult<{ state }> |
media methods
| Method | Result |
|---|---|
await media.search({ query, maxResults? }) | Promise<CommandResult<{ results, cached }>> |
media.inspect(platformMediaIdOrObject) | CommandResult<ValidatedMedia> |
await media.validate(platformMediaIdOrObject) | Promise<CommandResult<ValidatedMedia>> |
queue methods
| Method | Result |
|---|---|
queue.list() | QueueItem[] |
queue.add(platformMediaIdOrObject, { allowDuplicate? }?) | CommandResult<QueueItem> |
queue.remove(queueItemId) | CommandResult<{ queueItemId }> |
queue.replace(queueItemId, platformMediaIdOrObject) | CommandResult<QueueItem> |
queue.move(queueItemId, zeroBasedIndex) | CommandResult<QueueItem> |
queue.clear() | CommandResult<[]> |
queue.setNext(queueItemId) | CommandResult<QueueItem> |
deck methods
| Method | Result |
|---|---|
await deck.load("a" | "b", queueItemId, settings?) | Promise<CommandResult<DeckState>> |
await deck.play("a" | "b") | Promise<CommandResult<DeckState>> |
await deck.pause("a" | "b") | Promise<CommandResult<DeckState>> |
await deck.stop("a" | "b") | Promise<CommandResult<DeckState>> |
deck.seek("a" | "b", seconds) | CommandResult<DeckState> |
deck.getState("a" | "b") | DeckState | RejectedCommandResult |
deck.setVolume("a" | "b", 0..100) | CommandResult<DeckState> |
deck.setPlaybackRate("a" | "b", 0.25 | 0.5 | 1 | 1.5 | 2) | CommandResult<DeckState> |
deck.setCue("a" | "b", cueId, time?) | CommandResult<Cue> |
deck.getCues("a" | "b") | Cue[] | RejectedCommandResult |
deck.triggerCue("a" | "b", cueId) | CommandResult<Cue> |
deck.clearCue("a" | "b", cueId) | CommandResult<{ cueId }> |
deck.clearCues("a" | "b") | CommandResult<[]> |
deck.setBpm("a" | "b", bpm) | CommandResult<BeatGridState> |
deck.setDownbeat("a" | "b", mediaTimeSeconds) | CommandResult<BeatGridState> |
deck.nudgeBeatGrid("a" | "b", -1 | 1) | CommandResult<BeatGridState> |
deck.setBeatLoop("a" | "b", 2 | 4 | 8 | 16) | RejectedCommandResult<BEAT_LOOP_TEMPORARILY_UNAVAILABLE> |
deck.clearBeatLoop("a" | "b") | CommandResult<BeatGridState> |
deck.getBeatGrid("a" | "b") | BeatGridState | RejectedCommandResult |
deck.setLoop("a" | "b", startSeconds, endSeconds) | CommandResult<LoopState> |
deck.enableLoop("a" | "b") | CommandResult<LoopState> |
deck.disableLoop("a" | "b") | CommandResult<LoopState> |
deck.clearLoop("a" | "b") | CommandResult<LoopState> |
deck.getLoop("a" | "b") | LoopState | RejectedCommandResult |
mixer methods
| Method | Result |
|---|---|
mixer.setCrossfader(0..100) | CommandResult<{ crossfader }> |
mixer.crossfade(0..100, durationMs = 1000) | CommandResult<{ transitionId }> |
mixer.cancelTransition() | CommandResult<{ cancelled }> |
mixer.stopAll() | CommandResult<MixerState> |
mixer.getState() | MixerState |
events methods
| Method | Result |
|---|---|
events.subscribe(handler) | { ok: true } | RejectedCommandResult |
events.unsubscribe(handler) | { ok: boolean } |
events.getRecent() | ControllerEvent[] (latest 100 maximum) |
Result contract
Commands return { ok: true, command, value? } when accepted or { ok: false, command, error } when rejected. Read-only getters return their documented state or list directly. Event memory is bounded to the latest 100 events.
Visible UI control procedure
- Wait for the human to start Agent Performance.
- Continue only while the visible status reads active.
- Operate rendered DJCLIPZ controls without requiring page-owned JavaScript.
- Stop immediately on visible Pause Agent, Take Over, Stop Performance, an inactive status, or reload.
Direct controller procedure
- Confirm
window.DJCLIPZ.controllerexists, then inspect its version and capabilities. - Confirm
controller.session.getState().state === "active". - Use only documented methods and check every command result before reading its value or issuing a dependent command.
- Stop immediately on a terminal authority state or error, human Pause Agent, Take Over, Stop Performance, or reload.
See the complete browser-agent skill and machine-readable controller manifest.
Legacy compatibility
Performer v0.1.0 remains a playlist-only compatibility adapter with getState, getPlaylist, load, play, pause, setCrossfader, and stop. The raw-seconds setLoop, enableLoop, disableLoop, clearLoop, and getLoop controller methods remain for compatibility but are not exposed in the normal player UI. It is not the complete Agent Controller v1.1 surface. Its entrypoint is window.DJCLIPZ.performer.
Privacy and data boundaries
Search text is processed transiently by the first-party Worker and the YouTube Data API. Raw search text is not logged by the application, returned in the response, or written to D1. Detailed controller and media records remain in Mix Intelligence and are not sent to GA4 or connected intentionally to Formspree identity.
Measured limitations
- Control is browser-local to the current page. There is no remote command service, MCP server, or A2A endpoint.
- A human must start each Agent Performance session; authority never persists across reload.
- Media discovery and playback currently support YouTube only and depend on YouTube API and embed availability.
- The human mixer UI shows beat-loop controls as OFFLINE and keeps them disabled for YouTube playback. The agent command deck.setBeatLoop(...) rejects with BEAT_LOOP_TEMPORARILY_UNAVAILABLE and must not be retried. BPM entry, Tap Tempo, SET 1, saved browser calibration, hot cues, playback, mixing, and crossfading remain available.
- Beat-grid quantization assumes four-beat bars in Controller v1.1.0.
- setPlaybackRate accepts only 0.25, 0.5, 1, 1.5, or 2 and still rejects a rate unavailable from the current YouTube player.
- Timed crossfades accept 100 to 600000 ms and run on browser timers; they are not frame-accurate.
- Search is limited to 10 results and rate-limited; the session queue is limited to 50 items.
- DJCLIPZ does not bundle an AI model, automatic BPM detector, beat matcher, recommendation model, or full autonomous agent performance.