polywave API Reference

May 12, 2026 ยท View on GitHub

The polywave-web serve command exposes an HTTP API on localhost:7432 (configurable via --addr). All endpoints return JSON unless otherwise noted. SSE (Server-Sent Events) endpoints stream text/event-stream.

Base URL: http://localhost:7432

Quick Reference

EndpointMethodCategoryDescription
/api/eventsGET (SSE)GlobalGlobal event stream (impl list updates)
/api/browseGETNavigationOpen native file browser
/api/browse/nativeGETNavigationLaunch OS file picker
/api/implGETIMPL DocsList all IMPL docs
/api/impl/{slug}GETIMPL DocsGet IMPL doc details
/api/impl/{slug}DELETEIMPL DocsDelete IMPL doc
/api/impl/{slug}/archivePOSTIMPL DocsArchive IMPL doc
/api/impl/{slug}/rawGETIMPL DocsGet raw IMPL doc content
/api/impl/{slug}/rawPUTIMPL DocsUpdate raw IMPL doc
/api/impl/{slug}/approvePOSTReviewMark IMPL as approved
/api/impl/{slug}/rejectPOSTReviewMark IMPL as rejected
/api/impl/{slug}/diff/{agent}GETReviewGet file diffs for agent
/api/impl/{slug}/amendPOSTReviewAmend IMPL doc via AI
/api/impl/{slug}/critic-reviewGETCriticGet critic review for IMPL
/api/impl/{slug}/run-criticPOSTCriticRun critic review agent
/api/impl/{slug}/fix-criticPATCHCriticApply critic fix to IMPL
/api/impl/{slug}/auto-fix-criticPOSTCriticAuto-fix all critic issues
/api/impl/{slug}/validate-integrationGETValidationCheck integration gaps
/api/impl/{slug}/validate-wiringGETValidationCheck wiring gaps
/api/impl/importPOSTIMPL DocsBulk import IMPLs into a program
/api/scout/runPOSTScoutRun Scout agent
/api/scout/{slug}/rerunPOSTScoutRe-run Scout for existing IMPL
/api/scout/{runID}/eventsGET (SSE)ScoutScout execution event stream
/api/scout/{runID}/cancelPOSTScoutCancel running Scout
/api/wave/{slug}/startPOSTWaveStart wave execution
/api/wave/{slug}/eventsGET (SSE)WaveWave execution event stream
/api/wave/{slug}/stateGETWaveGet current wave state machine
/api/wave/{slug}/statusGETWaveGet agent progress status
/api/wave/{slug}/disk-statusGETWaveGet worktree disk status
/api/wave/{slug}/review/{wave}GETWaveGet wave review data
/api/wave/{slug}/mergePOSTWaveMerge completed wave
/api/wave/{slug}/finalizePOSTWaveFinalize wave (full pipeline)
/api/wave/{slug}/merge-abortPOSTWaveAbort an in-progress merge
/api/wave/{slug}/testPOSTWaveRun post-merge tests
/api/wave/{slug}/gate/proceedPOSTWaveProceed past quality gate
/api/wave/{slug}/agent/{letter}/rerunPOSTWaveRe-run specific agent
/api/wave/{slug}/resumePOSTWaveResume interrupted execution
/api/wave/{slug}/resolve-conflictsPOSTWaveResolve merge conflicts
/api/wave/{slug}/fix-buildPOSTWaveFix build failures
/api/wave/{slug}/step/{step}/retryPOSTRecoveryRetry a failed pipeline step
/api/wave/{slug}/step/{step}/skipPOSTRecoverySkip a pipeline step
/api/wave/{slug}/mark-completePOSTRecoveryForce-mark wave complete
/api/wave/{slug}/pipelineGETRecoveryGet pipeline state
/api/sessions/interruptedGETSessionsList interrupted sessions
/api/impl/{slug}/worktreesGETWorktreesList worktrees for IMPL
/api/impl/{slug}/worktrees/{branch}DELETEWorktreesDelete specific worktree
/api/impl/{slug}/worktrees/cleanupPOSTWorktreesBatch delete worktrees
/api/worktrees/cleanup-stalePOSTWorktreesGlobal stale worktree cleanup
/api/impl/{slug}/chatPOSTChatStart chat session
/api/impl/{slug}/chat/{runID}/eventsGET (SSE)ChatChat message stream
/api/impl/{slug}/revisePOSTReviseRevise IMPL doc via AI
/api/impl/{slug}/revise/{runID}/eventsGET (SSE)ReviseRevise event stream
/api/impl/{slug}/revise/{runID}/cancelPOSTReviseCancel revision
/api/impl/{slug}/scaffold/rerunPOSTScaffoldRe-run scaffold agent
/api/impl/{slug}/agent/{letter}/contextGETContextGet agent context payload
/api/contextGETContextGet CONTEXT.md content
/api/contextPUTContextUpdate CONTEXT.md
/api/configGETConfigGet polywave.config.json
/api/configPOSTConfigUpdate polywave.config.json
/api/config/validate-repoPOSTConfigValidate a repository path
/api/bootstrap/runPOSTBootstrapRun bootstrap for new project
/api/notifications/preferencesGETNotificationsGet notification preferences
/api/notifications/preferencesPOSTNotificationsSave notification preferences
/api/manifest/{slug}GETManifestLoad YAML manifest
/api/manifest/{slug}/validatePOSTManifestValidate manifest
/api/manifest/{slug}/wave/{number}GETManifestGet specific wave
/api/manifest/{slug}/completion/{agentID}POSTManifestSet completion report
/api/journal/{wave}/{agent}GETJournalGet tool usage journal
/api/journal/{wave}/{agent}/summaryGETJournalGet journal summary
/api/journal/{wave}/{agent}/checkpointsGETJournalList journal checkpoints
/api/journal/{wave}/{agent}/restorePOSTJournalRestore from checkpoint
/api/planner/runPOSTPlannerRun Planner agent
/api/planner/{runID}/eventsGET (SSE)PlannerPlanner execution event stream
/api/planner/{runID}/cancelPOSTPlannerCancel running Planner
/api/programsGETProgramsList all PROGRAM manifests
/api/programs/analyze-implsPOSTProgramsAnalyze IMPLs for program creation
/api/programs/create-from-implsPOSTProgramsCreate program from IMPLs
/api/program/{slug}GETProgramsGet program status
/api/program/{slug}/tier/{n}GETProgramsGet tier status
/api/program/{slug}/tier/{n}/executePOSTProgramsExecute a tier
/api/program/{slug}/contractsGETProgramsGet program contracts
/api/program/{slug}/replanPOSTProgramsRe-plan a program
/api/program/eventsGET (SSE)ProgramsProgram event stream
/api/pipelineGETAutonomyGet pipeline state
/api/queueGETAutonomyList execution queue
/api/queuePOSTAutonomyAdd item to queue
/api/queue/{slug}DELETEAutonomyRemove item from queue
/api/queue/{slug}/priorityPUTAutonomyReorder queue item priority
/api/autonomyGETAutonomyGet autonomy settings
/api/autonomyPUTAutonomyUpdate autonomy settings
/api/daemon/startPOSTDaemonStart background daemon
/api/daemon/stopPOSTDaemonStop background daemon
/api/daemon/statusGETDaemonGet daemon status
/api/daemon/eventsGET (SSE)DaemonDaemon event stream
/api/interview/startPOSTInterviewStart interview session
/api/interview/{runID}/eventsGET (SSE)InterviewInterview event stream
/api/interview/{runID}/answerPOSTInterviewSubmit interview answer
/api/interview/{runID}/cancelPOSTInterviewCancel interview
/api/observability/metrics/{impl_slug}GETObservabilityGet IMPL metrics
/api/observability/metrics/program/{program_slug}GETObservabilityGet program metrics summary
/api/observability/eventsGETObservabilityQuery observability events
/api/observability/rollupGETObservabilityGet aggregated rollup
/api/observability/cost-breakdown/{impl_slug}GETObservabilityGet cost breakdown
/api/files/treeGETFilesBrowse file tree
/api/files/readGETFilesRead file contents
/api/files/diffGETFilesGet file diff
/api/files/statusGETFilesGet file git status

