Agent: Workspace Sessions
Section titled “Agent: Workspace Sessions”These workspace-scoped session endpoints operate on a specific session within a workspace, providing session inspection, autonomous loop control, background job management, and CLI agent run capabilities. All endpoints require a workspaceID and sessionID in the path. Streaming endpoints return text/event-stream; the rest return JSON.
Session Inspection
Section titled “Session Inspection”Inspect the runtime state of a session: effective permission rulesets, individual tool-call results, and live message updates.
GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/permissions
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/permissions”Return the static merged ruleset that PermissionNext.ask() passes to evaluate() at tool-invocation time. Tool dispatch merges agent.permission with session.permission — not raw config.permission — because each agent definition pre-bakes defaults, YOLO overrides, agent-specific rules, and user cfg.permission into its own ruleset. The response includes the resolved agent name, the agent’s pre-baked agentRuleset, the session-scoped sessionRuleset, and the effective ruleset (the exact array passed to PermissionNext.evaluate() with last-match-wins semantics).
This endpoint reflects the persisted ruleset only. Transient "always" approvals from PermissionNext.reply that have not yet been written to session.permission are NOT included. Pass ?agent= to inspect the ruleset under a non-default agent.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier (project ID or workspace entry ID; 24-char lowercase hex) |
sessionID | path | string | Yes | Session identifier |
agent | query | string | No | Agent name to evaluate the ruleset under (defaults to the configured default agent or build) |
curl -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/permissions?agent=build" \ -H "Authorization: Bearer <token>"const result = await client.agent.workspaceSession.sessionsGetPermissions({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", agent: "build",});Response
Section titled “Response”{ "agent": "build", "agentRuleset": [ { "permission": "bash", "pattern": "*", "action": "allow" } ], "sessionRuleset": [ { "permission": "bash", "pattern": "rm -rf *", "action": "deny" } ], "effective": [ { "permission": "bash", "pattern": "rm -rf *", "action": "deny" }, { "permission": "bash", "pattern": "*", "action": "allow" } ]}{ "name": "NotFoundError", "data": { "message": "Session not found" }}GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/messages/{messageID}/tools/{callID}
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/messages/{messageID}/tools/{callID}”Return the ToolPart on a message that matches callID — without forcing the SDK consumer to fetch and scan the full message. Returns 404 if the message does not belong to this session, the message is missing, or the message has no ToolPart with that callID.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier (project ID or workspace entry ID; 24-char lowercase hex) |
sessionID | path | string | Yes | Session identifier |
messageID | path | string | Yes | Message identifier |
callID | path | string | Yes | Tool-call ID |
curl -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/messages/msg_01HXYZABCDEFGHJKMNPQRSTVW/tools/call_01HXYZABCDEFGHJKMNPQRSTVW" \ -H "Authorization: Bearer <token>"const part = await client.agent.workspaceSession.sessionsGetToolCall({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", messageID: "msg_01HXYZABCDEFGHJKMNPQRSTVW", callID: "call_01HXYZABCDEFGHJKMNPQRSTVW",});Response
Section titled “Response”{ "id": "prt_01HXYZABCDEFGHJKMNPQRSTVW", "sessionID": "sess_01HXYZABCDEFGHJKMNPQRSTVW", "messageID": "msg_01HXYZABCDEFGHJKMNPQRSTVW", "type": "tool", "callID": "call_01HXYZABCDEFGHJKMNPQRSTVW", "tool": "bash", "state": { "status": "completed", "input": { "command": "ls -la" }, "output": "total 12\ndrwxr-xr-x 3 user user 4096 ...\n", "title": "List directory", "metadata": {}, "time": { "start": 1700000000000, "end": 1700000000100 } }, "metadata": {}}{ "name": "NotFoundError", "data": { "message": "Tool call not found for this message" }}GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/messages/{messageID}/stream
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/messages/{messageID}/stream”Server-Sent Events stream of MessageV2 updates scoped to a single (sessionID, messageID). The server emits a snapshot event first with the current message and parts, then part.updated, part.removed, message.updated, and message.removed events as they happen on the bus. Heartbeats arrive every 30 seconds. The stream closes automatically once the assistant message becomes terminal (message.time.completed is set), sending a done event with the final message info just before close. Returns 404 if the message is missing in this session.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier (project ID or workspace entry ID; 24-char lowercase hex) |
sessionID | path | string | Yes | Session identifier |
messageID | path | string | Yes | Message identifier |
curl -N -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/messages/msg_01HXYZABCDEFGHJKMNPQRSTVW/stream" \ -H "Authorization: Bearer <token>" \ -H "Accept: text/event-stream"const stream = await client.agent.workspaceSession.sessionsStreamMessage({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", messageID: "msg_01HXYZABCDEFGHJKMNPQRSTVW",});
for await (const event of stream) { console.log(event.type, event);}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: text/event-stream
event: snapshotdata: {"type":"snapshot","message":{"id":"msg_01HXYZ...","role":"assistant","time":{"created":1700000000000}},"parts":[]}
event: part.updateddata: {"type":"part.updated","part":{"id":"prt_01HX...","type":"text","text":"Let me think..."}}
event: donedata: {"type":"done","message":{"id":"msg_01HXYZ...","time":{"completed":1700000005000}}}{ "name": "NotFoundError", "data": { "message": "Message not found in this session" }}Autonomous Loop
Section titled “Autonomous Loop”Drive the session’s prompt loop as a repeating directive. While a loop is active, the frontend disables the chat input.
GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/loop
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/loop”Return the active loop directive for the session, or null if no loop is active.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier (project ID or workspace entry ID; 24-char lowercase hex) |
sessionID | path | string | Yes | Session identifier |
curl -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/loop" \ -H "Authorization: Bearer <token>"const loop = await client.agent.workspaceSession.sessionsLoopPeek({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW",});Response
Section titled “Response”{ "prompt": "Run the test suite and fix any failures.", "iters": 5, "iter": 1, "started_at": 1700000000000, "launch_id": "launch_01HXYZABCDEFGHJKMNPQRSTVW", "agent": "build", "model": { "providerID": "anthropic", "modelID": "claude-3-5-sonnet-20241022" }, "system": "You are a careful engineer."}When no loop is active, the response is the JSON literal null.
{ "name": "NotFoundError", "data": { "message": "Session not found" }}POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/loop
Section titled “POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/loop”Install a loop directive on the session. The session re-enters its prompt loop for iters iterations, synthesizing the same prompt as the user turn each iteration. Stop with DELETE /loop. Returns 409 if a loop is already active or the session is busy.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier (project ID or workspace entry ID; 24-char lowercase hex) |
sessionID | path | string | Yes | Session identifier |
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Loop prompt (1–8000 chars) |
iters | integer | Yes | Total iterations (1–100) |
curl -X POST "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/loop" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Run the test suite and fix any failures.", "iters": 5 }'const loop = await client.agent.workspaceSession.sessionsLoopInstall({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", data: { prompt: "Run the test suite and fix any failures.", iters: 5, },});Response
Section titled “Response”{ "prompt": "Run the test suite and fix any failures.", "iters": 5, "iter": 0, "started_at": 1700000000000, "launch_id": "launch_01HXYZABCDEFGHJKMNPQRSTVW", "agent": "build", "model": { "providerID": "anthropic", "modelID": "claude-3-5-sonnet-20241022" }, "system": "You are a careful engineer."}{ "data": {}, "errors": [ { "field": "iters", "message": "Must be between 1 and 100" } ], "success": false}{ "name": "NotFoundError", "data": { "message": "Session not found" }}{ "error": "A loop is already active on this session", "code": "loop_already_active"}DELETE /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/loop
Section titled “DELETE /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/loop”Clear the loop directive AND cancel the running prompt. Idempotent — safe to call when no loop is active.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier (project ID or workspace entry ID; 24-char lowercase hex) |
sessionID | path | string | Yes | Session identifier |
curl -X DELETE "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/loop" \ -H "Authorization: Bearer <token>"const cleared = await client.agent.workspaceSession.sessionsLoopClear({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW",});Response
Section titled “Response”true{ "name": "NotFoundError", "data": { "message": "Session not found" }}Background Jobs
Section titled “Background Jobs”Manage background jobs created on a session — RSI, self-tuning, cli_agent, bash, webfetch. Jobs run with a wakePolicy (when the result is delivered back into the conversation) and a durability (how long they are kept).
GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs”Return background jobs created on this session. Filter by status with ?status=active|completed|all. Paginate with ?limit&cursor — when limit is set and more results exist after the page, the response includes nextCursor (use it as cursor on the next call). Jobs are sorted ascending by creation time, so nextCursor resumes after the last seen job ID.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | string | No | Status filter. Allowed values: active, completed, all. Default: "all". |
limit | query | integer | No | Max jobs to return per page. Defaults to no cap (returns the full filtered set). |
cursor | query | string | No | Pagination cursor. Pass the previous response’s nextCursor to fetch the next page. |
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
curl -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/jobs?status=all&limit=20" \ -H "Authorization: Bearer <token>"const page = await client.agent.workspaceSession.sessionsJobsList({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", status: "all", limit: 20,});Response
Section titled “Response”{ "jobs": [ { "id": "job_01HXYZABCDEFGHJKMNPQRSTVW", "sessionID": "sess_01HXYZABCDEFGHJKMNPQRSTVW", "messageID": "msg_01HXYZABCDEFGHJKMNPQRSTVW", "callID": "call_01HXYZABCDEFGHJKMNPQRSTVW", "tool": "bash", "status": "completed", "input": { "command": "npm test" }, "progress": { "message": "Running tests...", "percent": 75 }, "output": "All tests passed.", "fullOutput": "All tests passed.\n", "attachments": [ { "mime": "text/plain", "url": "https://files.hoody.com/..." } ], "metadata": {}, "time": { "created": 1700000000000, "started": 1700000000050, "completed": 1700000005000 }, "wakePolicy": "auto", "durability": "session", "groupID": "grp_01HXYZABCDEFGHJKMNPQRSTVW", "timeout": 60000, "retries": { "max": 2, "count": 0 }, "completionProcessed": true, "parentJobId": null, "childJobIds": [], "totalChildren": 0, "finishedChildJobIds": [] } ], "nextCursor": "job_01HXYZABCDEFGHJKMNPQRSTVW"}GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}”Fetch a single job’s full info: status, progress, output, error, timing. Use this to poll a job started by RSI, self-tuning, or cli_agent if the SSE stream is unavailable.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
jobId | path | string | Yes | Job identifier |
curl -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/jobs/job_01HXYZABCDEFGHJKMNPQRSTVW" \ -H "Authorization: Bearer <token>"const job = await client.agent.workspaceSession.sessionsJobsGet({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", jobId: "job_01HXYZABCDEFGHJKMNPQRSTVW",});Response
Section titled “Response”{ "id": "job_01HXYZABCDEFGHJKMNPQRSTVW", "sessionID": "sess_01HXYZABCDEFGHJKMNPQRSTVW", "messageID": "msg_01HXYZABCDEFGHJKMNPQRSTVW", "callID": "call_01HXYZABCDEFGHJKMNPQRSTVW", "tool": "bash", "status": "running", "input": { "command": "npm test" }, "progress": { "message": "Running test suite...", "percent": 42 }, "output": "Test 1 passed\nTest 2 passed\n", "fullOutput": "Test 1 passed\nTest 2 passed\nTest 3 running...\n", "metadata": {}, "time": { "created": 1700000000000, "started": 1700000000050 }, "wakePolicy": "auto", "durability": "session", "timeout": 60000, "retries": { "max": 2, "count": 0 }, "completionProcessed": false}GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}/output
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}/output”Return the complete output buffer of a background job. Job.Info.output may be truncated for index payloads; this endpoint returns the full uncapped output.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
jobId | path | string | Yes | Job identifier |
curl -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/jobs/job_01HXYZABCDEFGHJKMNPQRSTVW/output" \ -H "Authorization: Bearer <token>"const result = await client.agent.workspaceSession.sessionsJobsGetOutput({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", jobId: "job_01HXYZABCDEFGHJKMNPQRSTVW",});Response
Section titled “Response”{ "output": "Test 1 passed\nTest 2 passed\nTest 3 passed\nTest 4 passed\nAll tests passed.\n"}POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}/cancel
Section titled “POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}/cancel”Request cancellation of a running background job. Already-terminal jobs are returned with their existing status; running jobs are signalled to stop.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | workspaceID path parameter |
sessionID | path | string | Yes | sessionID path parameter |
jobId | path | string | Yes | jobId path parameter |
curl -X POST "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/jobs/job_01HXYZABCDEFGHJKMNPQRSTVW/cancel" \ -H "Authorization: Bearer <token>"const result = await client.agent.workspaceSession.sessionsJobsCancel({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", jobId: "job_01HXYZABCDEFGHJKMNPQRSTVW",});Response
Section titled “Response”{ "job": { "id": "job_01HXYZABCDEFGHJKMNPQRSTVW", "sessionID": "sess_01HXYZABCDEFGHJKMNPQRSTVW", "messageID": "msg_01HXYZABCDEFGHJKMNPQRSTVW", "callID": "call_01HXYZABCDEFGHJKMNPQRSTVW", "tool": "bash", "status": "cancelled", "input": { "command": "npm test" }, "time": { "created": 1700000000000, "started": 1700000000050, "completed": 1700000005000 }, "wakePolicy": "auto", "durability": "session", "timeout": 60000, "retries": { "max": 2, "count": 0 }, "completionProcessed": false }, "message": "Job cancelled"}POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/cancel
Section titled “POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/cancel”Bulk-cancel a set of jobs in one call. Each ID is processed independently — unknown IDs and any other per-job errors are reported in failed[] rather than aborting the batch. Already-terminal jobs are reported in failed[] with reason already_terminal. Returns 200 even when every job fails — inspect cancelled and failed to interpret the outcome.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
jobIds | array of string | Yes | Job IDs to cancel. Minimum 1, maximum 1000 per call. Unknown IDs are reported in failed, not 404. |
curl -X POST "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/jobs/cancel" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "jobIds": [ "job_01HXYZABCDEFGHJKMNPQRSTVW", "job_02HXYZABCDEFGHJKMNPQRSTVW", "job_03HXYZABCDEFGHJKMNPQRSTVW" ] }'const result = await client.agent.workspaceSession.sessionsJobsCancelBulk({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", data: { jobIds: [ "job_01HXYZABCDEFGHJKMNPQRSTVW", "job_02HXYZABCDEFGHJKMNPQRSTVW", "job_03HXYZABCDEFGHJKMNPQRSTVW", ], },});Response
Section titled “Response”{ "cancelled": 2, "failed": [ { "jobId": "job_03HXYZABCDEFGHJKMNPQRSTVW", "reason": "already_terminal" } ]}POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}/retry
Section titled “POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/{jobId}/retry”Re-run a job that ended in a non-success terminal state. Only failed, expired, and cancelled jobs are eligible; completed jobs return 409. Child jobs (those with parentJobId) cannot be retried in isolation — retry the top-level parent instead. The retry creates a NEW job with a new ID, copying the original tool, input, messageID, callID, wakePolicy, durability, and timeout. The original job record is left intact for audit.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
jobId | path | string | Yes | Job identifier |
curl -X POST "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/jobs/job_01HXYZABCDEFGHJKMNPQRSTVW/retry" \ -H "Authorization: Bearer <token>"const result = await client.agent.workspaceSession.sessionsJobsRetry({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", jobId: "job_01HXYZABCDEFGHJKMNPQRSTVW",});Response
Section titled “Response”{ "jobID": "job_02HXYZABCDEFGHJKMNPQRSTVW", "sessionID": "sess_01HXYZABCDEFGHJKMNPQRSTVW", "status": "queued", "retriedFrom": "job_01HXYZABCDEFGHJKMNPQRSTVW"}{ "error": "Job not found", "message": "No job with id job_01HXYZABCDEFGHJKMNPQRSTVW in this session"}{ "error": "Job is not in a retryable terminal state", "message": "Only failed, expired, or cancelled jobs can be retried. Current status: completed"}{ "error": "Tool factory no longer registered", "message": "Cannot retry: the tool that produced this job is no longer available"}{ "error": "Job is a child of another job", "message": "Retry the parent job (job_01HXYZABCDEFGHJKMNPQRSTVW) instead of this child"}POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/inject
Section titled “POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/jobs/inject”Mirror the agent prompt-loop’s own injection step: pull terminal, unprocessed jobs and attach summary parts to the last user message (or mint one if none). Pass jobIds: [...] to inject a specific subset; pass jobIds: [] to inject nothing explicitly; omit the field to drain all manual-policy unprocessed jobs. Returns 409 if the prompt loop is active.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
jobIds | array of string | No | Optional subset of job IDs to inject. Omit the field to drain all manual-policy unprocessed jobs. Pass [] to explicitly inject nothing. Max 1000 IDs per call. |
curl -X POST "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/jobs/inject" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "jobIds": [ "job_01HXYZABCDEFGHJKMNPQRSTVW", "job_02HXYZABCDEFGHJKMNPQRSTVW" ] }'const result = await client.agent.workspaceSession.sessionsJobsInject({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", data: { jobIds: [ "job_01HXYZABCDEFGHJKMNPQRSTVW", "job_02HXYZABCDEFGHJKMNPQRSTVW", ], },});Response
Section titled “Response”{ "injected": 2, "failed": 0, "message": "Injected 2 job result(s) into session context"}{ "error": "Session prompt loop is active", "code": "loop_already_active"}CLI Agent
Section titled “CLI Agent”Spawn and stream an external CLI agent (gemini, codex, claude) as a side job on a session. The session’s existing prompt loop is untouched — CLI agent runs are independent and their results can later be injected via POST /jobs/inject.
POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/cli-agent
Section titled “POST /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/cli-agent”Run an external CLI agent against the session’s working directory in the background. Returns a queued jobID; subscribe to /cli-agent/runs/{jobID}/stream for progress and final output.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
Request Body
Section titled “Request Body”| Name | Type | Required | Description |
|---|---|---|---|
agent | string | Yes | Configured CLI agent name (case-insensitive). e.g. Gemini Flash, Codex. |
prompt | string | Yes | Prompt to send to the CLI agent. Max 100K chars. |
model | string | No | Override the agent’s default model. |
git | boolean | No | Request git access (only honoured if agent’s allow_git is true, or codex-rw). |
timeout | integer | No | Override timeout in ms; clamped to the agent’s configured ceiling. |
curl -X POST "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/cli-agent" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "agent": "Codex", "prompt": "Investigate the failing login test and propose a fix.", "model": "gpt-4o", "git": false, "timeout": 300000 }'const run = await client.agent.workspaceSession.sessionsCliAgentStart({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", data: { agent: "Codex", prompt: "Investigate the failing login test and propose a fix.", model: "gpt-4o", git: false, timeout: 300000, },});Response
Section titled “Response”{ "jobID": "job_01HXYZABCDEFGHJKMNPQRSTVW", "sessionID": "sess_01HXYZABCDEFGHJKMNPQRSTVW", "status": "queued"}GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/cli-agent/runs/{jobID}/stream
Section titled “GET /api/v1/workspaces/{workspaceID}/sessions/{sessionID}/cli-agent/runs/{jobID}/stream”Server-Sent Events stream of progress events for a CLI agent job. The server emits a snapshot first (so late subscribers see the current state), then live events; if the job is already terminal, it emits the completion event and closes.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
sessionID | path | string | Yes | Session identifier |
jobID | path | string | Yes | CLI agent job identifier |
curl -N -X GET "https://api.hoody.com/api/v1/workspaces/5f9b3a2e1c8d4f7b6a5e3d2c/sessions/sess_01HXYZABCDEFGHJKMNPQRSTVW/cli-agent/runs/job_01HXYZABCDEFGHJKMNPQRSTVW/stream" \ -H "Authorization: Bearer <token>" \ -H "Accept: text/event-stream"const stream = await client.agent.workspaceSession.sessionsCliAgentStream({ workspaceID: "5f9b3a2e1c8d4f7b6a5e3d2c", sessionID: "sess_01HXYZABCDEFGHJKMNPQRSTVW", jobID: "job_01HXYZABCDEFGHJKMNPQRSTVW",});
for await (const event of stream) { console.log(event.type, event);}Response
Section titled “Response”HTTP/1.1 200 OKContent-Type: text/event-stream
event: snapshotdata: {"type":"snapshot","job":{"id":"job_01H...","status":"running","progress":{"message":"Reading files...","percent":20}}}
event: progressdata: {"type":"progress","message":"Analyzing test output","percent":55}
event: completedata: {"type":"complete","job":{"id":"job_01H...","status":"completed","output":"Found the issue: ..."}}