Skip to content

API endpoints

The Penates API is a REST API served on port 3333 (configurable via PORT). All endpoints under /api/ require authentication. Error messages are always in English regardless of the browser language setting.

Authentication

REST: include the token in every request header:

Authorization: Bearer <token>

WebSocket: pass the token as a subprotocol:

new WebSocket(url, ["bearer." + token])

The server echoes the subprotocol back in the handshake response. A legacy ?token= query-string fallback is accepted for migration purposes.

Remote access via Cloudflare Access: when CF_ACCESS_TEAM_DOMAIN and CF_ACCESS_AUD are set, tunnel requests must additionally carry a valid Cloudflare Access JWT in the Cf-Access-Jwt-Assertion header. Direct local requests bypass this check.

Sessions

MethodRouteDescription
GET/api/sessionsList all tmux sessions. Each entry includes command, limits, and cost.
POST/api/sessionsCreate a session. Body: { name, directory, command }. Names must match ^[\w\-. ]{1,64}$.
DELETE/api/sessions/:nameKill a session and remove it from the known-sessions store.
PATCH/api/sessions/:nameRename a session. Body: { newName }.
POST/api/sessions/:name/adoptRegister a foreign (non-hub) session under its original name without renaming it.
POST/api/sessions/:name/restoreRespawn a dormant (known but not running) session.
POST/api/sessions/:name/muteToggle notification mute for a session.
POST/api/sessions/:name/pinToggle sidebar pin for a session.
DELETE/api/sessions/:name/knownRemove an entry from known-sessions.json without killing the session.
GET/api/sessions/:name/diffUncommitted changes in the session working directory (used by the Repo panel Changes tab).
GET/api/sessions/:name/git/logCommit history for the session repo. Supports ?limit and ?skip for pagination.
GET/api/sessions/:name/git/branchesLocal and remote branches for the session repo.
GET/api/sessions/:name/git/commit/:shaHeader and per-file diffs for a single commit.
GET/api/sessions/:name/file-contentRead a file by path for clickable terminal path previews.
GET/api/sessions/:name/scrollbackCapture tmux scrollback history. Accepts ?lines=N.
POST/api/sessions/:name/uploadUpload files into the session working directory (multipart/form-data via Busboy).
POST/api/sessions/:name/imageUpload a single PNG (raw image/png, max 8 MB) into .penates-images/. Returns { rel }.
POST/api/sessions/:name/mata-captureCapture the current iOS Simulator frame and save it as a session image. Returns { rel }.

Board

MethodRouteDescription
GET/api/board/cardsList cards. Accepts ?projectId to filter by project.
POST/api/board/cardsCreate a card. Body: { projectId, title, priority, stage, origin }.
PATCH/api/board/cards/:idUpdate a card. Stage changes run through moveCard; other fields use updateCard.
DELETE/api/board/cards/:idDelete a card. Cards with active sessions or worktrees trigger cleanup.
POST/api/board/cards/:id/brainstormSpawn a brainstorm session for the card.
POST/api/board/cards/:id/implementSpawn an implement session in an isolated git worktree.
GET/api/board/cards/:id/branch-diffDiff between the card branch and its base branch (used by the Review column).
POST/api/board/cards/:id/finishMerge, update the changelog, and push (Review to Done). Runs preflightFinish + finishCard.

Projects and files

MethodRouteDescription
GET/api/projectsList all registered projects.
POST/api/projectsRegister a new project. Body: { name, path }.
PATCH/api/projects/:idUpdate project metadata.
DELETE/api/projects/:idRemove a project from the registry.
PATCH/api/projects/:id/itemsToggle a Released/In-Dev checklist item in the project plan document.
POST/api/projects/:id/releaseCut a new release entry in the project CHANGELOG.md.
POST/api/projects/:id/ideagenSpawn an idea-generation session for the project.
GET/api/projects/:id/filesList directory contents. Accepts ?path= for subdirectory.
POST/api/projects/:id/filesCreate a file or directory inside the project.
PATCH/api/projects/:id/filesRename, move, or copy a file within the project.
DELETE/api/projects/:id/filesMove a file to the system trash.
GET/api/projects/:id/files/readRead a file’s contents. Returns text (max 2 MB) or base64 image/PDF (max 10 MB).
GET/api/browseDirectory picker. Accepts ?path= and ?hidden=1. Restricted to $HOME and BROWSE_ROOTS.
POST/api/browse/mkdirCreate a directory anywhere within the allowed browse roots.

Usage

MethodRouteDescription
GET/api/usage/limitsAccount-level rate limits, history, and peaks from the statusline state. Cached for 30 s.
GET/api/usage/costsAggregated costs for all active sessions. Cached for 10 s.
GET/api/usage/historyExtended daily usage aggregate (getDailyUsageV2). Accepts ?days=30.
GET/api/recent-dirsRecency-ranked working directories from moshi-hook.

Hooks

These endpoints are called by Claude Code hook scripts configured by setup.sh. They do not require a human-facing client.

MethodRouteDescription
POST/api/hooks/StopClaude Code Stop hook. Marks the session as idle.
POST/api/hooks/NotificationClaude Code Notification hook. Marks the session as waiting.
POST/api/hooks/UserPromptSubmitClaude Code UserPromptSubmit hook. Marks the session as working.
POST/api/hooks/SubagentStopClaude Code SubagentStop hook. Treated the same as Stop.
POST/api/hooks/SessionStartClaude Code SessionStart hook. Initialises session state.
POST/api/hooks/SessionEndClaude Code SessionEnd hook. Purges session state.
POST/api/hooks/pre-tool-usePreToolUse hook. Routes the call through the approvals gate.
POST/api/hooks/statuslineReceives statusline data (rate limits, cost, context window, model) from the status line script.

All hook routes accept X-Penates-Session as a header to identify the sending session. Malformed JSON payloads are handled gracefully (the endpoint parses opportunistically and falls back to {}).

WebSocket

ProtocolRouteDescription
WS/api/terminal/:nameAttach to a session PTY. Binary frames carry raw PTY bytes; text frames carry JSON control messages. Close code 4004 means the session does not exist; 4001 means authentication failed.
WS/api/files/eventsLive file-change events. Send { subscribe: projectId } or { subscribeSession: name } to start receiving events.

Terminal frame format:

  • Client to server (text, JSON): { type: "input", data }, { type: "resize", cols, rows }, { type: "ping" }.
  • Server to client (binary): raw PTY bytes (UTF-8).
  • Server to client (text, JSON): { type: "error", message }, { type: "pong" }.

Other routes

MethodRouteDescription
GET/POST/api/preview/config, /api/preview/ports, /api/preview/selectBrowser-preview proxy configuration.
GET/POST/api/mata/status, /api/mata/controliOS Simulator (Mata) status and start/stop/restart control.
GET/POST/api/voice/config, /api/voice/transcribeVoice input configuration and WAV transcription.
GET/POST/api/approvals/*PreToolUse approval gate.
GET/POST/api/push/*Web Push subscription management.
GET/POST/api/settingsRead and write server settings (GET / PATCH).
POST/api/server/restartRestart the hub process via the OS service manager.
GET/api/server/logsStream recent log output.
GET/POST/api/updatesList available component updates. Accepts ?refresh=1.
POST/api/updates/:idTrigger an update by spawning a detached tmux session.
GET/POST/api/version, /api/version/checkHub version and GitHub release update check.