Skip to main content

Files and commits

Read and edit the files in a chat session's sandbox, then commit and push the changes yourself. The sandbox must be running, so wake it first with GET /api/projects/{projectId}/preview?sessionId=. A write changes the working tree only, and it stays uncommitted until you commit. A push publishes the branch and leaves the pull request to Open PR. Open PR sends $kosuke:open-pr on a chat session whose Model runs on OpenAI and /kosuke:open-pr on any other. While the session has no Model, or its sandbox lacks the kosuke plugin, it sends a plain message.

MethodPathDescription
GET/api/projects/{projectId}/chat-sessions/{sessionId}/preview/filesList the files in the session's sandbox. Empty when the sandbox is not running.
GET/api/projects/{projectId}/chat-sessions/{sessionId}/preview/files/content?path=Read one file from the session's sandbox.
PUT/api/projects/{projectId}/chat-sessions/{sessionId}/preview/files/contentWrite one file in the session's sandbox. Refused while a turn is running, and for binary content.
GET/api/projects/{projectId}/chat-sessions/{sessionId}/preview/git-stateRead whether the session's sandbox has uncommitted changes, unpushed commits, or commits ahead of its base branch.
POST/api/projects/{projectId}/chat-sessions/{sessionId}/preview/git/commitCommit the uncommitted changes in the sandbox. Refused while a turn is running.
POST/api/projects/{projectId}/chat-sessions/{sessionId}/preview/git/commit-messageDraft a commit message for the uncommitted changes. Needs a running sandbox.
POST/api/projects/{projectId}/chat-sessions/{sessionId}/preview/git/pushPush the session's branch to GitHub. Refused while a turn is running.

Read the file tree​

GET .../preview/files lists the project's files in the sandbox.

curl -s "https://app.kosuke.ai/api/projects/$PROJECT_ID/chat-sessions/$SESSION_ID/preview/files" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"files": [
{
"name": "src",
"type": "directory",
"path": "src",
"children": [
{ "name": "page.tsx", "type": "file", "path": "src/page.tsx", "size": 1843, "lastModified": "2026-09-30T09:14:02.511Z" }
]
}
]
}
}

Paths are relative to the project root. The tree leaves out the folders node_modules, .git, .next, dist, build, coverage, .turbo, .cache, __pycache__, venv and .venv, and the files .DS_Store and Thumbs.db. When the sandbox is not running, files is empty. The CLI command is kosuke sessions files list <projectId> <sessionId>.

Read a file​

GET .../preview/files/content returns one file's text.

ParameterWhat it does
pathRequired. The file's path, relative to the project root.
kosuke sessions files get $PROJECT_ID $SESSION_ID --path src/page.tsx

The answer is { "data": { "content": "..." } }. A path that does not exist, or that leads outside the project, answers 404.

Write a file​

PUT .../preview/files/content replaces the content of a file that exists. To add a new file, ask the agent in a message.

FieldTypeWhat it does
pathstring, up to 2,048 charactersRequired. The file's path, relative to the project root.
contentstring, up to 1,048,576 charactersRequired. The whole new content. Text only.
clientIduuidRequired. A UUID you generate, for example with uuidgen.
curl -s -X PUT "https://app.kosuke.ai/api/projects/$PROJECT_ID/chat-sessions/$SESSION_ID/preview/files/content" \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"path\": \"README.md\", \"content\": \"# Storefront\\n\", \"clientId\": \"$(uuidgen)\"}"
{ "data": { "path": "README.md", "updatedAt": "2026-09-30T09:31:47.220Z" } }

Members with the session open see the change at once. The change is not committed. A write while a turn runs answers 409 with JOB_ACTIVE, and binary content answers 400. The CLI command is kosuke sessions files write <projectId> <sessionId> --path <path> --content <text> --client-id <uuid>.

Read the git state​

GET .../preview/git-state says what is left to commit and push.

{
"data": {
"available": true,
"hasUncommittedChanges": true,
"hasUnpushedCommits": false,
"hasCommitsAheadOfBase": true
}
}
FieldWhat it means
availablefalse when the sandbox is not running. The other fields are then false too.
hasUncommittedChangesThe working tree has changes nobody committed.
hasUnpushedCommitsThe branch has commits that are not on GitHub yet.
hasCommitsAheadOfBaseThe branch has commits its pull request's base branch does not have, or the Target Branch before a pull request is open.

Reading the git state never wakes a sandbox. The CLI command is kosuke sessions git state <projectId> <sessionId>.

Commit​

POST .../preview/git/commit stages every change in the working tree and commits it. It wakes a paused sandbox.

FieldTypeWhat it does
messagestring, 1 to 2,000 charactersRequired. The commit message.
curl -s -X POST "https://app.kosuke.ai/api/projects/$PROJECT_ID/chat-sessions/$SESSION_ID/preview/git/commit" \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "docs: rename the project in the README"}'

The answer is { "data": { "sha": "9f3c1e7…" } }. The commit's author is you when you have a GitHub Connection, and Kosuke App otherwise. The commit stays in the sandbox until you push. The CLI command is kosuke sessions git commit <projectId> <sessionId> --message <text>.

Draft a commit message​

POST .../preview/git/commit-message takes no body. It returns { "data": { "message": "..." } }, a message written from the uncommitted changes. Nothing is committed. It needs a running sandbox. The CLI command is kosuke sessions git commit-message <projectId> <sessionId>.

Push​

POST .../preview/git/push takes no body. It pushes the session's branch to GitHub and answers { "data": { "ok": true } }. It wakes a paused sandbox.

A push opens no pull request. To open one, use Open PR: send $kosuke:open-pr on a chat session whose Model runs on OpenAI and /kosuke:open-pr on any other, as Pull requests and sync shows. When the session already has a pull request, the push adds your commits to it. The CLI command is kosuke sessions git push <projectId> <sessionId>.

Errors​

StatusCodeWhen
400VALIDATION_ERRORA field is missing, too long, or clientId is not a UUID.
400BAD_REQUESTA read has no path, the sandbox is not running for a read, a write or a draft message, the session has no sandbox for a commit or a push, the project has no GitHub access for a push, the content is binary, the write failed, or git refused the commit or the push. The message says which.
402CREDIT_LIMIT_REACHEDThe workspace is blocked on billing.
404NOT_FOUNDThe project, session or file does not exist.
409JOB_ACTIVEA turn is running. Write, commit or push again once it ends.
503SERVICE_UNAVAILABLEThe sandbox could not list the files, read the file or read the git state. Retry.

Responses and errors has the full table.

Next steps​