Projects
A project is a GitHub repository connected to a workspace. Install the Kosuke App on the repository, connect GitHub with an account that can write to it, then send POST /api/projects with a name, the repositoryUrl and the workspace id as orgId. The same routes list, rename and delete projects, and read a project's branches, its Session Labels and the skills its sessions can run.
| Method | Path | Description |
|---|---|---|
| GET | /api/projects | 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, or describe what to build to create a YOLO project on a new Kosuke-Org repository. Pass workflow yolo with a repository to import it in YOLO mode, with an optional prompt as its first message. 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; sessions start 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. Pass workflow yolo or personal only when the member asked for it. Report a chatError; on BRANCH_PROTECTED give its message and do not retry. |
| 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}/backlog-items | List a YOLO project's Backlog items in order: each one's title, prompt, state (parked, in_chat or done) and, once Done, the Version it was saved as. |
| POST | /api/projects/{projectId}/backlog-items | Add a Backlog item to a YOLO project: a title and an optional prompt, Parked until someone sends it to the chat. |
| PATCH | /api/projects/{projectId}/backlog-items/{itemId} | Change a Backlog item's title, prompt or position in the list. |
| DELETE | /api/projects/{projectId}/backlog-items/{itemId} | Delete a Backlog item. One already sent to the chat stays in Up next. |
| POST | /api/projects/{projectId}/backlog-items/{itemId}/send | Send a Backlog item to the project's chat. It starts a Turn when the chat is idle and waits Up next, marked from Backlog, when it is working. |
| GET | /api/projects/{projectId}/batch-merging | Read the Merge agent's mode (train: the merge train, batch: Batch merging, off: the platform merges nothing and members merge themselves; enabled is true for batch), how many go-ahead pull requests wait, and the run open now. |
| PUT | /api/projects/{projectId}/batch-merging | Switch the Merge agent's mode. batch: Batch merging, a batch agent combines go-ahead pull requests into one Batch pull request, reviews and QAs it, then an admin approves it. train: the merge train merges them one at a time. off, the mode a new project starts in: the platform merges, enqueues and batches nothing; members merge their pull requests themselves, and a run already open finishes what it carries. Batches run as the member who turned Batch merging on. Switching to train or batch starts a run for the go-ahead pull requests that wait. |
| POST | /api/projects/{projectId}/batch-merging/ejections | The running Batch's own session only: leave a pull request out of the Batch and send the reason to that pull request's task, whose agent fixes it for the next Batch. |
| POST | /api/projects/{projectId}/batch-merging/finish | The running Batch's own session only: end the Batch with nothing to merge, when it left every pull request out or failed on its own work. The platform starts no Batch for the same ready pull requests for an hour, or until one changes. A Batch whose pull request merges or closes ends on its own. |
| POST | /api/projects/{projectId}/batch-merging/members | The running Batch's own session only: record that the Batch carries a task's pull request, before closing it on GitHub. Its task then stays under review, is completed when the Batch merges, and gets its pull request reopened when the Batch ends without merging. Safe to repeat. |
| PUT | /api/projects/{projectId}/batch-merging/picks | The open Batch's own session only, running or pipelined: replace the list of task pull requests merged into its branch. Their tasks show the Batch while it runs, and stop once it ends. Safe to repeat. |
| 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}/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 YOLO project's recent log lines from Workers Logs. |
| POST | /api/projects/{projectId}/live/query | Run one read-only SQL statement against a published YOLO project's live database and return at most 500 rows. Anything that writes is refused. |
| GET | /api/projects/{projectId}/live/traffic?hours= | Read a published YOLO project's request and error counts over the last hours, by status. |
| POST | /api/projects/{projectId}/live/writes | Propose a write to a published YOLO project's live database. Nothing runs: the chat shows a card with the table, the rows before and after and the exact SQL, and a member applies it. Only the project's chat proposes one. Any other caller gets 409 NO_CHAT. |
| GET | /api/projects/{projectId}/live/writes/{writeId} | Read a proposed live write: its SQL, the rows before and after, and whether a member applied or dismissed it, who and when. |
| GET | /api/projects/{projectId}/merge-agent?live= | Read the project's Merge agent: its mode (train, batch, 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 next run with their QA, recorded head, stored review decision and state word (merged, ejected, in-batch, waiting, failed or ready, the one the Tasks board shows), the Batch the queue is split by (its CI, review, QA, members and ejections, each with its state word), 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 (what the Batch pull request still needs, the merge queue) are null. |
| 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 model the Merge agent's next run (train or Batch) starts on, as an encoded id such as anthropic:opus__high, or default for the Default Model. The open run keeps the model it started on. |
| GET | /api/projects/{projectId}/merge-agent/runs?limit=&cursor= | List every Merge agent run of the project, Batches and train runs, newest first, a page at a time: each one's number, mode, session id (for kosuke sessions get), pull request, 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 YOLO project'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: |
| GET | /api/projects/{projectId}/versions | List a YOLO project's Versions, newest first: each passing Turn saved to the default branch, with its commit and, for a Restore, the Version it brought back. |
| POST | /api/projects/{projectId}/workflow | Switch a project between YOLO mode and Collaboration. YOLO completes every Active and Under Review session and turns Backlog sessions into Backlog items; switching back revives the sessions it closed. Before a switch to YOLO, list the Active, Under Review and Backlog sessions it closes (sessions list --status active,under-review,backlog) and switch only on the member's yes in a later message. A YOLO project's work goes into its one chat, the oldest session not Completed: steer it, or create one when there is none, and never run /kosuke:ship there. A refusal (BRANCH_PROTECTED, TURN_IN_FLIGHT, QUEUED_FILES, BACKLOG_FILES) changed nothing: say it. |
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"
Deleting a project cannot be undone. It stops a running Deploy and destroys the project's sandboxes. It removes its chat sessions and their messages, uploaded attachments, Up next, Deploys, services, environment variables and share links, and the runs its Crons made in it. A Cron keeps its other projects; one left with none stays, disabled, saying "No projects left".
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.
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. |
| 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.