Global Events

GET /api/events

Global SSE stream for server-wide events (e.g., IMPL list updates).

Response: text/event-stream

Events:

  • impl_list_updated -- IMPL directory changed (new/modified/deleted files)
    {"event": "impl_list_updated"}
    

Example:

const es = new EventSource('/api/events');
es.addEventListener('impl_list_updated', () => {
  // Refresh IMPL list
});

GET /api/browse

Open native OS file browser at repository root.

Response:

{"status": "ok"}

Status: 200 OK on success, 500 if file browser fails to launch


GET /api/browse/native

Launch native OS file picker dialog (currently same as /api/browse).

Response:

{"status": "ok"}

IMPL Document Operations

GET /api/impl

List all IMPL docs in the configured --impl-dir.

Response:

{
  "impls": [
    {
      "slug": "oauth",
      "title": "Add OAuth 2.0 authentication",
      "path": "/abs/path/to/docs/IMPL/IMPL-oauth.yaml",
      "status": "suitable",
      "format": "yaml",
      "wave_count": 3,
      "agent_count": 8,
      "current_wave": 2
    }
  ]
}

Fields:

  • slug -- Filename without IMPL- prefix and extension
  • status -- pending, suitable, not-suitable, in-progress, complete
  • format -- markdown or yaml

GET /api/impl/{slug}

Get parsed IMPL doc with full wave/agent details.

Path params:

  • slug -- IMPL doc slug (e.g., oauth for IMPL-oauth.yaml)

Response:

{
  "slug": "oauth",
  "title": "Add OAuth 2.0 authentication",
  "path": "/abs/path/to/IMPL-oauth.yaml",
  "format": "yaml",
  "raw": "...",
  "verdict": {
    "status": "suitable",
    "reason": "Clear scope, well-defined waves",
    "complexity": "medium"
  },
  "waves": [
    {
      "wave": 1,
      "agents": [
        {
          "id": "A",
          "task": "Implement OAuth client",
          "files": ["pkg/oauth/client.go"],
          "dependencies": [],
          "status": "complete"
        }
      ]
    }
  ],
  "interface_contracts": [
    {
      "file": "pkg/oauth/types.go",
      "description": "OAuth token types",
      "frozen": true
    }
  ],
  "file_ownership": {
    "pkg/oauth/client.go": "A",
    "pkg/oauth/storage.go": "B"
  }
}

Status: 200 OK on success, 404 if not found, 500 on parse error


DELETE /api/impl/{slug}

Delete an IMPL doc file.

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK on success, 404 if not found


