Skip to main content

Deploys

A Deploy brings up a project's main sandbox. 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.

Deploy Chat sends and queued-message edits use the same attachment transport as chat sessions: up to 20 files, each at most 10 MiB (10,485,760 bytes). The CLI stages batches larger than 20 MiB through the operation's advertised project attachment endpoint, preserving the original order, then sends opaque references in the ordinary multipart attachment slots. Smaller batches stay inline.

MethodPathDescription
GET/api/projects/{projectId}/deploy-messages?limit=&before=&from=Read the deploy conversation, from the user's latest deploy on, oldest first, and the current deploy status: the whole of it, its last limit messages, the page before an olderCursor, or everything from one; newestCursor is what a poll passes as from to read only what changed since. messageCount counts the whole conversation. Blocks come as stored. In a message recorded since previews were stored, a tool call's input keeps its short fields (inputCompacted when cut), a result over 500 characters its first 500 (resultCompacted), and a subagent its last output entry with outputCount (outputOmitted when cut). kosuke deploys messages get reads one message whole.
GET/api/projects/{projectId}/deploy-messages/{messageId}?agentOutput=Read one message of the deploy conversation with every block as recorded: whole tool inputs, results and subagent output, unless agentOutput is compact (subagent output as stored) or summary (blocks as stored).
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-deployStart 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/cancelStop 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/modelPick 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/queueList 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}/moveMove your own queued Deploy Chat message to another place in Up next.
POST/api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/sendSend 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}/steerSend your own queued Deploy Chat message into the running deploy agent Turn as a steer, on any deploy model whose runtime takes one; the message stays queued when nothing can take it.
POST/api/projects/{projectId}/settings/agentic-deploy/queue/resumeResume 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 workspace Deploy uses workspace Credentials only. A personal-project Deploy uses the owner's Subscriptions, or Sensei free when they hold none. What a Deploy does in the web app, and what to do when one fails, is on Deploy your project.

Start a Deploy​

Creating a project starts its first Deploy, so a new project needs no request here. See Projects. If that Deploy fails, Sensei starts one Recovery Deploy of it.

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 fieldMeaning
userResponseYour message to the deploy agent.
freshDeploytrue starts the first Deploy with userResponse as its instructions.
runningDeployJobIdThe 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 nothing can run the deploy model, the Deploy starts and then fails. In a workspace project its error reads "The workspace has no usable credentials for the Deploy model. Ask a workspace admin to reconnect its provider in Workspace AI Providers or change the Deploy model setting." A Deploy nobody pressed, such as an import's first Deploy, is skipped instead, and its error starts with "Deploy skipped:". A workspace Deploy never runs on a member's Subscription or on Sensei free. In a personal project the Deploy runs on the owner's chosen Deploy model, or else on the first connected provider in catalog order and its catalog default model, and fails with "The owner's selected Deploy model cannot run on their personal subscriptions." when that choice cannot run: limits, reconnects and failures never move it to Free. Connecting the first Subscription moves a Free Deploy to the provider's catalog default model from its next turn; removing the last moves its choice to Free. A running turn keeps its source.

A Free Deploy works like a personal Subscription, within the Free allowance and staff maximum Turn Level. Sensei picks one Source for the Deploy and moves it automatically if that Source reaches its limit, is paused or is removed. Its model, Source and provider stay hidden.

In the CLI, run kosuke deploys start <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,
"deepseek": 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": "[email protected]",
"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 Sensei started after it. role is user, assistant or system.

Each message's blocks come as stored. A message recorded since previews were stored has them cut the way a chat session's messages are, as Read one session describes. There, inputCompacted and resultCompacted mark only an input or result that was cut. outputOmitted marks only a subagent with more than one entry, or a long one. GET /api/projects/{projectId}/deploy-messages/{messageId} returns one message with every block as recorded, results whole. Its agentOutput is full by default. compact returns whole inputs and results, with subagent output as the list returns it, and summary the blocks as stored. In the CLI, run kosuke deploys messages get <projectId> <messageId>.

statusMeaning
idleThe project has no Deploy yet.
creating_sandboxSensei is creating a fresh sandbox.
starting_servicesThe services are starting, and Sensei waits for them to be healthy.
running_agentThe deploy agent is setting up and checking the project.
updatingThe deploy agent is working on the live project.
awaiting_userThe deploy agent asked a Clarification. Answer it with userResponse.
warmingSensei loads pages so the sandbox starts with a warm cache.
promotingSensei runs final checks and makes the new sandbox live.
warming_poolSensei prepares spare sandboxes so new tasks start fast.
deployedThe project is live.
failedThe Deploy failed. error says why.
cancelledThe Deploy was stopped: by a member, by a newer Deploy that replaced it, or by Sensei when it could not run. When Sensei 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 jobs watch <projectId> _ <activeStreamId> --type deploy

How to poll well is on Follow a turn. In the CLI, the read above is kosuke deploys messages list <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"
}'
warning

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 sendWhat happensAnswer
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 runsThe agent starts a new turn on the live project.delivery: "job", status: "updating"
You stopped the project's first DeployThe Deploy resumes where it stopped.delivery: "job"
The project has no main sandbox (it never deployed, or its main sandbox was reclaimed) and nothing runsRefused with 409 NOT_DEPLOYED. Start a Deploy first.

In the CLI, run kosuke deploys start <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 deploys cancel <projectId>.

Pick the deploy model​

Choose the model the deploy agent runs on. Take a value from Models.

Body fieldMeaning
modelA model of any provider, 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. Without Anthropic it runs on openai:gpt-6-astra__high, then on zai:glm-5.3__high, moonshot:k3__high and deepseek:deepseek-flash__high, in that order. 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 deploys model set <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": "[email protected]",
"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.

RouteWhat it doesWho
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}/moveMoves it to toIndex, counted from the top. Answers 204.Its author
POST /api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/steerSends it into the running turn as a steer, on any deploy model whose runtime takes one.Its author
POST /api/projects/{projectId}/settings/agentic-deploy/queue/resumeResumes 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 deploys queue list, update, delete, move, send, steer and resume.

Read past Deploys​

List the project's Deploys, newest first.

Query parameterMeaning
pagePage number, from 1. Default 1.
pageSizeDeploys 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, the first Deploy an import starts included, and system for a Recovery Deploy. status takes the values in Follow a Deploy.

In the CLI, run kosuke deploys list <projectId> --page-size 10.

Errors​

StatusCodeWhen
400BAD_REQUESTThe message is empty, a file is refused, or the model is refused. A model change while a Deploy runs is refused too.
402CREDIT_LIMIT_REACHEDThe workspace is blocked on billing.
403FORBIDDENYou changed a queued message you did not write.
404NOT_FOUNDNo such project or queued message.
409DEPLOY_ACTIVEA Deploy is already running, or still stopping.
409JOB_STOPPEDThe Deploy you named in runningDeployJobId was stopped.
409NOT_DEPLOYEDThe project has no main sandbox, because it never deployed or its main sandbox was reclaimed. Start a Deploy.
409DEPLOY_RESUME_UNAVAILABLEThe stopped Deploy cannot resume. Start a new one.
409QUEUE_FULLUp next already holds 20 messages.
409STEER_UNAVAILABLENo turn can take the steer right now. The message stays Up next.
409JOB_STOPPED_TEXT_RETURNEDThe turn you steered into was stopped before it took the message. The message stays Up next.
409QUEUED_MESSAGE_CHANGEDThe message changed or was sent while you edited it. Read Up next again before you save.
409QUEUED_MESSAGE_GONEThe message already left Up next. It was sent or deleted.

The full list is in Responses and errors.

Next steps​