# Sensei CLI

Install the Sensei CLI to start chat sessions, follow turns and manage projects from your terminal or a script. You need Node.js 22.18 or later. Install it with npm, sign in with an API key, and every API command that returns a body prints JSON you can pipe into `jq`.

[Integrate Kosuke](https://kosuke.ai/docs/integrate.md) puts the CLI, the MCP server and one prompt to paste into your agent on one page.

## Install

```sh
npm install -g @kosuke-ai/kosuke
kosuke --version
```

## Sign in

1. Create an API key in Settings > You > API keys. See [Authentication](https://kosuke.ai/docs/api/authentication.md).
2. Run `kosuke auth login` and paste the key when it asks. What you type stays hidden.
3. Sensei checks the key and saves it. It prints a line such as `Logged in to https://app.kosuke.ai; member of 2 workspaces. API key saved to /home/you/.config/kosuke/credentials.json.`

`kosuke auth status get` shows where the key comes from and whether Sensei accepts it. `kosuke auth logout` deletes the stored key.

In CI or any script that runs without a person, skip the login. Set the `KOSUKE_API_KEY` environment variable to the key, or pass `--api-key <token>` to any command. A key from a flag or the environment wins over the stored one.

Inside a chat sandbox, where the credential is a sandbox agent token, the tree narrows to the operations that token may call. The same holds in a Cron Run, where the credential is [the run's own key](https://kosuke.ai/docs/endpoint-reference/crons.md#a-cron-runs-own-key). The tools of the connected [integrations](https://kosuke.ai/docs/workspace/integrations.md), the workspace's and, in your own turns, [yours](https://kosuke.ai/docs/workspace/personal-integrations.md), are there too: see [Run integration tools](https://kosuke.ai/docs/interfaces/cli.md#run-integration-tools).

The [MCP server](https://kosuke.ai/docs/interfaces/mcp.md) does not need this key: your agent's client signs you in through the browser instead, though it also accepts an API key as a bearer token.

## Your first commands

```sh
# 1. Find the project's id.
kosuke projects list --json | jq '.data[] | {id, name}'

# 2. File a task, note its task id, then start it.
kosuke tasks create <orgId> --hint-project <projectId> \
  --title "Fix footer typo" --description "Fix the typo in the pricing page footer"
kosuke tasks start <orgId> <taskId> --project-id <projectId> --skill ship

# 3. Follow the turn until it ends, printing what the agent says.
kosuke sessions jobs watch <projectId> <sessionId> <jobId> \
  | jq -r 'select(.type == "message") | .data.text'
```

`tasks create` saves Todo work. `tasks start` starts its execution. The older `sessions create --status backlog` remains supported.

## How commands work

- Ids are positional arguments, in the order the help shows, such as `kosuke sessions get <projectId> <sessionId>`. A command that takes a project id and then a session id also runs with the session id alone, or with `--session-id <id>`: `kosuke sessions get <sessionId>` looks the project up first. A command whose session id is a flag, such as `kosuke sensei sessions facts get`, also takes it as its first positional argument.
- Request fields are flags, such as `--title`, `--content` or `--exclude-archived`.
- `--body '<json>'` sends a whole request as JSON. `--body-file <path>` reads it from a file, and `--body-file -` reads it from stdin. A few commands, such as `projects env-vars create`, take only a whole body.
- `--attach <path>` attaches a file. Repeat it for several files. `sessions create`, `sessions send`, `sessions prompt update`, `sessions queue update`, `deploys start`, `deploys queue update` and `files set` take files. `files set` takes one file of up to 25 MB, the others up to 10 MB each.
- Every API command that returns a body prints JSON to stdout, with the result under `data`; one whose request answers 204 prints nothing. In a terminal the JSON is indented. Piped into another program or a file, it is compact: one line, with each row of a `data` list on its own line. `--pretty` prints it indented anyway. Errors go to stderr, and the command exits with 1.
- `--json`, or `KOSUKE_OUTPUT=json` in the environment, asks for the platform's whole JSON. Pass it in any script that reads the output with `jq`.
- The lists are short without it: `projects list`, `sessions list`, `tasks list`, `crons list`, `activity list`, `sensei threads list`, `sensei cards list` and `files list` print at most 20 rows, each with the fields you pick a row by, and a last line on stderr such as `20 of 3122. More: --cursor <c>`. `--all` reads every page, `--full` keeps every field, and `--fields` picks from whole rows.
- `--fields id,title,chatSession.id` prints only those fields, per row of a list, or of the list the answer holds (such as the `crons` of `crons list`), else of the object. A dot reaches into a nested object. A field no row has exits with 1 and names the closest fields. `--format compact` prints a header line, then one tab-separated line per row, with nulls empty and times to the second; what sits beside the rows, such as the next cursor, goes to stderr. `--fields` also works with `--json`.
- Times in the JSON are ISO 8601 in UTC, for scripts to parse. `user usage get` and `workspaces usage breakdown get` count calendar days in your own timezone unless you pass `--tz`. When your timezone cannot be read they count UTC days and say so on stderr.
- `--repository` takes `owner/repo`, such as `--repository acme/storefront`, or the JSON `{"owner":"acme","name":"storefront"}`.
- `--help` works at every level. `kosuke sessions --help` lists the group's commands, and `kosuke sessions send --help` lists that command's flags, one line each. `--help --long` prints each description in full.
- `kosuke help --compact` lists every command you can run with its arguments, one line per group, in about 4,000 characters. An agent reads it once in place of many `--help` calls.
- An unknown command or flag names the closest one: a mistyped `lst` after `kosuke sessions qa runs` answers `Did you mean ...?` with the commands of that group.

## Find a session

`kosuke find <query>` finds sessions in one call. The query is a pull request number such as `3323` or `#3323`, a session id, a task id, or words of a title such as `"compact view"`. It prints one line per match, with the workspace, project, session, your Sensei Thread that follows it, its task, its pull request number and the head commit Sensei last saw.

```sh
kosuke find 3323
kosuke find "compact view" --json | jq -r '.data[] | "\(.projectName) \(.sessionId) #\(.pullRequestNumber)"'
```

It searches what `kosuke sessions list` shows you: every workspace you belong to, or the token's own workspace inside an agent's turn.

## Command reference

### Tasks

| Command | Positional arguments | Purpose |
| --- | --- | --- |
| `tasks list` | `<orgId>` | Filter one workspace with `--status`, `--owners`, `--priorities`, `--project`, `--q`, and `--labels '["bug","ui"]'` (up to 20 names, matching any). |
| `tasks list` | none | All caller workspaces, with `--status`, `--q` and `--labels '["bug","ui"]'`. |
| `tasks labels list` | `<workspaceId>` | List label names and colors across the workspace's repositories. |
| `tasks create` | `<orgId>` | `--title`, `--description`; optional `--priority`, `--owner-id`, `--hint-project`, `--reason`, `--start-when-deployed`, `--sandbox-size small|medium|large|xlarge`, `--app-stack start|skip`. |
| `tasks get` | `<orgId> <taskId>` | Read a task. |
| `tasks update` | `<orgId> <taskId>` | Edit `--title`, `--description`, `--priority`, `--owner-id`, `--status todo|done`, `--hint-project` for a task with no session, and while it is Todo `--sandbox-size` and `--app-stack`. |
| `tasks start` | `<orgId> <taskId>` | `--project-id`; optional `--skill ship`, `--sandbox-size`, `--app-stack`. |
| `tasks project set` | `<orgId> <taskId>` | `--project-id`; optional `--if-revision`. Moves a Todo task and its Backlog session to another deployed repository of the workspace, in place. Nothing starts. |


The tables list the main commands, not every one. `kosuke help --compact` lists every command, and `kosuke <group> --help` every command in a group.

### auth

| Command | Arguments | What it does |
| --- | --- | --- |
| `auth login` | none | Store an API key after checking it works |
| `auth status get` | none | Show where the key comes from and whether Sensei accepts it |
| `auth logout` | none | Delete the stored key |

### projects

| Command | Arguments | What it does |
| --- | --- | --- |
| `projects list` | none | List the projects you can reach, across every workspace |
| `projects get` | `<projectId>` | Read one project |
| `projects create` | none | Import a GitHub repository with `--repository-url` and `--name`, or make a repository from kosuke-starter with `--description`. With an import, `--prompt` files its first task, which starts when the first deploy lands |
| `projects update` | `<projectId>` | Rename a project |
| `projects delete` | `<projectId>` | Delete a project and everything it owns. Admins only |
| `projects merge-agent get` | `<projectId>` | Read the Merge agent's `mode`, `goAhead` and `waitForQa`. Only `mode` `off` means it is off; the output has no `enabled` |
| `projects merge-agent set` | `<projectId>` | Change the Merge agent's `--mode`, `--go-ahead` (`member` or `checks`) or `--wait-for-qa`. The older `--no-enabled` still works and means `train`; `--enabled` is refused |
| `projects versions list` | `<projectId>` | List the Versions of a repository with the kosuke-starter layout |
| `projects releases list` | `<projectId>` | List its Releases |
| `projects merge-agent model set` | `<projectId>` | Pick the model the Merge agent's next run starts on, or `default` |
| `projects branches list` | `<projectId>` | List the repository's branches |
| `projects skills list` | `<projectId>` | List the skills the agent can run in the project, for one provider |
| `projects labels list` | `<projectId>` | List the project's Session Labels |
| `projects settings get` | `<projectId>` | Read setup commands, services, environment and sandbox size |
| `projects settings update` | `<projectId>` | Change the QA Guide with `--qa-guide` or the device folders with `--device-write-paths`. Setup commands, branches, working directory and sandbox size get 403, see below |
| `projects settings set` | `<projectId>` | Replace services and environment from a `kosuke.config.json` file. Gets 403, see below |
| `projects settings changes list` | `<projectId>` | Read the project's [Change history](https://kosuke.ai/docs/set-up/project-settings.md#change-history), newest first. Environment values are never kept |
| `projects qa-guide set` | `<projectId>` | Save the project's QA Guide from `--content` |
| `projects services list` | `<projectId>` | List the services in the order they start |
| `projects services create` | `<projectId>` | Add a service. Gets 403, see below |
| `projects services update` | `<projectId> <serviceId>` | Change a service. Gets 403, see below |
| `projects services delete` | `<projectId> <serviceId>` | Remove a service. Gets 403, see below |
| `projects env-vars create` | `<projectId>` | Add environment variables. Gets 403, see below |
| `projects env-vars delete` | `<projectId>` | Remove environment variables. Gets 403, see below |

Only a workspace admin changes a project's setup, services and environment, in the web or desktop app. The CLI signs in with an API key, so the commands marked 403 above, and `deploys start`, get 403 `SETTINGS_ADMIN_ONLY` for every member, admins included, until API keys get a project settings scope. Reads still work. See [What only the web app can do](https://kosuke.ai/docs/api/what-an-api-key-cannot-do.md#project-settings-and-deploys).

An import with a first task looks like this. The task starts on `/kosuke:ship` when the first deploy lands.

```bash
kosuke projects create --org-id <workspaceId> --name storefront \
  --repository-url https://github.com/acme/storefront \
  --prompt "add a footer"
```

A repository from kosuke-starter starts from a sentence. See [Preview and publish](https://kosuke.ai/docs/set-up/preview-and-publish.md#start-from-kosuke-starter). While Start from kosuke-starter is off on the deployment, `--description` is refused with 403 `KOSUKE_STARTER_OFF` and makes no repository.

```bash
kosuke projects create --org-id <workspaceId> --description "A booking page for my yoga classes"
```

### sessions

| Command | Arguments | What it does |
| --- | --- | --- |
| `sessions list` | `<projectId>` | List a project's chat sessions |
| `sessions list` | none | List sessions across every workspace. `--labels '["bug","ui"]'` matches any selected label. |
| `sessions search` | none | Search sessions by title |
| `sessions get` | `<projectId> <sessionId>` or `<sessionId>` | Read a session with its latest turn and pull request |
| `sessions create` | `<projectId>` | Start a session, or add one to the Backlog with `--status backlog` |
| `sessions start` | `<projectId> <sessionId>` | Start a Backlog session |
| `sessions app-stack start` | `<projectId> <sessionId>` | Start the project's services in a session that skipped its App stack, and wait until they answer |
| `sessions env sync` | `<projectId> <sessionId>` | Deliver the project's current environment variables to a running session sandbox and restart its services. Refused while a turn runs |
| `sessions update` | `<projectId> <sessionId>` | Change the title, status, model, Assignee or priority, and, while the session is in the Backlog, its `--sandbox-size` and `--app-stack`. Once the session started those two are fixed: 409 `SANDBOX_SETTINGS_LOCKED` |
| `sessions delete` | `<projectId> <sessionId>` | Delete a session |
| `sessions labels set` | `<projectId> <sessionId>` | Replace the session's Session Labels |
| `sessions labels update` | `<projectId> <sessionId>` | Add and remove Session Labels, leaving the rest |
| `sessions prompt update` | `<projectId> <sessionId>` | Rewrite a Backlog session's prompt and attachments |
| `sessions send` | `<projectId> <sessionId>` | Send a message. It starts a turn, or waits Up next |
| `sessions messages list` | `<projectId> <sessionId>` | Read the conversation with tool calls and subagents as stored previews. `--limit` reads the newest messages, and `--before` the page older than an `olderCursor` |
| `sessions messages get` | `<projectId> <sessionId> <messageId>` | Read one message with every block as recorded. `--agent-output compact` keeps each subagent's last output entry |
| `sessions jobs watch` | `<projectId> <sessionId> <jobId>` | Follow a turn until it ends |
| `sessions runtime-commands run` | `<projectId> <sessionId>` | Run `/clear` or `/compact` |
| `sessions jobs list` | `<projectId> <sessionId>` | List the session's turns |
| `sessions jobs get` | `<projectId> <sessionId> <jobId>` | Read one turn's status |
| `sessions jobs cancel` | `<projectId> <sessionId> <jobId>` | Stop a running turn |
| `sessions queue list` | `<projectId> <sessionId>` | List the messages Up next |
| `sessions queue update` | `<projectId> <sessionId> <queuedMessageId>` | Edit your own message Up next |
| `sessions queue move` | `<projectId> <sessionId> <queuedMessageId>` | Move your own message within Up next |
| `sessions queue steer` | `<projectId> <sessionId> <queuedMessageId>` | Steer your own message into your running turn |
| `sessions queue delete` | `<projectId> <sessionId> <queuedMessageId>` | Delete a message Up next |
| `sessions queue resume` | `<projectId> <sessionId>` | Resume a paused Up next |
| `sessions diff files list` | `<projectId> <sessionId>` | List the files the session's branch changes |
| `sessions diff patch get` | `<projectId> <sessionId>` | Read the changes as patches |
| `sessions diff commits list` | `<projectId> <sessionId>` | List the commits on the session's branch |
| `sessions diff comments list` | `<projectId> <sessionId>` | List the line comments on the changes |
| `sessions diff comments create` | `<projectId> <sessionId>` | Comment on a range of lines |
| `sessions diff comments update` | `<projectId> <sessionId> <commentId>` | Edit your own line comment, or resolve or reopen any |
| `sessions diff comments delete` | `<projectId> <sessionId> <commentId>` | Delete your own line comment |
| `sessions sandbox-files list` | `<projectId> <sessionId>` | List the files in the session's sandbox |
| `sessions sandbox-files get` | `<projectId> <sessionId>` | Read one file. Wake the sandbox first |
| `sessions sandbox-files set` | `<projectId> <sessionId>` | Write one file |
| `sessions git state get` | `<projectId> <sessionId>` | Read whether the sandbox has uncommitted changes, unpushed commits, or commits ahead of the base branch |
| `sessions files list` | `<projectId> <sessionId>` | List the session's [files](https://kosuke.ai/docs/sessions/files.md): what its agent wrote, a deleted one as a row, then the files its ticket points at |
| `sessions files get` | `<projectId> <sessionId> <fileId>` | Read one file of the session, by its id or its name |
| `sessions files attach` | `<projectId> <sessionId>` | Point a Backlog session at a file of the project's Files, without copying it. `--file <path>` names a file, or a folder whose files are all attached |

### deploy

| Command | Arguments | What it does |
| --- | --- | --- |
| `deploys start` | `<projectId>` | Start a Deploy, or answer the deploy agent. Gets 403 `SETTINGS_ADMIN_ONLY`: a workspace admin does it in the Deploy Chat |
| `deploys cancel` | `<projectId>` | Stop the running Deploy |
| `deploys list` | `<projectId>` | List the project's Deploys |
| `deploys messages list` | `<projectId>` | Read the Deploy Chat and the current Deploy status |
| `deploys messages get` | `<projectId> <messageId>` | Read one Deploy Chat message with every block as recorded. `--agent-output compact` keeps each subagent's last output entry |
| `deploys model set` | `<projectId>` | Pick the deploy agent's model |
| `deploys queue list` | `<projectId>` | List the Deploy Chat messages Up next |
| `deploys queue update` | `<projectId> <queuedMessageId>` | Edit your own message Up next |
| `deploys queue move` | `<projectId> <queuedMessageId>` | Move your own message within Up next |
| `deploys queue steer` | `<projectId> <queuedMessageId>` | Steer your own message into the running deploy turn                        |
| `deploys queue delete` | `<projectId> <queuedMessageId>` | Delete a message Up next |
| `deploys queue resume` | `<projectId>` | Resume the Deploy Chat's paused Up next |

### preview

| Command | Arguments | What it does |
| --- | --- | --- |
| `preview get` | `<projectId>` | Read the preview addresses of the main preview, or of a session with `--session-id` |
| `preview health get` | `<projectId>` | Read the health of each service behind a preview |
| `preview sandbox reset` | `<projectId>` | Kill a preview's sandbox so Sensei creates a new one |
| `preview share get` | `<projectId>` | Read a preview's share link, if it has one |
| `preview share create` | `<projectId>` | Create a preview's share link |
| `preview share delete` | `<projectId>` | Revoke a preview's share link |
| `preview shared get` | `<slug>` | Open a share link. Needs no API key |
| `preview shared-files get` | `<slug> <fileId>` | Read a file behind a share link. Needs no API key |

### files

A workspace's shared [Files](https://kosuke.ai/docs/workspace/files.md). A path is folder names and a file name joined by `/` from the workspace root, such as `prototypes/board/a-columns.html`.

| Command | Arguments | What it does |
| --- | --- | --- |
| `files list` | `<workspaceId>` | List one folder, folders first, with its breadcrumb. `--folder` takes a folder id or a path and defaults to the root |
| `files get` | `<workspaceId> <fileId>` | Read one item's details and its `url`. A text file of up to 1 MB includes its `body`. Any other file includes a short-lived `downloadUrl` and its `expiresAt` |
| `files set` | `<workspaceId>` | Write a file by `--path`, creating the folders on the way. `--text` gives the content inline and `--attach <path>` a local file. A file of the same name is replaced and its version counts up. `--if-version <n>` refuses the write with 409 when the file is on another version. `--media-type` overrides the type |
| `files set` | `<workspaceId>` | With `--parent-id <folderId>` and `--name <name>` in place of `--path`, write into a folder by its id |
| `files folders create` | `<workspaceId>` | Create a folder by `--path`, with the folders above it |
| `files move` | `<workspaceId> <fileId>` | Rename with `--name`, move with `--parent-id <folderId>`, or both. To move to the root, send `--body '{"parentId":null}'` |
| `files delete` | `<workspaceId> <fileId>` | Delete a file, or a folder with everything in it |

Each command prints the item's `url`, which opens it in Files. A sandbox, a Cron Run and Sensei can list, read, write and move. Their instructions tell them not to delete, though their credentials reach `files delete`. A folder Sensei keeps and a locked file refuse every caller. A Quick Question from Spotlight can list and read only. A key reaches only the workspaces its owner belongs to.

```bash
kosuke files set <workspaceId> --path notes/plan.md --text "# Plan"
kosuke files set <workspaceId> --path designs/home.png --attach ./home.png
kosuke files list <workspaceId> --folder designs
```

### user files

Your personal [Files](https://kosuke.ai/docs/workspace/files.md#personal-files), which belong to you and to no workspace. Only you see them. They take the same paths, flags and limits as a workspace's `files` commands, with no workspace argument.

| Command | Arguments | What it does |
| --- | --- | --- |
| `files list personal` | none | List one folder of your personal Files, folders first, with its breadcrumb. `--folder` takes a folder id or a path and defaults to the root |
| `files get personal` | `<fileId>` | Read one item's details and its `url`. A text file of up to 1 MB includes its `body`. Any other file includes a short-lived `downloadUrl` and its `expiresAt` |
| `files set personal` | none | Write a file by `--path`, or by `--parent-id` and `--name`, creating the folders on the way. A file of the same name is replaced; `--if-version <n>` refuses a stale replace |
| `files folders create personal` | none | Create a folder by `--path`, with the folders above it |
| `files move personal` | `<fileId>` | Rename with `--name`, move with `--parent-id <folderId>`, or both |
| `files delete personal` | `<fileId>` | Delete a file, or a folder with everything in it. Only your API key can. A sandbox, a Cron Run, Sensei and a Connected App cannot |

An agent reaches the personal Files of the member it acts as: Sensei, a chat session agent in a Turn that member sent, a Cron Run of their Personal Cron, and the Slack agent answering them. An agent acting as the workspace is refused. A Connected App's Connector Token reaches them as your API key does.

```bash
kosuke files set personal --path notes/ideas.md --text "# Ideas"
```

### crons

| Command | Arguments | What it does |
| --- | --- | --- |
| `crons list` | `<workspaceId>` | List a workspace's crons. `--project` keeps the ones that include a project |
| `crons get` | `<workspaceId> <cronId>` | Read one cron with its projects |
| `crons create` | `<workspaceId>` | Create a cron. `--project` names a project and repeats for several; leave it out for a cron that runs with no repository |
| `crons update` | `<workspaceId> <cronId>` | Change a cron. `--project` replaces its projects, `--no-enabled` pauses it and `--enabled` resumes it. A cron disabled with "No projects left" stays disabled until an update picks a project |
| `crons delete` | `<workspaceId> <cronId>` | Delete a cron with its runs and transcripts. Their files stay in Files |
| `crons run` | `<workspaceId> <cronId>` | Fire a cron once now, in every project that is not paused or in the ones `--project` names |
| `crons runs list` | `<workspaceId> <cronId>` | List a cron's runs. `--project` and `--status` filter them and repeat for several |
| `crons runs get` | `<workspaceId> <cronId> <runId>` | Read one run with its Reply and the sessions it filed |
| `crons runs messages list` | `<workspaceId> <cronId> <runId>` | Read the Cron Agent's transcript of one run |
| `crons files list` | `<workspaceId> <cronId>` | List the files all of a cron's runs wrote |
| `crons runs files list` | `<workspaceId> <cronId> <runId>` | List the files a run wrote |
| `crons runs files get` | `<workspaceId> <cronId> <runId> <fileId>` | Read one file of a run |
| `crons runs cancel` | `<workspaceId> <cronId> <runId>` | Stop a run that is still going |

### workspaces

| Command | Arguments | What it does |
| --- | --- | --- |
| `workspaces list` | none | List the workspaces you belong to |
| `workspaces get` | `<workspaceId>` | Read a workspace and your role in it |
| `workspaces members list` | `<workspaceId>` | List members and pending invitations |
| `workspaces credits get` | `<workspaceId>` | Read the credit balance and limit |
| `workspaces usage get` | `<workspaceId>` | Read sandbox usage by day and by project |
| `workspaces sandbox-limit get` | `<workspaceId>` | Read how many sandboxes may run at once, and which are running |
| `workspaces sandboxes stop` | `<workspaceId>` | Pause the sandboxes of the sessions you name |
| `providers access get` | `<workspaceId>` | Read which providers you, or the workspace, can run |
| `providers get` | `<workspaceId>` | Read the workspace's Credentials, with secrets masked |
| `providers set` | `<workspaceId>` | Store or switch workspace Credentials. Admins only |
| `providers delete` | `<workspaceId>` | Remove one set of workspace Credentials. Admins only |
| `providers usage get --provider claude_code` | `<workspaceId>` | Read the workspace Claude login's usage |
| `providers usage get --provider codex` | `<workspaceId>` | Read the workspace Codex login's usage |
| `providers usage get --provider coding_plan` | `<workspaceId>` | Read the workspace GLM Coding Plan's usage |
| `providers usage get --provider kimi_code` | `<workspaceId>` | Read the workspace Kimi Code key's usage |
| `providers usage get --provider deepseek_api` | `<workspaceId>` | Read the workspace DeepSeek API key's balance |
| `providers logins start --provider claude_code` | `<workspaceId>` | Start a Claude login for the workspace. Admins only |
| `providers logins complete --provider claude_code` | `<workspaceId>` | Finish a Claude login with the code from the browser. Admins only |
| `providers logins start --provider codex` | `<workspaceId>` | Start a Codex login for the workspace. Admins only |
| `providers logins complete --provider codex` | `<workspaceId>` | Finish a Codex login once the code is approved. Admins only |
| `skills list` | `<workspaceId>` | List the workspace's Custom Skills |
| `skills get` | `<workspaceId> <skillId>` | Read one Workspace Skill with its files |
| `skills create` | `<workspaceId>` | Add a custom skill from its files. Admins only |
| `skills update` | `<workspaceId> <skillId>` | Turn a skill on or off, or replace a custom skill's files. Admins only |
| `skills delete` | `<workspaceId> <skillId>` | Delete a Custom Skill and its files. Admins only |
| `plugins list` | `<workspaceId>` | List the plugins the official marketplaces offer, and which are on |
| `plugins update` | `<workspaceId> <pluginId>` | Turn a Workspace Plugin on or off. Admins only |
| `integrations connections list` | `<workspaceId>` | List the workspace's integrations with their status |
| `integrations connections get` | `<workspaceId> <toolkit>` | Read one integration by toolkit slug, such as `sentry` |
| `integrations connections delete` | `<workspaceId> <toolkit>` | Disconnect an integration. Admins only |

### user

| Command | Arguments | What it does |
| --- | --- | --- |
| `user profile get` | none | Read your account and preferences |
| `providers get personal` | none | Read your Claude, Codex, GLM Coding Plan, Kimi Code and DeepSeek API Subscriptions and your Default Model |
| `providers delete personal` | none | Disconnect your Subscription for the provider `--provider` names |
| `providers usage get personal` | none | Read your Subscription's usage, or a DeepSeek API key's balance |
| `providers keys set personal` | `<provider>` | Connect your GLM Coding Plan, Kimi Code or DeepSeek API with its key |
| `providers default-model set personal` | none | Save your Default Model |
| `providers logins start personal --provider claude_code` | none | Start connecting your Claude Subscription |
| `providers logins complete personal --provider claude_code` | none | Finish connecting it with the code from the browser |
| `providers logins start personal --provider codex` | none | Start connecting your Codex Subscription |
| `providers logins complete personal --provider codex` | none | Finish connecting it once the code is approved |
| `skills list personal` | none | List your Personal Skills |
| `skills get personal` | `<skillId>` | Read one Personal Skill with its files |
| `skills create personal` | none | Add a Personal Skill from its files |
| `skills update personal` | `<skillId>` | Turn a Personal Skill on or off, or replace its files |
| `skills delete personal` | `<skillId>` | Delete a Personal Skill |
| `plugins list personal` | none | List the plugins you can turn on for yourself |
| `plugins update personal` | `<pluginId>` | Turn a Personal Plugin on or off |
| `integrations connections list personal` | none | List your own integrations with their connections |
| `integrations connections delete personal` | `<toolkit>` | Disconnect one of your own integration connections, named with `--connection-id` |
| `crons create personal` | none | Create a Personal Cron, up to 50 per member. `--project` names your Personal Repositories and repeats for several. With some, it runs in its own sandbox and needs a Model of its own on any released provider, using your own Subscription; with none, it runs in its Sensei Thread |
| `crons update personal` | `<cronId>` | Change a Personal Cron, its projects included. Removing every project returns it to its Sensei Thread |
| `crons delete personal` | `<cronId>` | Delete a Personal Cron with its runs and transcripts; its files stay in Personal Files. Only your API key can. A sandbox, a Cron Run and Sensei cannot |

### integrations

| Command | Arguments | What it does |
| --- | --- | --- |
| `integrations list` | none | Print each toolkit that has connections, with the connections and how many read and write tools it has. `--toolkit <slug>` lists that toolkit's tools, `--search <text>` keeps the tools whose name or description mention the text, `--account <account>` keeps what one connection offers |
| `integrations tools get` | `<name>` | Print one tool's input schema. `--account` picks a connection |
| `integrations call` | `<name>` | Run one tool with `--args '<json>'`, `--args-file <path>` or `-` for stdin. `--account` picks a connection. `--file <argument>=<path>` uploads a local file, up to 5 GiB, for a file argument, such as `videoFilePath=./clip.mp4` or `attachment.0=./report.pdf`, and repeats for several. Waits up to 330 s for the answer, as long as the platform lets a call run |
| `integrations request` | `<toolkit>` | Send one request to a Composio toolkit's own API through your connection, for an action no listed tool does. `--method` is GET, POST, PUT or PATCH, `--path` is relative to the API base URL `integrations list --toolkit <slug>` prints, with `--query name=value` and `--body-file <path>` beside it. `--purpose` is one required line on what no listed tool does, with no names, emails or event titles. A write that gets no answer exits 1 and is never sent again |
| `integrations uploads create` | none | Reserve one file's upload for a tool that takes files, and print the file reference and the URL to PUT the file to. `integrations call --file` does this for you |

### sensei

| Command | Arguments | What it does |
| --- | --- | --- |
| `sensei chat get` | none | Print your own Sensei Chat as JSON: its latest page and its Turn. `--before <messageId>` prints the older messages before that one |
| `sensei cards list` | none | List your open cards in every workspace, in the order of Needs you: a teammate waiting on you, your blocked builds, failures, merges, then messages. `--workspace <id>` keeps one workspace's cards. `--thread <threadId>` lists a thread's open, sending and decided cards. Members get every decided card; Sensei's token gets those closed in the last 7 days. `--since <ISO time>` keeps decided cards placed at or after that time (`postedAt` or, if absent, `createdAt`); open and sending cards always return. Only member credentials can read decision messages |
| `sensei cards set` | none | Open a card in the thread of a Sensei Turn, or update the open card with the same key. Only a Sensei Turn runs it, with `--body-file` holding the headline, blocks, instruction, verb, the negative button's own label and tone when the default Reject or Dismiss misdescribes it, links, target and state key |
| `sensei cards schema` | `[field]` | Print every field `sensei cards set` takes, with its rules and, for a JSON field, its shape. `sensei cards schema blocks` prints one field |
| `sensei threads get` | `<threadId>` | Read a Sensei Thread as text: the member's messages, Sensei's replies and each card's headline. `--tools` adds the tool calls and their results. `--since <messageId>` prints only the replies after that one, and `--before <messageId>` the ones before it |
| `sensei sessions facts get` | `<sessionId>` | Read a session this thread follows: its pull request's head, checks, `mergeable`, `mergeStateStatus`, `reviewDecision`, `reviewRequests` and `isDraft`, its QA report, and the revision an assessment names. Only a Sensei Turn runs it |
| `sensei cards close` | none | Close the open card with `--key`, naming the `--revision` read and a `--reason`. Only a Sensei Turn runs it |
| `sensei device-requests list` | none | List the device requests of `--session-id`, with whether you may answer each one. Only you or a Sensei Turn you started run it |
| `sensei device-requests update` | none | Approve or decline the device request `--request-id` of `--session-id` as you, with `--decision approve` or `decline`. Only you or a Sensei Turn you started run it, the Turn only after your own yes or no; a session's agent or a Cron is refused |
| `sensei tickets merge` | none | Fold the Todo drafts named by `--fold` into the one named by `--keep`, with the merged text from `--content-file`, refused when a prompt changed since the `--revisions` read. Only a Sensei Turn or you run it |
| `sensei messages send` | none | Send one message to a member's Sensei, for any sender: your API key, your own Sensei Turn when you ask, a Cron Run or a chat session's agent. The body names `memberId`, `projectId` (or `sessionId`), a `key` and the `text`, and optionally a `pullRequest`, `title`, `why`, `paths` and an https or Sensei `link`. The recipient's Sensei draws a card whose button carries out the text, or opens the link. The same key with new text updates that card; pass `ifRevision` to be refused when it moved on |
| `sensei messages move` | none | Send a message from a cron or an agent on to another member. Only a Sensei Turn runs it |
| `sensei connect-buttons create` | none | Put Connect buttons in a message of your Turn's own thread, under your words, for each connection the request needs: `github`, `toolkit:<slug>` or `subscription:claude_code|codex|antigravity`. `--required` drops Not now, `--any` carries on once one connects. Only a Sensei Turn runs it |
| `sensei suggestions create` | none | Put suggestion pills in a message of your Turn's own thread, under your words. A tap fills the member's reply; an item with `"newThread": true` starts a thread of its own. Only a Sensei Turn runs it |
| `sensei repository-cards create` | none | Put the Repository card in a message of your Turn's own thread, naming `--workspace <workspaceId>`: it lists the repositories Sensei can write to, and the member imports one from it. Only a Sensei Turn runs it |
| `sensei describe-cards create` | none | Put the Describe card in a message of your Turn's own thread, naming `--workspace <workspaceId>`: the member writes what to build and creates it as a repository from kosuke-starter. Only a Sensei Turn runs it, and it is refused with 403 `KOSUKE_STARTER_OFF` while Start from kosuke-starter is off on the deployment |

### github, models, activity and agent

| Command | Arguments | What it does |
| --- | --- | --- |
| `github connection get` | none | Read your GitHub Connection |
| `github repositories list` | none | List the repositories the Kosuke App can reach through your connection |
| `models list` | none | List the models a chat session can use, as the values `--model` takes |
| `activity list` | none | List Activity across your workspaces. `--unseen` keeps only New events |
| `agent summary get` | none | Print a short digest of what needs you, for an agent to read |

## Run integration tools

`kosuke integrations` lists, describes and runs the tools of the connected [integrations](https://kosuke.ai/docs/workspace/integrations.md). `kosuke integrations list` is an overview: one block per toolkit with the scope, label, account, short id and alias of each connection, and how many read and write tools the toolkit has. The `kosuke agent summary get` digest lists the same connections. Add `--toolkit <slug>` to see a toolkit's tools, `tools get <name>` for a tool's schema, and `call <name> --args '<json>'` to run it. A list that is cut short says how many of how many it shows. `call` exits 0 when the tool ran, 1 when the tool or the platform reported an error (a write whose outcome is unknown says not to retry), and 2 when the command itself was used wrongly, such as an API key without `--workspace`. The hidden `kosuke integrations tools list` and `kosuke integrations tools call` print the raw JSON of the same two routes.

When a toolkit has several connections, pick one with `--account`: its alias such as `notion-personal`, its short id or full id, or `scope:label` such as `personal:Engineering`. Case, curly quotes and extra spaces do not matter. A bare `personal` or `workspace` works when exactly one connection of that scope can run the tool. A missing or ambiguous account is refused with the choices, one per line with its alias, and every `call` prints the connection it ran on (alias, scope, label and account) on stderr, beside the tool's text on stdout.

Inside a chat sandbox, a Cron Run or a Sensei turn, the turn's credential decides what you reach, as in [Who can use a connection](https://kosuke.ai/docs/workspace/personal-integrations.md#who-can-use-a-connection). Sensei with no workspace named uses your personal integrations and the Personal space’s workspace integrations. Naming a workspace uses that workspace’s integrations plus your personal ones, never the Personal space’s. Personal Crons use the Personal space’s integrations plus yours; Workspace Crons and Deploy Chat use workspace integrations only. Restricted integrations need a grant for the call’s workspace, Personal included.

From your laptop with an API key:

- `list` and `tools get` need `--workspace <workspaceId>`. You must belong to that workspace. They show its connections and your own personal ones. With no shared workspace, name your Personal space’s id; the flag is still required.
- `call` runs your own personal connections only. A call on a workspace connection is refused: workspace connections run only inside an agent's turn.
- A Connector Token from the [MCP server](https://kosuke.ai/docs/interfaces/mcp.md) is refused for all three.

```sh
kosuke integrations list --workspace <workspaceId>
kosuke integrations list --workspace <workspaceId> --toolkit gmail
kosuke integrations call notion_search_notion_page --workspace <workspaceId> --account notion-personal --args '{"query":"roadmap"}'
```

## Follow a turn with sessions jobs watch

`kosuke sessions jobs watch` follows one turn as it runs, so a script does not have to poll. The job id is the `chatJobId` that `sessions create` and `sessions send` print when they start a turn. A send that waits Up next prints a `queuedMessageId` instead. Each event is one JSON line on stdout. Messages meant for a person go to stderr.

If the connection drops, `watch` reconnects and picks up where it left off. When the turn ends, a last `watch.links` line carries the session, preview and pull request links. If some events could not be read, a `watch.status` line says `"complete": false`.

| Flag | What it does |
| --- | --- |
| `--timeout <seconds>` | Stop waiting after this many seconds and exit with 124 |
| `--type deploy` | Follow a Deploy turn instead. The job id is the `activeStreamId` that `kosuke deploys messages list` prints |

| Exit code | Meaning |
| ---: | --- |
| 0 | The turn ended, or stopped to ask you a question |
| 1 | The turn failed or was stopped |
| 3 | The API key was refused |
| 4 | The project, session or turn was not found |
| 124 | `--timeout` passed before the turn ended |

## Use it with your coding agent

The [MCP server](https://kosuke.ai/docs/interfaces/mcp.md) covers most of what a coding agent needs. A few things only the CLI does:

- Attach a file, with `--attach`.
- Print every event of a turn as it happens, with `kosuke sessions jobs watch`.
- Read your own Sensei Chat, with `kosuke sensei chat get`.

## Give your agent a digest

`kosuke agent summary get` prints a digest of about 1,500 tokens for an agent to read. Its first line gives the time in your own timezone, named, such as `2026-11-05 09:12 Europe/Rome`. When your timezone cannot be read it gives UTC and says so. It lists:

- the chat sessions that need you
- your connected Subscriptions and their usage across every released provider, and with `--workspace` that workspace's AI providers too
- with `--workspace` (inside an agent's turn, its own workspace), the connected integrations, one line each: toolkit, alias, scope, label and account. A long list ends with "and N more", and a refused or failed read says so rather than leaving the section out
- your oldest New Activity events, one line each
- the workspaces it read

It marks seen only the events it prints. The rest stay New for `kosuke activity list --unseen`. Add `--workspace <id>` to cover one workspace, or `--peek` to mark nothing seen.

To have your coding agent start from it, paste this line into your `AGENTS.md` or `CLAUDE.md`:

```text
Before you answer anything about my Sensei work, run `kosuke agent summary get --peek` and read what it prints.
```

## Configuration

| Setting | Flag | Environment variable | Default |
| --- | --- | --- | --- |
| API key | `--api-key <token>` | `KOSUKE_API_KEY` | The key `kosuke auth login` stored |
| Sensei address | `--api-url <url>` | `KOSUKE_API_URL` | `https://app.kosuke.ai` |
| Config folder | none | `KOSUKE_CONFIG_DIR` | `$XDG_CONFIG_HOME/kosuke`, else `~/.config/kosuke`. On Windows, `%APPDATA%\kosuke` |

A flag wins over its environment variable, and both win over the stored key. The stored key is `credentials.json` in the config folder, readable only by you.

## Update

Run the install command again, then check the version:

```sh
npm install -g @kosuke-ai/kosuke
kosuke --version
```

## Next steps

- [Connect your coding agent](https://kosuke.ai/docs/interfaces/mcp.md)
- [Ship a change end to end](https://kosuke.ai/docs/recipes/ship-a-change-end-to-end.md)
- [Follow a turn](https://kosuke.ai/docs/api/turns.md)

Use `kosuke sensei threads close <threadId>` to mark a thread Done. Open cards, running replies and messages waiting Up next prevent it. Threads have three states: Needs you, Working and Done; event lines and Receipts do not make them unread.