POST /api/impl/{slug}/archive

Archive an IMPL doc (move to complete/ subdirectory).

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK on success, 404 if not found


GET /api/impl/{slug}/raw

Get raw IMPL doc content (markdown or YAML).

Path params:

  • slug -- IMPL doc slug

Response:

{
  "content": "# IMPL: Add OAuth...",
  "format": "markdown"
}

Status: 200 OK on success, 404 if not found


PUT /api/impl/{slug}/raw

Update raw IMPL doc content.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "content": "# IMPL: Updated content..."
}

Response:

{"status": "ok"}

Status: 200 OK on success, 400 on invalid JSON, 500 on write error


POST /api/impl/import

Bulk import IMPL docs into a program.

Request body:

{
  "program_slug": "my-program",
  "impl_slugs": ["oauth", "caching", "rate-limit"]
}

Response:

{"status": "ok", "imported": 3}

Status: 200 OK on success, 400 on invalid request


Review Operations

POST /api/impl/{slug}/approve

Mark IMPL doc as approved (sets status to approved in metadata).

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK always


POST /api/impl/{slug}/reject

Mark IMPL doc as rejected (sets status to rejected in metadata).

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK always


GET /api/impl/{slug}/diff/{agent}

Get file diffs for a specific agent's worktree.

Path params:

  • slug -- IMPL doc slug
  • agent -- Agent letter (e.g., A, B)

Query params:

  • wave -- Wave number (optional)
  • file -- URL-encoded file path to get diff for specific file (optional)

Response:

{
  "agent": "A",
  "diffs": [
    {
      "file": "pkg/oauth/client.go",
      "diff": "@@ -1,5 +1,8 @@\n package oauth\n+\n+import \"net/http\"\n..."
    }
  ]
}

Status: 200 OK on success, 404 if agent/worktree not found


POST /api/impl/{slug}/amend

Amend an IMPL doc using AI based on feedback.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "feedback": "Add error handling to Wave 2 agents"
}

Response:

{"status": "ok"}

Status: 200 OK on success


Critic Operations

GET /api/impl/{slug}/critic-review

Get the most recent critic review for an IMPL doc.

Path params:

  • slug -- IMPL doc slug

Response:

{
  "review": {
    "issues": [...],
    "score": 85,
    "timestamp": "2026-03-15T10:30:00Z"
  }
}

Status: 200 OK on success, 404 if no review found


POST /api/impl/{slug}/run-critic

Run critic review agent against an IMPL doc.

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok", "run_id": "..."}

Status: 200 OK on success


PATCH /api/impl/{slug}/fix-critic

Apply a specific critic fix to an IMPL doc.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "issue_id": "critic-1",
  "fix": "..."
}

Response:

{"status": "ok"}

Status: 200 OK on success


POST /api/impl/{slug}/auto-fix-critic

Automatically fix all critic issues in an IMPL doc.

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok", "fixed": 3}

Status: 200 OK on success


Validation Operations

GET /api/impl/{slug}/validate-integration

Check for integration gaps in an IMPL doc (missing cross-agent dependencies, untested interfaces).

Path params:

  • slug -- IMPL doc slug

Query params:

  • wave -- Wave number to check (optional)

Response:

{
  "gaps": [...],
  "valid": true
}

Status: 200 OK on success


GET /api/impl/{slug}/validate-wiring

Check for wiring gaps in an IMPL doc (unconnected components, missing imports).

Path params:

  • slug -- IMPL doc slug

Response:

{
  "gaps": [...],
  "valid": true
}

Status: 200 OK on success


Scout Operations

POST /api/scout/run

Run Scout agent to generate a new IMPL doc.

Request body:

{
  "feature": "Add OAuth 2.0 authentication",
  "backend": "auto"
}

Fields:

  • feature -- Feature description (required)
  • backend -- api, cli, or auto (optional; default: auto)

Response:

{
  "run_id": "1773031123005120000",
  "slug": "oauth"
}

Status: 200 OK on success, 400 on invalid request

See also: GET /api/scout/{runID}/events for execution stream


POST /api/scout/{slug}/rerun

Re-run Scout agent for an existing IMPL doc (regenerate based on current codebase).

Path params:

  • slug -- IMPL doc slug

Response:

{
  "run_id": "1773031456789012000"
}

Status: 200 OK on success, 404 if IMPL not found


GET /api/scout/{runID}/events

SSE stream for Scout agent execution.

Path params:

  • runID -- Run ID from POST /api/scout/run response

Response: text/event-stream

Events:

  • scout_output -- Streaming output chunk
    {"run_id": "...", "chunk": "Analyzing codebase..."}
    
  • scout_complete -- Scout finished successfully
    {"run_id": "...", "slug": "oauth", "path": "/path/to/IMPL-oauth.yaml"}
    
  • scout_failed -- Scout failed
    {"run_id": "...", "error": "Failed to parse..."}
    

POST /api/scout/{runID}/cancel

Cancel a running Scout agent.

Path params:

  • runID -- Run ID from Scout run

Response:

{"status": "ok"}

Status: 200 OK if cancelled, 404 if run not found


Wave Execution

POST /api/wave/{slug}/start

Start wave execution for an IMPL doc.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "wave_num": 1,
  "auto": true
}

Fields:

  • wave_num -- Wave number to execute (default: 1)
  • auto -- Continue automatically after completion (default: false)

