Deploys
A Deploy brings up a project's main sandbox, the one behind its Preview. The deploy agent reads the repository, writes the project settings and boots the sandbox. Start one with POST /api/projects/{projectId}/settings/agentic-deploy, answer the agent on the same route with userResponse, and follow it with GET /api/projects/{projectId}/deploy-messages.
| Method | Path | Description |
|---|---|---|
| GET | /api/projects/{projectId}/deploy-messages | Read the deploy conversation and the current deploy status. |
| GET | /api/projects/{projectId}/deploys?page=&pageSize= | List the project's Deploys, newest first: whether a member (user) or the platform (system) started each, its status, error and timestamps, with the total in meta.pagination. |
| POST | /api/projects/{projectId}/settings/agentic-deploy | Start a deploy (empty JSON body) or continue the current one with userResponse. While the deploy agent works, the message waits Up next; while the sandbox builds, it joins the agent's first turn as instructions. Attachments ride along as multipart, where the message is called content. |
| POST | /api/projects/{projectId}/settings/agentic-deploy/cancel | Stop the running deploy. Steers its agent had not taken go back to the top of Up next, which pauses; instructions sent while its sandbox built are discarded and listed. |
| PUT | /api/projects/{projectId}/settings/agentic-deploy/model | Pick the model the deploy agent runs on, as an encoded id such as anthropic:sonnet__medium. Refused while a deploy runs or waits for an answer. |
| GET | /api/projects/{projectId}/settings/agentic-deploy/queue | List the messages waiting Up next in the Deploy Chat, in the order they will be sent, and whether Up next is paused. |
| PATCH | /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId} | Save an edit to your own queued Deploy Chat message, keeping its place in Up next. New files ride along as multipart. |
| DELETE | /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId} | Delete a queued Deploy Chat message: your own, or any as a workspace owner or admin. |
| POST | /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/move | Move your own queued Deploy Chat message to another place in Up next. |
| POST | /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/send | Send your own queued Deploy Chat message now, ahead of the rest of Up next. Only while the deploy agent is idle; it resumes a paused Up next. |
| POST | /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/steer | Send your own queued Deploy Chat message into the running deploy agent Turn as a steer. Claude deploys only; the message stays queued when nothing can take it. |
| POST | /api/projects/{projectId}/settings/agentic-deploy/queue/resume | Resume the Deploy Chat's paused Up next. Its top message is sent as soon as the deploy is idle. |
Any member of the workspace can call these routes. A Deploy runs on the workspace's Credentials, and the deploy agent needs Anthropic or OpenAI ones. What a Deploy does in the web app, and what to do when one fails, is on Deploy your project.
Start a Deploy
Send the request with an empty body. It starts a new Deploy and stops any Deploy already running. The web app's Redeploy sends the same request, but only when nothing runs or the agent is waiting on a Clarification.
curl -s -X POST https://app.kosuke.ai/api/projects/$PROJECT_ID/settings/agentic-deploy \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"delivery": "job",
"status": "creating_sandbox",
"deployJobId": "c7e2a9d4-5b1f-4e8a-9c3d-2f6b0a1e4d87"
}
}
To give a project's first Deploy instructions, send them with freshDeploy. This starts a new Deploy only on a project that has never deployed.
| Body field | Meaning |
|---|---|
userResponse | Your message to the deploy agent. |
freshDeploy | true starts the first Deploy with userResponse as its instructions. |
runningDeployJobId | The deployJobId you saw running. See Answer the deploy agent. |
curl -s https://app.kosuke.ai/api/projects/$PROJECT_ID/settings/agentic-deploy \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
--json '{ "userResponse": "The API lives in apps/api and needs Redis.", "freshDeploy": true }'
To attach files, send the request as multipart/form-data. The message goes in a content field next to the files. A multipart request always needs content.
When the workspace has no usable Anthropic or OpenAI Credentials, the Deploy starts and then fails, and its error says so.
In the CLI, run kosuke deploy run <projectId>. Add --user-response "..." --fresh-deploy for instructions. To attach files, pass the message as --content "..." and add --attach <path> for each file.
Follow a Deploy
Read the Deploy Chat and the current state.
curl -s https://app.kosuke.ai/api/projects/$PROJECT_ID/deploy-messages \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"status": "running_agent",
"deployJobId": "c7e2a9d4-5b1f-4e8a-9c3d-2f6b0a1e4d87",
"activeStreamId": "d9f1b3c5-7e2a-4d6b-8a0c-1e3f5a7b9c2d",
"lastStreamId": "d9f1b3c5-7e2a-4d6b-8a0c-1e3f5a7b9c2d",
"error": null,
"deploySandboxId": "i8k2m4p6r9t1v3x5z7b0d",
"deployModel": "anthropic:opus__xhigh",
"credentialOwners": {
"anthropic": { "kind": "organization", "needsReauth": false, "authMethod": "api_key" },
"openai": null,
"zai": null,
"moonshot": null
},
"messages": [
{
"id": "0e4c8a2f-6b1d-4f3e-9a5c-7d2b1e0f8a36",
"deployJobId": "c7e2a9d4-5b1f-4e8a-9c3d-2f6b0a1e4d87",
"role": "user",
"content": "deploy my project",
"attachments": [],
"author": {
"userId": "u8Rk2mQ4xT7vB1nP9sL3cW6yD0fH5jZa",
"name": "Sam Rivera",
"email": "sam@acme.com",
"imageUrl": null
},
"createdAt": "2026-09-30T10:02:11.000Z"
}
]
}
}
messages starts at the project's most recent Deploy a member started, and includes the Recovery Deploys Kosuke started after it. role is user, assistant or system.
status | Meaning |
|---|---|
idle | The project has no Deploy yet. |
creating_sandbox | Kosuke is creating a fresh sandbox. |
starting_services | The services are starting, and Kosuke waits for them to be healthy. |
running_agent | The deploy agent is setting up and checking the project. |
updating | The deploy agent is working on the live project. |
awaiting_user | The deploy agent asked a Clarification. Answer it with userResponse. |
warming | Kosuke loads pages so the sandbox starts with a warm cache. |
promoting | Kosuke runs final checks and makes the new sandbox live. |
warming_pool | Kosuke prepares spare sandboxes so new sessions start fast. |
deployed | The project is live. |
failed | The Deploy failed. error says why. |
cancelled | The Deploy was stopped: by a member, by a newer Deploy that replaced it, or by Kosuke when it could not run. When Kosuke stopped it, error says why. |
To stream the running turn instead of polling, pass activeStreamId to the CLI. The session id argument is not read for a Deploy, so any value works there:
kosuke sessions watch <projectId> _ <activeStreamId> --type deploy
How to poll well is on Follow a turn. In the CLI, the read above is kosuke deploy messages <projectId>.
Answer the deploy agent
When status is awaiting_user, the agent is waiting for you. Send your answer as userResponse.
curl -s https://app.kosuke.ai/api/projects/$PROJECT_ID/settings/agentic-deploy \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
--json '{
"userResponse": "Use a Stripe test key. I added STRIPE_SECRET_KEY as a secret.",
"runningDeployJobId": "c7e2a9d4-5b1f-4e8a-9c3d-2f6b0a1e4d87"
}'
Always send the message as userResponse. A JSON body without userResponse starts a new Deploy and stops the running one. That includes a body that carries the message in content, which only multipart requests read.
Pass the deployJobId you saw as runningDeployJobId. If someone stopped that Deploy before your message arrived, the call answers 409 JOB_STOPPED instead of starting over.
The same route takes any message for the deploy agent. What happens depends on where the Deploy is:
| When you send | What happens | Answer |
|---|---|---|
The agent is working (running_agent or updating) | The message waits Up next and starts the next turn. | 201, delivery: "queued" with a queuedMessageId |
The sandbox is still building (creating_sandbox, starting_services, warming or promoting) | The message joins the agent's first turn as instructions. | delivery: "steer" |
The agent asked a Clarification (awaiting_user) | Your answer continues the Deploy. It may carry files. | delivery: "job" |
| The project is deployed and nothing runs | The agent starts a new turn on the live project. | delivery: "job", status: "updating" |
| You stopped the project's first Deploy | The Deploy resumes where it stopped. | delivery: "job" |
| The project has no main sandbox (it never deployed, or its main sandbox was reclaimed) and nothing runs | Refused with 409 NOT_DEPLOYED. Start a Deploy first. |
In the CLI, run kosuke deploy run <projectId> --user-response "..." --running-deploy-job-id <deployJobId>.
Stop a Deploy
Stop the running Deploy.
curl -s -X POST https://app.kosuke.ai/api/projects/$PROJECT_ID/settings/agentic-deploy/cancel \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{ "data": { "cancelled": 1, "discardedInstructionIds": [], "discardedInstructions": [] } }
After a stop, messages you steered that the agent had not taken go back to the top of Up next, and Up next pauses. Instructions sent while the sandbox was building are dropped and returned in discardedInstructions. A stopped first Deploy keeps its sandbox, so your next message resumes it. With nothing running, cancelled is 0.
In the CLI, run kosuke deploy cancel <projectId>.
Pick the deploy model
Choose the model the deploy agent runs on. Take a value from Models.
| Body field | Meaning |
|---|---|
model | An Anthropic or OpenAI model, such as openai:gpt-6.1-sol__high. The workspace needs Credentials for that provider. |
curl -s -X PUT https://app.kosuke.ai/api/projects/$PROJECT_ID/settings/agentic-deploy/model \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
--json '{ "model": "openai:gpt-6.1-sol__high" }'
{ "data": { "deployModel": "openai:gpt-6.1-sol__high" } }
Change the model between Deploys. While a Deploy runs or waits for an answer, the route answers 400. Switching to another provider starts the agent's next turn fresh, with the conversation so far handed over as text. When no model is saved, the deploy agent runs on anthropic:opus__xhigh, or on openai:gpt-6-astra__high when the workspace has only OpenAI Credentials. deployModel in the Deploy Chat response shows the current one. If the workspace loses the Credentials for the saved model's provider, pick another model before the next Deploy.
In the CLI, run kosuke deploy set-model <projectId> --model openai:gpt-6.1-sol__high.
Up next
A message sent while the deploy agent works waits Up next, as in a chat session. Up next holds at most 20 messages. It pauses when a Deploy fails, is stopped, or ends on a Clarification.
curl -s https://app.kosuke.ai/api/projects/$PROJECT_ID/settings/agentic-deploy/queue \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"messages": [
{
"id": "4b7d1f3a-9e2c-4a5b-8d6f-0c1e2a3b4c5d",
"content": "Also seed the database with the demo fixtures.",
"position": 0,
"author": {
"userId": "u8Rk2mQ4xT7vB1nP9sL3cW6yD0fH5jZa",
"name": "Sam Rivera",
"email": "sam@acme.com",
"imageUrl": null
},
"attachments": [],
"context": {},
"editingBy": null,
"can": { "edit": true, "move": true, "steer": true, "delete": true },
"createdAt": "2026-09-30T10:06:40.000Z"
}
],
"paused": null
}
}
can says what you may do with each message. paused is null, or holds the reason and pausedAt.
| Route | What it does | Who |
|---|---|---|
PATCH /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId} | Saves new content and keeps its place. List the files to keep in retainedAttachmentIds. Answers 204. | Its author |
DELETE /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId} | Deletes the message. Answers 204. | Its author, or a workspace owner or admin |
POST /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/move | Moves it to toIndex, counted from the top. Answers 204. | Its author |
POST /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/steer | Sends it into the running turn as a steer. Works only when the deploy model is a Claude model. | Its author |
POST /api/projects/{projectId}/settings/agentic-deploy/queue/resume | Resumes a paused Up next. Its top message goes as soon as no Deploy is running, or at once as the answer when the agent is waiting on a Clarification. Answers 204. | Any member |
A steer the running turn cannot take answers 409 STEER_UNAVAILABLE, and the message stays Up next.
In the CLI, the commands are kosuke deploy queue list, update, delete, move, send, steer and resume.
Read past Deploys
List the project's Deploys, newest first.
| Query parameter | Meaning |
|---|---|
page | Page number, from 1. Default 1. |
pageSize | Deploys per page. Default 25. Values above 100 are read as 100. |
curl -s "https://app.kosuke.ai/api/projects/$PROJECT_ID/deploys?pageSize=10" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": [
{
"id": "c7e2a9d4-5b1f-4e8a-9c3d-2f6b0a1e4d87",
"trigger": "user",
"status": "deployed",
"error": null,
"createdAt": "2026-09-30T10:02:10.000Z",
"startedAt": "2026-09-30T10:02:12.000Z",
"completedAt": "2026-09-30T10:09:51.000Z"
}
],
"meta": { "pagination": { "page": 1, "totalPages": 3, "pageSize": 10, "total": 24, "hasMore": true } }
}
trigger is user for a Deploy a member started and system for a Recovery Deploy. status takes the values in Follow a Deploy.
In the CLI, run kosuke deploy list <projectId> --page-size 10.
Errors
| Status | Code | When |
|---|---|---|
| 400 | BAD_REQUEST | The message is empty, a file is refused, or the model is refused. A model change while a Deploy runs is refused too. |
| 402 | CREDIT_LIMIT_REACHED | The workspace is blocked on billing. |
| 403 | FORBIDDEN | You changed a queued message you did not write. |
| 404 | NOT_FOUND | No such project or queued message. |
| 409 | DEPLOY_ACTIVE | A Deploy is already running, or still stopping. |
| 409 | JOB_STOPPED | The Deploy you named in runningDeployJobId was stopped. |
| 409 | NOT_DEPLOYED | The project has no main sandbox, because it never deployed or its main sandbox was reclaimed. Start a Deploy. |
| 409 | DEPLOY_RESUME_UNAVAILABLE | The stopped Deploy cannot resume. Start a new one. |
| 409 | QUEUE_FULL | Up next already holds 20 messages. |
| 409 | STEER_UNAVAILABLE | No turn can take the steer right now. The message stays Up next. |
| 409 | JOB_STOPPED_TEXT_RETURNED | The turn you steered into was stopped before it took the message. The message stays Up next. |
| 409 | QUEUED_MESSAGE_CHANGED | The message changed or was sent while you edited it. Read Up next again before you save. |
| 409 | QUEUED_MESSAGE_GONE | The message already left Up next. It was sent or deleted. |
The full list is in Responses and errors.
Next steps
- Change what the agent wrote with Project settings.
- Learn how Deploys work in the web app on Deploy your project.