| Method | Path | Description |
|---|---|---|
| GET | /api/projects?sessions= | List the projects you can reach, across every workspace you belong to. An agent token sees only its own workspace. |
| POST | /api/projects | Connect a GitHub repository as a project in a workspace (its Merge agent starts Off), or describe what to build to start a repository from kosuke-starter on a new Kosuke-Org repository (its Merge agent starts on the merge train with the go-ahead from passing checks, unless mergeAgentMode and mergeGoAhead say otherwise; 403 KOSUKE_STARTER_OFF when staff have it off on this deployment). With a repository, an optional prompt files its first task. Pass personal instead of orgId to create it in your Personal: your own credential, or your Sensei. Its first Deploy starts by itself, as the caller's; the first task starts on /kosuke:ship once it lands. Imports only a repository your own GitHub Connection can write to: 403 GITHUB_REPOSITORY_ACCESS_REQUIRED otherwise, 401 GITHUB_RECONNECT_REQUIRED when GitHub no longer accepts your connection. A repository the workspace or Personal already has is refused with 409 REPOSITORY_ALREADY_IMPORTED: details.projects names each of its projects there ({ id, name }, oldest first), so open one instead of importing again; another workspace's import never refuses it. Pass personal only when the member asked for it. Report a chatError. |
| GET | /api/projects/{projectId} | Read one project. |
| PATCH | /api/projects/{projectId} | Rename a project. |
| DELETE | /api/projects/{projectId} | Delete a project and everything it owns. Workspace admins only. |
| GET | /api/projects/{projectId}/branches?search=&cursor= | List the repository's branches, 30 per page in alphabetical order; pass nextCursor back as cursor for the next page, and search to filter by name. |
| GET | /api/projects/{projectId}/chat | Read the repository's Chat for you: whether it is on (and who pushes, you or Kosuke, on a repository Kosuke made) or off with the reason and next step, read from GitHub's rules on the default branch at most 60 seconds ago; its session, or null before anyone opened it; and the last 50 pushes its Turns made to the default branch, oldest first, each with its Version number once recorded (null without the kosuke-starter layout). Send messages with the session commands. |
| POST | /api/projects/{projectId}/chat | Open the repository's Chat: create its session on the default branch if it has none, and answer it (the same session every time). 409 CHAT_OFF while Chat is off for you, with the reason; 409 CHAT_BRANCH_TAKEN while another open session works on the default branch. No Turn starts: send the first message with the session commands. |
| GET | /api/projects/{projectId}/labels | List the project's Session Labels as { name, color }, in alphabetical order, including labels no session carries any more. color is six hex digits without '#'. |
| PATCH | /api/projects/{projectId}/labels | Recolor a Session Label. Session Labels stay in Sensei: nothing is written to GitHub. |
| DELETE | /api/projects/{projectId}/labels | Delete a Session Label from the project's catalog. A label sessions still carry is refused with 409 and the list of them unless removeFromSessions is true, which removes it from each of them. Deleting a name the project does not have, including one already deleted, answers 404. |
| GET | /api/projects/{projectId}/labels/usage?name= | List the sessions carrying a Session Label, in every status including archived and completed, as { projectName, sessions: [{ id, title, status, pullRequestNumber }] }. Answers 404 when the project has no label by that name. |
| GET | /api/projects/{projectId}/live/logs?minutes=&limit= | Read a published repository's recent log lines from Workers Logs. |
| POST | /api/projects/{projectId}/live/query | Run one read-only SQL statement against a published repository's live database and return at most 500 rows. Anything that writes is refused. |
| GET | /api/projects/{projectId}/live/traffic?hours= | Read a published repository's request and error counts over the last hours, by status. |
| GET | /api/projects/{projectId}/merge-agent?live= | Read the project's Merge agent: its mode (train, or off, where a new project starts), the base and whether it has GitHub's merge queue, the model the next run starts on (null: the Default Model), the go-ahead pull requests waiting for the merge train with their QA, recorded head, stored review decision and state word (merged, waiting, failed or ready, the one the Tasks board shows), the merge train's order as its open run saved it (trainOrder: each waiting pull request's place, group and reason, else null), and the open run and the last ten earlier runs, each with the model and effort its session runs on. kosuke projects merge-agent runs list lists every run. --live false reads Sensei's own data only: no GitHub call, and GitHub's facts (the merge queue) are null. |
| PUT | /api/projects/{projectId}/merge-agent | Switch the Merge agent's mode, its Go-ahead, or Wait for QA; give any of them, and the others stay. mode train: the merge train merges go-ahead pull requests one at a time. off, the mode an imported repository starts in: the platform merges and enqueues nothing; members merge their pull requests themselves, and a run already open finishes what it carries. goAhead, under the merge train: member, a member gives each pull request the go-ahead (QA must pass too); checks, a pull request a platform agent works on whose required checks pass on its latest commit has the go-ahead with nobody giving it, and waitForQa true makes it wait for QA to pass there too. Leaving train with checks takes back every go-ahead the checks gave. Switching to train starts a run for the go-ahead pull requests that wait. |
| GET | /api/projects/{projectId}/merge-agent/ci-check | Read the Merge agent's CI check: whether the repository's pull request CI tests GitHub's merge of each pull request with the base while the base requires its checks, so a red base fails every pull request and GitHub refuses every merge. Kosuke reads the required checks and the CI files (GitHub Actions, CircleCI, Buildkite, Jenkins) once an hour, when the Merge agent is turned on and when a fix pull request merges; this read makes no GitHub call. row is null while the Merge agent is off, before the first read, when nothing blocks merges and when the CI could not be read. A blocking row names the service, base, repository, the required checks it feeds, the one change (detail) and, for GitHub Actions, where its Fix stands (fix: idle, working, or open with its pull request). A fixed row shows the fix pull request for a day after it merged. canFix: the reader is a workspace owner or admin. |
| POST | /api/projects/{projectId}/merge-agent/ci-check/fix | Start the Fix of the Merge agent's CI check, for a GitHub Actions repository whose pull request CI tests GitHub's merge with the base: files and starts a session in the project with --skill ship that opens one pull request setting every pull_request checkout step to the pull request's own commit. Workspace owners and admins only, in the app or with their own API key: no agent token reaches it. Refused (409) unless the stored check is blocking on GitHub Actions with no fix working or open; two requests at once start one. A start that is refused archives the filed session and answers the refusal's status and code, with nothing changed. Answers the CI check as projects merge-agent ci-check get reads it, its fix working. |
| POST | /api/projects/{projectId}/merge-agent/finish | The open merge train run's own session only: end the run once nothing waits, neither waiting nor in progress, with what it merged. Its saved merge order stops showing on the tasks' boards, and the next go-ahead starts a new run. |
| POST | /api/projects/{projectId}/merge-agent/merges | The open Merge agent run's own session only: merge a pull request into the run's base as the Kosuke GitHub App, or add it to GitHub's merge queue with --queue, only at the head its member gave the go-ahead on and GitHub holds now. Refused for any other head, base or caller. |
| PUT | /api/projects/{projectId}/merge-agent/model | Pick the Merge agent's model, as an encoded id such as anthropic:opus__high, or default for the Default Model: the open run switches to it from its next turn, and the next run starts on it. The answer's run says whether the open run took it, and why not. |
| POST | /api/projects/{projectId}/merge-agent/retry | Retry the open Merge agent run's last Turn now, when it failed: sends its message again into the run's session. A Turn that failed on its Provider (billing, rate limit, overloaded, server error, authentication) is retried by Kosuke after 5, 15 and 30 minutes; after those it stops until this retry. Any project member may retry. |
| GET | /api/projects/{projectId}/merge-agent/runs?limit=&cursor= | List every Merge agent run of the project, newest first, a page at a time: each one's number, mode (always train), session id (for kosuke sessions get), state, finish reason and dates. Pass nextCursor back as cursor for the older runs. The runs' sessions stay out of the session lists. |
| POST | /api/projects/{projectId}/merge-agent/syncs | The open Merge agent run's own session only: bring the run's base into an open pull request's branch as the Kosuke GitHub App, as GitHub's Update branch does. A conflict is refused with GitHub's words. |
| GET | /api/projects/{projectId}/releases | List a repository's Releases, newest first: the Version each published, its status (publishing, live, superseded or failed), and whether it changed the database schema. |
| GET | /api/projects/{projectId}/ship-estimates/accuracy | How far the project's ship-run time estimates were off, over its last 30 runs that became Ready: medianAbsPctError is the median absolute percentage error of the middle estimate against the working time each run took, waits left out (null with no run to judge), and recent lists each run's estimatedMidMs, estimatedHighMs, actualMs, completedAt, the size inputs the estimate was made from and its estimateSource, newest first. |
| GET | /api/projects/{projectId}/skills?provider=&sessionId= | List the skills the agent can invoke in this project, for one provider: the project's own, the workspace's and the member's, the plugins', and the platform's own skills in the kosuke plugin, which every chat session carries as kosuke:<name>. From a sandbox, sessionId defaults to its own chat session. provider is the session's agent: anthropic for Claude, GLM, Kimi and DeepSeek; openai for Codex; meta for Muse; google for Gemini; xai for Grok. Check a skill is listed before you send a message that runs it. |
| GET | /api/projects/{projectId}/versions | List a repository's Versions, newest first: each task merged into the default branch (and, for a migrated App, each Turn it saved), with its commit and, for a Restore, the Version it brought back. |
The routes that start and follow a Deploy are on Deploys. Setup commands, services and environment variables are on Project settings.
A chat session's sandbox token and a Cron Run's token reach the live routes only in their own project: the session's project, or a project the Cron Run covers. Another project of the same workspace answers 403.
List projects
List every project in every workspace you belong to, newest first.
curl -s https://app.kosuke.ai/api/projects \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": [
{
"id": "3f6c1e0a-8b2d-4e57-9a41-0c2f7d9b5e18",
"name": "storefront",
"description": null,
"orgId": "YzH4k2P9sQ1mVx7bN3cR8tL5wD0fG6jA",
"githubRepoUrl": "https://github.com/acme/storefront",
"githubOwner": "acme",
"githubRepoName": "storefront",
"defaultBranch": "main",
"deploymentStatus": "deployed",
"sandboxTier": "MEDIUM",
"createdAt": "2026-08-14T09:20:11.000Z",
"sessions": [
{
"id": "b1d6e2f4-7a3c-4c1e-9f0b-2e8d5a6c7b90",
"title": "Fix the checkout total",
"branchName": "kosuke/chat-x7k2m9",
"messageCount": 6,
"status": "active",
"lastActivityAt": "2026-09-30T09:02:44.000Z"
}
]
}
]
}
orgId is the workspace the project belongs to. sessions holds the project's active, under-review and completed sessions that have a branch, most recently active first. For every session, use Chat sessions.
GET /api/projects/{projectId} reads one project. It has the same fields without sessions, and adds credentialOwners, whose credentials the project's own sandbox runs each provider on.
In the CLI, run kosuke projects list and kosuke projects get <projectId>.
Create a project
Import a repository into a workspace. Any member of the workspace can.
- Find the workspace id with
GET /api/organizations. See Workspaces. - Pick the repository from
GET /api/auth/github/repositories, one whoseappInstalledistrue. See GitHub to install the Kosuke App on another one. - Send the request below.
| Body field | Meaning |
|---|---|
name | The project's name, 1 to 100 characters. |
repositoryUrl | The repository's GitHub URL, such as its html_url or clone_url. |
orgId | The workspace id. Required with an API key. |
curl -s https://app.kosuke.ai/api/projects \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
--json '{
"name": "storefront",
"repositoryUrl": "https://github.com/acme/storefront",
"orgId": "YzH4k2P9sQ1mVx7bN3cR8tL5wD0fG6jA"
}'
The route answers 201 with the new project in data.project.
Importing also brings the repository's open pull requests in as chat sessions. A draft pull request becomes an active session, and one ready for review an under-review session. These sessions have no Assignee.
Creating the project starts its first Deploy, as you, the same as an import in the web app. Follow it with Deploys. When the workspace has no deploy model it can run, the Deploy does not start, and the Deploy Chat says why. Sessions start once the first Deploy lands. Backlog sessions can be filed at once.
In the CLI, run kosuke projects create --name storefront --repository-url https://github.com/acme/storefront --org-id <workspaceId>.
To create the project in your Personal instead, send "personal": true in place of orgId, or pass --personal in the CLI. It needs your own credential, or your Sensei in a Turn your own message started. A chat session's sandbox token, a Cron Run's token and Sensei in any other Turn answer 403. A Personal import checks your own GitHub Connection, even for a Superadmin.
Rename a project
Any member can rename a project. The route answers 200 with the updated project.
| Body field | Meaning |
|---|---|
name | The new name, 1 to 100 characters. |
curl -s -X PATCH https://app.kosuke.ai/api/projects/$PROJECT_ID \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
--json '{ "name": "storefront-web" }'
In the CLI, run kosuke projects update <projectId> --name storefront-web.
Delete a project
Workspace owners and admins can delete a project. The route answers 204.
curl -s -X DELETE https://app.kosuke.ai/api/projects/$PROJECT_ID \
-H "Authorization: Bearer $KOSUKE_API_KEY"
The repository on GitHub stays as it is, with its branches and pull requests. The workspace's usage records and Activity keep the project's past entries.
In the CLI, run kosuke projects delete <projectId>.
Branches
List the repository's branches, 30 per page in alphabetical order.
| Query parameter | Meaning |
|---|---|
search | Only branches whose name matches this text. |
cursor | The nextCursor of the previous page. |
curl -s "https://app.kosuke.ai/api/projects/$PROJECT_ID/branches?search=release" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"branches": ["release/2026-09", "release/2026-10"],
"defaultBranch": "main",
"nextCursor": null
}
}
defaultBranch is the branch new sessions start from. It is the project's own setting when one is saved, otherwise the repository's default branch. nextCursor is null on the last page.
In the CLI, run kosuke projects branches list <projectId> --search release.
Skills available in a project
List the skills and commands a session in this project can run. In a session, the composer menu also shows the Runtime Commands /clear and /compact ($clear and $compact in Codex sessions), which this route does not return. provider is required. Pass anthropic for Claude, GLM, Kimi and DeepSeek sessions, openai for Codex sessions, meta for Muse Code sessions, google for Gemini sessions, or xai for Grok sessions. Add sessionId to read the repository's skills from that session's sandbox while it is running, and to list the Personal Skills of that session's Assignee; otherwise the list comes from the project's main sandbox or the last cached list.
curl -s "https://app.kosuke.ai/api/projects/$PROJECT_ID/skills?provider=anthropic" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"skills": [
{
"slug": "kosuke:sync-branch",
"name": "sync-branch",
"description": "Bring the current branch up to date with the branch its pull request targets: …",
"argumentHint": "[--target-branch <branch>]",
"kind": "skill",
"origin": "kosuke",
"source": "kosuke"
}
]
}
}
| Field | Meaning |
|---|---|
slug | What you type after /, or after $ in a Codex session. |
kind | skill or command. |
origin | project, workspace, personal, plugin, or kosuke for a Factory Skill. |
ownerName | On someone else's Personal Skill, the member it belongs to. |
To run a skill in a session, send its invocation as a message. See Messages and turns.
In the CLI, run kosuke projects skills list <projectId> --provider anthropic.
Chat
A repository's Chat is one session per project that works on the default branch and pushes there itself, with no pull request. Read it for yourself with GET: the answer depends on who asks, because the push is made with your GitHub account, or by Kosuke on a repository Kosuke made.
curl -s "https://app.kosuke.ai/api/projects/$PROJECT_ID/chat" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"availability": { "on": true, "branch": "main", "pusher": "member" },
"session": { "id": "2b0c6f2e-5a51-4c55-9a8e-0f3c1d9e7a10", "status": "active" },
"pushes": [
{
"chatJobId": "8d7e1f4a-3c2b-4d6e-9f10-2a3b4c5d6e7f",
"commitSha": "4f9c2a1e7b3d5c6a8e0f1b2c3d4e5f6a7b8c9d0e",
"versionNumber": 12,
"pushedAt": "2026-11-03T10:24:05.000Z"
}
]
}
}
| Field | Meaning |
|---|---|
availability.on | Whether you can use Chat now. GitHub's rules on the default branch are read at most 60 seconds earlier. |
availability.pusher | member when the push is made with your GitHub account, app when Kosuke pushes, on a repository Kosuke made. |
availability.reason | When off: no_connection, reconnect, no_push, pull_request, status_checks, signatures, deployments, merge_queue, blocks_update, restricted or unreadable. availability.message says it in a sentence, with the next step. |
session | The Chat session, or null before anyone opened Chat. |
pushes | The last 50 pushes its Turns made, oldest first. versionNumber is null until the Version is recorded, and stays null on a repository without the kosuke-starter layout. |
Chat is off on an imported repository when you have no GitHub connection, it needs a reconnect, or your account cannot push. On any repository, it is off when a branch protection rule or an active ruleset on the default branch requires pull requests, status checks, signed commits, deployments or a merge queue, blocks updates, or keeps direct pushes out, even when the pusher could bypass it. Use a task instead, and the Merge agent lands it.
Open it with POST, which takes no body. It creates the session the first time and answers the same one after that, so you can send it again safely. No Turn starts: send the first message to session.id as in Messages and turns. Each Turn runs as the member who sent it. A message you send while another member's Turn runs waits in the Queue.
curl -s -X POST "https://app.kosuke.ai/api/projects/$PROJECT_ID/chat" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"session": { "id": "2b0c6f2e-5a51-4c55-9a8e-0f3c1d9e7a10", "status": "active" }
}
}
In the CLI, run kosuke projects chat get <projectId> and kosuke projects chat create <projectId>. See Project settings for the Chat tab in the app.
Errors
| Status | Code | When |
|---|---|---|
| 400 | BAD_REQUEST | orgId is missing with an API key, the repository URL is not a GitHub repository, or provider, search or cursor is invalid. |
| 400 | VALIDATION_ERROR | The body fails the schema, such as an empty name. |
| 403 | FORBIDDEN | You are not a member of orgId, or a member tried to delete a project. |
| 404 | NOT_FOUND | No such project, or it belongs to a workspace you are not in. |
| 409 | CHAT_OFF | You opened Chat, or sent a message to it, while it is off for you. The message says why. |
| 409 | CHAT_BRANCH_TAKEN | You opened Chat while another open session works on the default branch. End it, then open Chat. |
| 500 | SERVER_ERROR | The Kosuke App is not installed on the repository you tried to import. Install it and try again. |
The full list is in Responses and errors.
Next steps
- Follow the project's first Deploy with Deploys.
- Configure what runs in its sandbox with Project settings.
- Open a session in it with Chat sessions.