Response:

{"status": "started"}

Status: 200 OK on success, 409 if wave already running

See also: GET /api/wave/{slug}/events for execution stream


GET /api/wave/{slug}/events

SSE stream for wave execution events.

Path params:

  • slug -- IMPL doc slug

Response: text/event-stream

Events:

  • wave_started -- Wave execution began
    {"wave": 1, "agents": ["A", "B"]}
    
  • agent_status -- Agent status changed
    {"wave": 1, "agent": "A", "status": "running"}
    
  • agent_output -- Agent stdout/stderr line
    {"wave": 1, "agent": "A", "line": "Processing file..."}
    
  • agent_complete -- Agent finished
    {"wave": 1, "agent": "A", "status": "complete"}
    
  • agent_failed -- Agent failed
    {"wave": 1, "agent": "A", "error": "Build failed"}
    
  • wave_complete -- All agents in wave finished
    {"wave": 1, "status": "complete"}
    
  • merge_started -- Merge operation began
    {"wave": 1}
    
  • merge_complete -- Merge succeeded
    {"wave": 1, "status": "merged"}
    
  • merge_failed -- Merge failed
    {"wave": 1, "error": "Conflict in file..."}
    
  • run_complete -- All waves finished
    {"status": "success", "waves": 3, "agents": 8}
    
  • run_failed -- Wave run failed
    {"error": "Wave 2 failed: Agent C blocked"}
    

GET /api/wave/{slug}/state

Get current wave state machine status.

Path params:

  • slug -- IMPL doc slug

Response:

{
  "stage": "wave_executing",
  "wave": 2,
  "agents": {
    "A": "complete",
    "B": "running",
    "C": "pending"
  }
}

Stages: scout_pending, reviewed, scaffold_pending, wave_pending, wave_executing, wave_merging, wave_verified, complete, blocked, not_suitable

Status: 200 OK on success, 404 if IMPL not found


GET /api/wave/{slug}/status

Get agent progress status for a wave (real-time agent progress tracking).

Path params:

  • slug -- IMPL doc slug

Response:

{
  "agents": {
    "A": {"status": "running", "progress": 75},
    "B": {"status": "complete"}
  }
}

Status: 200 OK on success


GET /api/wave/{slug}/disk-status

Get worktree disk status for a wave (disk usage, file counts).

Path params:

  • slug -- IMPL doc slug

Response:

{
  "worktrees": [
    {"agent": "A", "path": "/path/to/worktree", "size_bytes": 1234567}
  ]
}

Status: 200 OK on success


GET /api/wave/{slug}/review/{wave}

Get review data for a specific wave (diffs, commit summaries, gate results).

Path params:

  • slug -- IMPL doc slug
  • wave -- Wave number

Response:

{
  "wave": 1,
  "agents": [...],
  "diffs": [...],
  "gate_results": [...]
}

Status: 200 OK on success, 404 if wave not found


POST /api/wave/{slug}/merge

Manually trigger merge for a completed wave.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "wave_num": 1
}

Response:

{"status": "merging"}

Status: 200 OK on success, 409 if merge already in progress


POST /api/wave/{slug}/finalize

Finalize a wave (run the full post-wave pipeline: verify commits, scan stubs, run gates, merge, verify build, cleanup).

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "wave_num": 1
}

Response:

{"status": "finalizing"}

Status: 200 OK on success, 409 if already in progress


POST /api/wave/{slug}/merge-abort

Abort an in-progress merge operation.

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK on success


POST /api/wave/{slug}/test

Run post-merge test suite for a wave.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "wave_num": 1
}

Response:

{
  "status": "running",
  "test_id": "..."
}

Status: 200 OK on success


POST /api/wave/{slug}/gate/proceed

Proceed past a quality gate checkpoint (when paused for review).

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK on success


POST /api/wave/{slug}/agent/{letter}/rerun

Re-run a specific agent in a wave (recovery tool).

Path params:

  • slug -- IMPL doc slug
  • letter -- Agent letter (e.g., A, B)

Response:

{"status": "rerunning"}

Status: 200 OK on success, 404 if agent not found


POST /api/wave/{slug}/resume

Resume an interrupted wave execution.

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "resumed"}

Status: 200 OK on success, 404 if no interrupted session found


POST /api/wave/{slug}/resolve-conflicts

Resolve merge conflicts for a wave (launches conflict resolution agent).

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "resolving"}

Status: 200 OK on success


POST /api/wave/{slug}/fix-build

Fix build failures after merge (launches build fix agent).

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "fixing"}

Status: 200 OK on success


Recovery Operations

POST /api/wave/{slug}/step/{step}/retry

Retry a specific failed pipeline step.

Path params:

  • slug -- IMPL doc slug
  • step -- Pipeline step name (e.g., verify_commits, scan_stubs, run_gates, validate_integration, merge_agents, fix_go_mod, verify_build, integration_agent, cleanup)

Request body:

{
  "wave": 1
}

Response:

{"status": "retrying"}

Status: 200 OK on success, 400 if step is invalid


POST /api/wave/{slug}/step/{step}/skip

Skip a pipeline step (only allowed for skippable steps).

Path params:

  • slug -- IMPL doc slug
  • step -- Pipeline step name

Request body:

{
  "wave": 1,
  "reason": "Known flaky test, skip for now"
}

Response:

{"status": "skipped"}

Status: 200 OK on success, 400 if step is not skippable


POST /api/wave/{slug}/mark-complete

Force-mark a wave as complete (emergency recovery).

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK on success


GET /api/wave/{slug}/pipeline

Get current pipeline state for a wave (step statuses, current step, errors).

Path params:

  • slug -- IMPL doc slug

Response:

{
  "steps": [
    {"name": "verify_commits", "status": "complete"},
    {"name": "run_gates", "status": "failed", "error": "test failure"}
  ],
  "current_step": "run_gates"
}

Status: 200 OK on success


Session Management

GET /api/sessions/interrupted

List interrupted wave sessions that can be resumed.

Response:

{
  "sessions": [
    {
      "slug": "oauth",
      "wave": 2,
      "interrupted_at": "2026-03-15T10:30:00Z",
      "agents": {"A": "complete", "B": "running"}
    }
  ]
}

Status: 200 OK always


Worktree Management

GET /api/impl/{slug}/worktrees

List all worktrees associated with an IMPL doc.

Path params:

  • slug -- IMPL doc slug

Response:

{
  "worktrees": [
    {
      "branch": "wave-1-agent-A",
      "path": "/path/to/.claude/worktrees/wave-1-agent-A",
      "agent": "A",
      "wave": 1,
      "status": "active"
    }
  ]
}

Status: 200 OK on success


DELETE /api/impl/{slug}/worktrees/{branch}

Delete a specific worktree.

Path params:

  • slug -- IMPL doc slug
  • branch -- Branch name (e.g., wave-1-agent-A)

Query params:

  • force -- Set to true to force deletion (optional)

Response:

{"status": "ok"}

Status: 200 OK on success, 404 if not found


POST /api/impl/{slug}/worktrees/cleanup

Batch delete worktrees for completed waves.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "wave_num": 1
}

Response:

{
  "deleted": ["wave-1-agent-A", "wave-1-agent-B"],
  "count": 2
}

Status: 200 OK on success


POST /api/worktrees/cleanup-stale

Trigger global stale worktree cleanup across all repos.

Response:

{"status": "ok", "cleaned": 5}

Status: 200 OK on success


Chat Operations

POST /api/impl/{slug}/chat

Start a chat session with Claude about an IMPL doc.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "message": "What does Agent B do?",
  "history": [
    {"role": "user", "content": "Explain this IMPL"},
    {"role": "assistant", "content": "This IMPL adds OAuth..."}
  ]
}

Fields:

  • message -- User message (required)
  • history -- Previous conversation turns (optional)

Response:

{
  "run_id": "1773031678901230000"
}

Status: 200 OK on success

See also: GET /api/impl/{slug}/chat/{runID}/events for response stream


GET /api/impl/{slug}/chat/{runID}/events

SSE stream for chat response.

Path params:

  • slug -- IMPL doc slug
  • runID -- Run ID from chat request

Response: text/event-stream

Events:

  • chat_output -- Response chunk
    {"run_id": "...", "chunk": "Agent B implements..."}
    
  • chat_complete -- Response finished
    {"run_id": "...", "slug": "oauth"}
    
  • chat_failed -- Chat failed
    {"run_id": "...", "error": "API error"}
    

Revise Operations

POST /api/impl/{slug}/revise

Request AI revision of an IMPL doc based on feedback.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "feedback": "Split Wave 2 into two waves for better parallelization"
}

Response:

{
  "run_id": "1773031890123450000"
}

Status: 200 OK on success


GET /api/impl/{slug}/revise/{runID}/events

SSE stream for revision process.

Path params:

  • slug -- IMPL doc slug
  • runID -- Run ID from revise request

Response: text/event-stream

Events:

  • revise_output -- Progress update
    {"run_id": "...", "chunk": "Analyzing wave dependencies..."}
    
  • revise_complete -- Revision finished
    {"run_id": "...", "slug": "oauth"}
    
  • revise_failed -- Revision failed
    {"run_id": "...", "error": "..."}
    

POST /api/impl/{slug}/revise/{runID}/cancel

Cancel an in-progress revision.

Path params:

  • slug -- IMPL doc slug
  • runID -- Run ID from revise request

Response:

{"status": "ok"}

Status: 200 OK if cancelled, 404 if not found


Scaffold Operations

POST /api/impl/{slug}/scaffold/rerun

Re-run scaffold agent to regenerate interface contract stubs.

Path params:

  • slug -- IMPL doc slug

Response:

{
  "run_id": "1773032012345670000",
  "status": "running"
}

Status: 200 OK on success


Context Operations

GET /api/impl/{slug}/agent/{letter}/context

Get agent-specific context payload (E23).

Path params:

  • slug -- IMPL doc slug
  • letter -- Agent letter (e.g., A, B)

Response:

{
  "task": "Implement OAuth client with PKCE",
  "files": ["pkg/oauth/client.go"],
  "dependencies": [],
  "impl_doc_path": "/path/to/IMPL-oauth.yaml"
}

Status: 200 OK on success, 404 if agent not found


GET /api/context

Get CONTEXT.md content (project-wide context file).

Response:

{
  "content": "# Project Context\n\n...",
  "exists": true
}

Status: 200 OK always (returns empty if file doesn't exist)


PUT /api/context

Update CONTEXT.md content.

Request body:

{
  "content": "# Updated Context\n\n..."
}

Response:

{"status": "ok"}

Status: 200 OK on success, 500 on write error


Configuration

GET /api/config

Get current polywave.config.json configuration.

Response:

{
  "repos": [
    {
      "path": "/path/to/project",
      "name": "MyProject",
      "active": true
    }
  ],
  "agent": {
    "scout_model": "claude-sonnet-4",
    "wave_model": "claude-sonnet-4",
    "chat_model": "claude-sonnet-4"
  },
  "quality": {
    "require_tests": true,
    "require_lint": false,
    "block_on_failure": true
  },
  "appearance": {
    "theme": "system"
  }
}

Status: 200 OK always (returns defaults if config doesn't exist)


POST /api/config

Update polywave.config.json configuration.

Request body: Same structure as GET response

Response:

{"status": "ok"}

Status: 200 OK on success, 400 on invalid JSON, 500 on write error


POST /api/config/validate-repo

Validate a repository path (check if it's a valid git repo with appropriate structure).

Request body:

{
  "path": "/path/to/repo"
}

Response:

{
  "valid": true,
  "name": "my-project"
}

Status: 200 OK always (validation result in body)


Bootstrap

POST /api/bootstrap/run

Run bootstrap workflow for a new project (creates CONTEXT.md, initializes IMPL directory, etc.).

Request body:

{
  "repo_path": "/path/to/project"
}

Response:

{"status": "ok", "run_id": "..."}

Status: 200 OK on success


Notifications

GET /api/notifications/preferences

Get notification preferences.

Response:

{
  "preferences": {
    "wave_complete": true,
    "agent_failed": true,
    "merge_conflict": true
  }
}

Status: 200 OK always


POST /api/notifications/preferences

Save notification preferences.

Request body: Same structure as GET response

Response:

{"status": "ok"}

Status: 200 OK on success


Manifest Operations

GET /api/manifest/{slug}

Load and parse a YAML IMPL manifest.

Path params:

  • slug -- IMPL doc slug

Response:

{
  "feature": "Add OAuth 2.0 authentication",
  "verdict": {
    "status": "suitable",
    "reason": "...",
    "complexity": "medium"
  },
  "waves": [...],
  "interface_contracts": [...]
}

Status: 200 OK on success, 404 if not found, 500 on parse error


POST /api/manifest/{slug}/validate

Validate a YAML manifest against protocol invariants.

Path params:

  • slug -- IMPL doc slug

Response:

{
  "valid": true,
  "errors": []
}

Or with errors:

{
  "valid": false,
  "errors": [
    {
      "code": "E16C",
      "message": "Duplicate agent ID 'A' in wave 2",
      "line": 45
    }
  ]
}

Status: 200 OK always (validation result in body)


GET /api/manifest/{slug}/wave/{number}

Get a specific wave from a manifest.

Path params:

  • slug -- IMPL doc slug
  • number -- Wave number

Response:

{
  "wave": 2,
  "agents": [
    {
      "id": "C",
      "task": "...",
      "files": [...],
      "dependencies": ["A"]
    }
  ]
}

Status: 200 OK on success, 404 if wave not found


POST /api/manifest/{slug}/completion/{agentID}

Set completion report for an agent.

Path params:

  • slug -- IMPL doc slug
  • agentID -- Agent ID (e.g., A, B)

Request body:

{
  "status": "complete",
  "summary": "Implemented OAuth client",
  "files_modified": ["pkg/oauth/client.go"],
  "tests_added": 12,
  "notes": "Added integration tests"
}

Response:

{"status": "ok"}

Status: 200 OK on success, 400 on invalid JSON, 500 on save error


Journal Operations

GET /api/journal/{wave}/{agent}

Get full tool usage journal for an agent.

Path params:

  • wave -- Wave number
  • agent -- Agent letter

Response:

{
  "wave": 1,
  "agent": "A",
  "entries": [
    {
      "timestamp": "2026-03-11T10:30:00Z",
      "tool": "Read",
      "args": {"file_path": "/path/to/file.go"},
      "result": "success"
    }
  ]
}

Status: 200 OK on success, 404 if journal not found


GET /api/journal/{wave}/{agent}/summary

Get summary statistics for agent's tool usage.

Path params:

  • wave -- Wave number
  • agent -- Agent letter

Response:

{
  "total_tools": 45,
  "by_type": {
    "Read": 12,
    "Write": 8,
    "Bash": 15,
    "Edit": 10
  },
  "duration_seconds": 320
}

Status: 200 OK on success, 404 if journal not found


GET /api/journal/{wave}/{agent}/checkpoints

List available checkpoints in agent's journal.

Path params:

  • wave -- Wave number
  • agent -- Agent letter

Response:

{
  "checkpoints": [
    {
      "id": "1",
      "timestamp": "2026-03-11T10:35:00Z",
      "description": "After parsing config"
    }
  ]
}

Status: 200 OK on success, 404 if journal not found


POST /api/journal/{wave}/{agent}/restore

Restore agent state from a checkpoint.

Path params:

  • wave -- Wave number
  • agent -- Agent letter

Request body:

{
  "checkpoint_id": "1"
}

Response:

{"status": "ok"}

Status: 200 OK on success, 404 if checkpoint not found


Planner Operations

POST /api/planner/run

Run Planner agent to produce a PROGRAM manifest from a feature description.

Request body:

{
  "feature": "E-commerce platform with payments and inventory",
  "backend": "auto"
}

Response:

{
  "run_id": "1773031123005120000"
}

Status: 200 OK on success, 400 on invalid request


GET /api/planner/{runID}/events

SSE stream for Planner agent execution.

Path params:

  • runID -- Run ID from POST /api/planner/run response

Response: text/event-stream

Events:

  • planner_output -- Streaming output chunk
  • planner_complete -- Planner finished successfully
  • planner_failed -- Planner failed

POST /api/planner/{runID}/cancel

Cancel a running Planner agent.

Path params:

  • runID -- Run ID from Planner run

Response:

{"status": "ok"}

Status: 200 OK if cancelled, 404 if run not found


Program Operations

GET /api/programs

List all PROGRAM manifests.

Response:

{
  "programs": [
    {
      "slug": "ecommerce",
      "title": "E-commerce Platform",
      "tier_count": 3,
      "status": "in_progress"
    }
  ]
}

Status: 200 OK always


POST /api/programs/analyze-impls

Analyze existing IMPLs to suggest program groupings and dependencies.

Request body:

{
  "impl_slugs": ["oauth", "caching", "rate-limit"]
}

Response:

{
  "suggestions": [...]
}

Status: 200 OK on success


POST /api/programs/create-from-impls

Create a new PROGRAM manifest from selected IMPLs.

Request body:

{
  "title": "Auth System",
  "impl_slugs": ["oauth", "session-mgmt"]
}

Response:

{"status": "ok", "slug": "auth-system"}

Status: 200 OK on success


GET /api/program/{slug}

Get program status with tier completion details.

Path params:

  • slug -- Program slug

Response:

{
  "slug": "ecommerce",
  "title": "E-commerce Platform",
  "tiers": [
    {"tier": 1, "impls": ["oauth", "users"], "status": "complete"},
    {"tier": 2, "impls": ["payments", "inventory"], "status": "in_progress"}
  ]
}

Status: 200 OK on success, 404 if not found


GET /api/program/{slug}/tier/{n}

Get detailed status for a specific tier.

Path params:

  • slug -- Program slug
  • n -- Tier number

Response:

{
  "tier": 1,
  "impls": [...],
  "status": "complete"
}

Status: 200 OK on success, 404 if tier not found


POST /api/program/{slug}/tier/{n}/execute

Execute all IMPLs in a tier (triggers Scout/Wave for each).

Path params:

  • slug -- Program slug
  • n -- Tier number

Response:

{"status": "executing"}

Status: 200 OK on success, 409 if already executing


GET /api/program/{slug}/contracts

Get cross-IMPL interface contracts for a program.

Path params:

  • slug -- Program slug

Response:

{
  "contracts": [...]
}

Status: 200 OK on success


POST /api/program/{slug}/replan

Re-plan a program (re-analyze dependencies and reorder tiers).

Path params:

  • slug -- Program slug

Response:

{"status": "ok"}

Status: 200 OK on success


GET /api/program/events

SSE stream for program-level events (tier completion, IMPL status changes).

Response: text/event-stream

Events:

  • program_updated -- Program state changed
  • tier_complete -- A tier finished execution

Autonomy Layer

GET /api/pipeline

Get the full autonomy pipeline state (queue, daemon status, active executions).

Query params:

  • include_completed -- Set to true to include completed items (optional)

Response:

{
  "queue": [...],
  "daemon_running": true,
  "active_execution": "oauth"
}

Status: 200 OK always


GET /api/queue

List the current execution queue.

Response:

{
  "items": [
    {"slug": "oauth", "priority": 1, "status": "pending"},
    {"slug": "caching", "priority": 2, "status": "pending"}
  ]
}

Status: 200 OK always


POST /api/queue

Add an item to the execution queue.

Request body:

{
  "slug": "oauth",
  "priority": 1
}

Response:

{"status": "ok"}

Status: 200 OK on success


DELETE /api/queue/{slug}

Remove an item from the execution queue.

Path params:

  • slug -- IMPL doc slug

Response:

{"status": "ok"}

Status: 200 OK on success, 404 if not found


PUT /api/queue/{slug}/priority

Change the priority of a queue item.

Path params:

  • slug -- IMPL doc slug

Request body:

{
  "priority": 3
}

Response:

{"status": "ok"}

Status: 200 OK on success


GET /api/autonomy

Get autonomy settings (auto-execute, concurrency limits, etc.).

Response:

{
  "enabled": true,
  "max_concurrent": 1,
  "auto_merge": false
}

Status: 200 OK always


PUT /api/autonomy

Update autonomy settings.

Request body: Same structure as GET response

Response:

{"status": "ok"}

Status: 200 OK on success


Daemon Operations

POST /api/daemon/start

Start the background execution daemon (processes queue automatically).

Response:

{"status": "started"}

Status: 200 OK on success, 409 if already running


POST /api/daemon/stop

Stop the background execution daemon.

Response:

{"status": "stopped"}

Status: 200 OK on success


GET /api/daemon/status

Get current daemon status.

Response:

{
  "running": true,
  "uptime_seconds": 3600,
  "current_task": "oauth"
}

Status: 200 OK always


GET /api/daemon/events

SSE stream for daemon events (task started, completed, errors).

Response: text/event-stream

Events:

  • daemon_started -- Daemon started
  • daemon_stopped -- Daemon stopped
  • task_started -- Daemon picked up a queue item
  • task_complete -- Queue item finished
  • task_failed -- Queue item failed

Interview Operations

POST /api/interview/start

Start an interactive interview session to refine a feature description before Scout.

Request body:

{
  "feature": "Add user authentication",
  "backend": "auto"
}

Response:

{
  "run_id": "1773031123005120000"
}

Status: 200 OK on success


GET /api/interview/{runID}/events

SSE stream for interview questions and progress.

Path params:

  • runID -- Run ID from interview start

Response: text/event-stream

Events:

  • interview_question -- A question for the user
  • interview_complete -- Interview finished, feature refined
  • interview_failed -- Interview failed

POST /api/interview/{runID}/answer

Submit an answer to an interview question.

Path params:

  • runID -- Run ID from interview start

Request body:

{
  "answer": "We need OAuth 2.0 with PKCE for SPAs"
}

Response:

{"status": "ok"}

Status: 200 OK on success


POST /api/interview/{runID}/cancel

Cancel an in-progress interview.

Path params:

  • runID -- Run ID from interview start

Response:

{"status": "ok"}

Status: 200 OK if cancelled, 404 if not found


Observability Operations

GET /api/observability/metrics/{impl_slug}

Get observability metrics for an IMPL (agent durations, token usage, success rates).

Path params:

  • impl_slug -- IMPL doc slug

Response:

{
  "impl_slug": "oauth",
  "total_duration_seconds": 1200,
  "total_tokens": 50000,
  "agent_metrics": [...]
}

Status: 200 OK on success, 500 if observability store not configured


GET /api/observability/metrics/program/{program_slug}

Get aggregated observability metrics for a program.

Path params:

  • program_slug -- Program slug

Response:

{
  "program_slug": "ecommerce",
  "total_cost": 12.50,
  "impl_summaries": [...]
}

Status: 200 OK on success


GET /api/observability/events

Query observability events with filters.

Query params:

  • type -- Event type filter (optional)
  • impl -- IMPL slug filter (optional)
  • program -- Program slug filter (optional)
  • agent -- Agent ID filter (optional)
  • start_time -- Start time in RFC3339 format (optional)
  • end_time -- End time in RFC3339 format (optional)
  • limit -- Max results (optional)
  • offset -- Pagination offset (optional)

Response:

{
  "events": [...]
}

Status: 200 OK on success


GET /api/observability/rollup

Get aggregated rollup of observability data.

Query params:

  • type -- Event type filter (optional)
  • group_by -- Grouping key (optional)
  • impl -- IMPL slug filter (optional)
  • program -- Program slug filter (optional)
  • start_time -- Start time in RFC3339 format (optional)
  • end_time -- End time in RFC3339 format (optional)

Response:

{
  "rollups": [...]
}

Status: 200 OK on success


GET /api/observability/cost-breakdown/{impl_slug}

Get cost breakdown for an IMPL (per-agent, per-wave costs).

Path params:

  • impl_slug -- IMPL doc slug

Response:

{
  "impl_slug": "oauth",
  "total_cost": 5.25,
  "by_wave": [...],
  "by_agent": [...]
}

Status: 200 OK on success


File Browser Operations

GET /api/files/tree

Browse file tree of a repository.

Query params:

  • repo -- Repository name (optional)
  • path -- Relative path within repo (optional)

Response:

{
  "entries": [
    {"name": "pkg", "type": "dir"},
    {"name": "main.go", "type": "file", "size": 1234}
  ]
}

Status: 200 OK on success


GET /api/files/read

Read file contents from a repository.

Query params:

  • repo -- Repository name (optional)
  • path -- Relative file path (required)

Response:

{
  "content": "package main\n\nimport...",
  "path": "main.go"
}

Status: 200 OK on success, 404 if file not found


GET /api/files/diff

Get git diff for a file.

Query params:

  • repo -- Repository name (optional)
  • path -- Relative file path (required)

Response:

{
  "diff": "@@ -1,5 +1,8 @@\n..."
}

Status: 200 OK on success


GET /api/files/status

Get git status for files in a repository.

Query params:

  • repo -- Repository name (optional)

Response:

{
  "files": [
    {"path": "pkg/new.go", "status": "added"},
    {"path": "pkg/old.go", "status": "modified"}
  ]
}

Status: 200 OK on success


Static Assets

GET /

Serves the embedded React web UI. All non-API routes fall through to the single-page app (SPA) router.


Error Responses

All endpoints return errors in consistent format:

400 Bad Request:

{"error": "missing slug parameter"}

404 Not Found:

{"error": "IMPL doc not found: oauth"}

409 Conflict:

{"error": "wave 2 already running"}

500 Internal Server Error:

{"error": "failed to parse manifest: ..."}

SSE Event Format

All SSE endpoints follow this pattern:

event: event_name
data: {"key": "value"}

Example stream:

event: wave_started
data: {"wave": 1, "agents": ["A", "B"]}

event: agent_output
data: {"wave": 1, "agent": "A", "line": "Starting..."}

event: wave_complete
data: {"wave": 1, "status": "complete"}

Client example:

const es = new EventSource('/api/wave/oauth/events');
es.addEventListener('wave_started', (e) => {
  const data = JSON.parse(e.data);
  console.log('Wave', data.wave, 'started');
});

Authentication

Currently, the API has no authentication. It's intended for local development only. Do not expose polywave-web serve to untrusted networks.


Rate Limiting

No rate limiting. All operations are synchronous or streamed.


See Also