> ## Documentation Index
> Fetch the complete documentation index at: https://docs.os.meetluno.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI reference

> Full reference for the Luno OS CLI.

The `luno` CLI is the primary way to build, deploy, and operate Luno OS projects. You'll use it to scaffold a project, ship it to the platform, and then invoke and inspect what's running there.

Luno OS is deploy-first: edit your codebase, deploy, then run and inspect against your **cloud** project on the platform.

**Command shape** — resource collections use plural names (matching the HTTP API): `luno <collection> <verb> [<slug>]`. Examples: `luno workflows run greeting`, `luno triggers disable inbound-email-poll`, `luno integrations get github`.

> [!TIP]
>
> Run `luno --help`, or `luno <command> --help`, for the authoritative list of flags on any command.

## Install

Install the `luno` command globally. Requires [Node.js](https://nodejs.org) `^22.18.0 || >=24.0.0` (Node 23 is not supported).

```bash npm theme={null}
npm install -g @meetluno/cli
```

```bash pnpm theme={null}
pnpm add -g @meetluno/cli
```

```bash yarn theme={null}
yarn global add @meetluno/cli
```

```bash bun theme={null}
bun add -g @meetluno/cli
```

To refresh the CLI and every project `@meetluno/*` dependency to npm `latest`:

```bash theme={null}
luno update
```

`luno deploy` / `build` / `lint` / `typecheck` require those packages to be current and will tell you to run `luno update` when they are not.

A CLI installed from the `dev` dist-tag (version `0.1.N-dev`) stays on its channel: it updates itself and the project packages to `dev`, and checks them against `dev`. A package with no `dev` release falls back to `latest`. Set `LUNO_CLI_DIST_TAG` to override the channel.

## Authentication

Log in once and the token is reused for every command. Switching organizations does not require logging in again.

```bash theme={null}
luno auth login              # browser device flow; auto-picks your org
luno auth login --org <slug> # log in and select a specific organization
luno auth status             # show the current user and active organization
luno auth logout             # clear stored credentials
```

| Command | Flags | Description |
| - | - | - |
| `auth login` | `--org <slug>`, `--web-url <url>`, `--platform-url <url>` | Authenticate via the browser device flow |
| `auth status` | `--web-url <url>` | Print authentication status as JSON |
| `auth logout` | `--web-url <url>` | Remove the stored access token |

Your token is stored in your operating system's secure credential store (Keychain, Credential Manager, or secret service).

> [!NOTE]
>
> `auth login` applies to local machines only. Hosted sessions — the in-app [Luno Builder](https://docs.os.meetluno.ai/build-with-ai/platform-agent.md) and [MCP](https://docs.os.meetluno.ai/build-with-ai/mcp-for-agents.md) workspaces — have credentials injected already and cannot complete the browser device flow.

## Project targeting

Most runtime commands (`workflows`, `agents`, `triggers`, `credentials`, `connect`, `health`) run against your deployed cloud project on the platform. There is no local CLI API server — every HTTP command uses the configured platform URL.

**Which platform project you deploy to** is stored in the project's `luno.config.ts` as optional `project` and `organization` slugs — set by `luno projects link` or `luno init --project`. Global CLI config lives in `~/.luno`.

```bash theme={null}
luno config show                 # print effective web/platform URLs + linked project slugs
luno config org                  # list organizations you belong to
luno config preferences get      # show account preferences (JSON)
luno projects link --project <slug>  # link this directory to a platform project
```

| Command | Description |
| - | - |
| `config show` | Print `webUrl`, effective `platformUrl`, and linked project/org slugs |
| `config org` | List organizations you belong to |
| `config preferences get` / `set` | Read or update account preferences |

Defaults are `https://os.meetluno.ai` (web) and `https://api.meetluno.ai` (platform). Switch environments with `luno auth login --web-url <url>` and optional `--platform-url <url>` — both persist in `~/.luno`. Local dashboard: `--web-url http://localhost:3000` (platform URL derives automatically when known).

For a one-off override that doesn't change your config, pass [`--project`](#global-options):

```bash theme={null}
luno --project other-app triggers list      # hit a specific cloud project once
```

## Scaffold a project

Create a project from the default template, then [deploy](#deploy) it.

```bash theme={null}
luno init my-app --yes        # scaffold a project from the default template
cd my-app
luno projects link --project <slug>  # link this directory to a platform project
luno deploy                    # lint + typecheck + build + ship dist/
```

Or seed the link at init time:

```bash theme={null}
luno init my-app --yes --project <slug> --organization <org-slug>
```

`luno init` creates `luno.config.ts`, a committed `tsconfig.json` (extends `@meetluno/cli/tsconfig.json`), a `src/` directory with an example agent, and an `AGENTS.md` guide so your coding agent knows how Luno OS works. Lint, typecheck, and test tooling (oxlint, TypeScript, vitest, `@types/node`) ship inside `@meetluno/cli` — projects do not declare them or ship `.oxlintrc.json` / `vitest.config.ts`. `AGENTS.md` is versioned to your CLI — commands run inside the project re-sync it automatically after a CLI update. For deeper context, use [`luno docs search`](https://docs.os.meetluno.ai/cli#docs) and [`luno docs query`](https://docs.os.meetluno.ai/cli#docs).

| Command | Key flags | Description |
| - | - | - |
| `init` | `--name <name>`, `--template <name>`, `-y, --yes`, `--skip-install`, `--pm <manager>`, `--project <slug>`, `--organization <slug>` | Create a new project from a template (`--yes` for headless/agent use) |
| `build` | `--dir <path>` | Build the project for production |
| `lint` | `--dir <path>` | Lint `src/` with bundled oxlint (config lives in the CLI) |
| `typecheck` | `--dir <path>` | Type-check with bundled TypeScript using the project `tsconfig.json` |
| `test` | `--dir <path>`, `[args...]` | Run tests with bundled vitest (`--project unit` or `integration`); never runs evals |
| `evals run` | `--dir <path>`, `--name <label>`, `--no-upload`, `[filters...]` | Run agent [evals](https://docs.os.meetluno.ai/learn/agents/test-agents.md#evals) (`src/**/*.eval.ts`) against real models and upload the results to the linked project; fails when a score is under its threshold |
| `evals list` | `--agent <slug>`, `--limit <n>` | The linked project's eval runs (newest first) as JSON |
| `evals get` | `<run-id>` | One eval run with every case, tool call and score as JSON |
| `update` | `--dir <path>` | Update `@meetluno/*` project deps and the CLI to latest |
| `health` | | Check connectivity to the platform |

> [!NOTE]
>
> `package.json` scripts (`pnpm lint`, `pnpm typecheck`, `pnpm test`) call these commands. Config files stay in the CLI bundle — nothing is written into your project when you run them.

## Deploy

For **managed-Git** projects, the CLI compares the pinned `main` and draft commits locally, analyzes filtered impact, then acquires a platform deploy lease and ships the candidate artifact. Expanded or unknown filtered impact requires confirmation or `--accept-impact`. For **snapshot-only** projects, deploy runs lint and typecheck, builds, uploads the `dist/` artifact, and activates it. Link the directory first (or pass `--project` for a one-off deploy). After deploy, runtime commands target your linked cloud project.

You do not need to run `luno lint`, `luno typecheck`, or `luno build` first — deploy runs the required checks and build.

```bash theme={null}
luno projects list                     # list projects in your organization
luno projects create --name "My app"   # create a deploy target
luno projects link --project <slug>    # write project + org slugs to luno.config.ts
luno deploy                           # preflight, build, upload, and activate
luno deploy --accept-impact --filter workflows/ping   # accept expanded/unknown impact
luno deploy --build-from-workspace    # build against local monorepo packages
luno deploy --allow-data-loss         # also run destructive defineTable DDL (drops, retypes)
luno deploy --project other-app       # one-off deploy to a different project
```

| Command | Key flags | Description |
| - | - | - |
| `projects link` | `--project <slug>`, `--dir <path>` | Link this directory to a platform project in `luno.config.ts` |
| `deploy` | `--dir <path>`, `--filter <entry>`, `--accept-impact`, `--build-from-workspace`, `--allow-data-loss`, `--project <slug>` | Preflight, build, upload, and activate a deploy |
| `projects list` | `--admin` | List projects in the active organization |
| `projects create` | `--name <name>`, `--description <desc>` | Create a platform project |
| `projects update` | `--name <name>`, `--description <desc>` | Update a project's name or description |
| `projects delete` | `-y, --yes` | Delete a project |
| `projects metrics` | `--project <slug>`, `--admin` | Show rollup metrics for projects |
| `projects deployments list` | `--project <slug>` | View deployment history for a project |

Pass `--filter <entry>` with workflow/agent keys (`workflows/…`, `agents/…`). Managed filtered deploys analyze shared dependencies locally and may require confirmation (`--accept-impact` in non-TTY). Snapshot filtered deploys merge a targeted local build into the active artifact.

For a project nested in a package-manager monorepo, `--build-from-workspace` builds against the current checkout so `workspace:`, `link:`, and local `file:` dependencies resolve. This escape hatch only supports full deploys and local package sources are not captured in Luno OS's managed source, so the artifact is not reproducible from that source alone. Prefer published dependency versions when possible.

## Pull

`luno pull` fetches the shared unpublished draft (`luno/draft`) and merges it into your local checkout, then installs dependencies. Pass `--published` to fetch the exact commit on the active deploy instead. Managed Git state lives in `.luno/git`, so your configured remotes are left unchanged.

```bash theme={null}
luno pull --project <slug>             # into the current directory
luno pull --project <slug> --dir ./my-app
luno pull --project <slug> --published # active published revision
```

| Command | Key flags | Description |
| - | - | - |
| `pull` | `--dir <path>`, `--published` | Merge the shared draft, or the active revision with `--published` |

`pull` targets the linked project in `luno.config.ts` when `--project` is omitted. Git-less directories are bootstrapped into the managed sidecar. If the merge conflicts, Git leaves conflict markers in place — resolve them, `git add`, and `git commit` (or `git merge --abort`). Legacy snapshot-only artifacts still use the bulk source download when `--published` is set.

## Invoke and inspect

Run your workflows and agents, fire triggers, and audit run history against your deployed cloud project.

### Workflows

```bash theme={null}
luno workflows list
luno workflows run greeting --input '{"name":"Ada"}' --wait --timeout 60
luno workflows runs list greeting
luno workflows runs get greeting <run-id> --wait --timeout 60
luno workflows runs get <run-id> --summary
luno workflows runs get greeting <run-id> --field output
luno workflows runs get greeting <run-id> --include steps,trace,children
luno workflows runs hooks greeting <run-id>
luno workflows runs cancel greeting <run-id>
luno workflows forms list
luno workflows forms publish greeting --title "Greeting"
luno workflows forms url greeting
```

| Command | Key flags | Description |
| - | - | - |
| `workflows run` | `--input <json>`, `--wait`, `--timeout <seconds>`, `--summary` (with `--wait`) | Invoke a workflow and optionally wait for completion |
| `workflows runs list` | `--limit <n>`, `--cursor <cursor>`, `--status <s>`, `--trigger <t>` | List runs for a workflow |
| `workflows runs get` | `--wait`, `--timeout <seconds>`, `--summary`, `--field <field>`, `--include <parts>` (`trigger,steps,trace,children,none`) | Inspect a run; waiting requires `<workflow> <run-id>` |
| `workflows runs hooks` | | Hook tokens + resume URLs for a run |
| `workflows runs cancel` | `<workflow> <run-id>` | Cancel a running or queued run |
| `workflows runs restart` | `<workflow> <run-id>`, `--step <id>`, `--input <json>` | Run a finished run again under the same id: a failed run from the step that failed, or any run from `--step` (time travel) |
| `workflows forms list` | `--admin` | List forms in scope (`--admin` ignores linked project; explicit `--project` still narrows) |
| `workflows forms get` | | Get a workflow's form JSON |
| `workflows forms url` | | Print a published form's public URL |
| `workflows forms publish` | `--title`, `--description`, `--config <json>`, `--field-config <json>` | Publish or update a public form |
| `workflows forms unpublish` | | Stop accepting form submissions |
| `workflows forms rotate` | | Rotate a form's public link token |

See [workflow forms](https://docs.os.meetluno.ai/learn/workflows/forms.md) for when to use forms, field presentation, and dashboard publish.

`--wait` is bounded and defaults to 60 seconds for workflows. Set a different duration with `--timeout <seconds>`. If the timeout elapses, the command returns the latest running state with exit code `0`; continue with `workflows runs get <workflow> <run-id> --wait`. A failed or canceled run exits with code `1`.

### Agents

```bash theme={null}
luno agents list
luno agents prompt support --message "Hi" --wait --timeout 120
luno agents prompt support --message "and then?" --session-id <session-id> --wait
luno agents prompt triage --message "Login is broken" --wait --output-schema-file ./triage-output.json
luno agents sessions get support <session-id> --wait --timeout 120
luno agents sessions get support <session-id> --summary
luno agents sessions get support <session-id> --include messages,trace
```

| Command | Key flags | Description |
| - | - | - |
| `agents prompt` | `--message <text>`, `--session-id <id>`, `--output-schema <json>` / `--output-schema-file <path>`, `--wait`, `--timeout <seconds>`, `--summary` (with `--wait`) | Send a message and optionally wait for completion; with an output schema (JSON Schema, `type: "object"`), `--wait` prints the validated [structured output](https://docs.os.meetluno.ai/learn/agents/build-agents.md#structured-output-over-http-the-sdk-and-the-cli) |
| `agents sessions list` | `--limit <n>`, `--cursor <cursor>`, `--status <s>`, `--source <s>` | List sessions for an agent |
| `agents sessions get` | `--wait`, `--timeout <seconds>`, `--summary`, `--field <field>`, `--include <parts>` (`gateway,messages,events,trace,none`) | Inspect a session or continue waiting for it |
| `agents sessions cancel` | `<agent> <session-id>` | Cancel a running session |
| `agents approvals list` | `<agent> <session-id>`, `--all` | Tool calls waiting for a human decision (`needsApproval`) and who may approve them; `--all` adds decided calls with who decided, where and when |
| `agents approvals approve` / `deny` | `<agent> <session-id> <approval-id>`, `--reason <text>` | Decide a paused tool call; the session resumes once nothing else is pending. Fails with 403 when the tool has approvers, or the agent has a "who can approve" list, and you are not on it |

Agent waits default to 120 seconds. A wait timeout means the session is still running and exits with code `0`; continue with `agents sessions get <agent> <session-id> --wait`. Failed and canceled sessions exit with code `1`.

### Actions

Find apps with `integrations search` (the apps your organization can connect: official and custom) and inspect one with `integrations get`. There is no hosted action catalog: an official app's actions (`github`, `gmail`, …) ship as TypeScript in its curated `@meetluno/integration-*` package and run from your project's workflows and agents, so `integrations actions list <official-app>` explains where they live and `integrations actions get` / `integrations execute` do not apply to official apps. Custom MCP apps support live `integrations actions list` and `integrations execute` against the remote server.

| Command | Official app (`github`) | Custom MCP (`my-org/example-mcp`) | Other custom org app (`wells/demo-echo`) |
| - | - | - | - |
| `integrations search <query>` | Listed (`{ items: [{ id, name, description, category, … }], nextCursor? }`) | Listed | Listed |
| `integrations get <slug>` | `{ kind: "catalog", app: { id, name, authKind, oauthScopes, … } }` | `{ kind: "custom", app: { …, source: "mcp", … } }` | `{ kind: "custom", app: { slug, authKind, credentialFields, … } }` |
| `integrations actions list <slug>` | Guidance only (`kind: "official"`) — actions live in the integration package | Live remote `tools/list` (`kind: "mcp"`) — **not** authored TypeScript yet | Guidance only (`kind: "custom"`) — use `integrations sync` / project actions |
| `integrations execute` | Not applicable — run your workflow/agent instead | Supported (remote `tools/call`) | Not applicable — run your workflow/agent instead |

```bash theme={null}
luno integrations search git                       # find an app and its slug
luno integrations get github                       # official app: auth kind, scopes
luno integrations get wells/demo-echo              # custom credential template
luno integrations actions list my-org/example-mcp  # after connect: every remote MCP tool (may lack TS wrappers)
luno integrations execute my-org/example-mcp list_accounts --input '{}'
luno integrations actions list wells/demo-echo     # explains there are no catalog tools
```

Credential resolution matches the runtime: it uses the **project default**, then the **org default**. Project credentials only resolve when you target a project with the global `--project <slug>` flag (or run inside a linked project); without it, only org credentials resolve. **User credentials are never a default** — reach one explicitly with `--credential <slug>`. If the app is not connected, `integrations execute` exits with a hint to run `luno connect <app>`. Executing has side effects, so a user credential only runs for its owner and an org or project credential needs `project:run` in the project (without `--project`, org-wide: owner or admin); otherwise it answers 403 — see [who can execute a tool](https://docs.os.meetluno.ai/learn/credentials/custom-integrations.md#who-can-execute-a-tool).

```bash theme={null}
luno integrations execute my-org/example-mcp list_accounts                          # org default
luno integrations execute my-org/example-mcp list_accounts --project my-app         # project default (falls back to org)
luno integrations execute my-org/example-mcp list_accounts --credential work-mcp    # pin a specific instance by slug
```

Pass `--credential <slug>` to pin a specific instance when a scope has more than one — the slug is the one you set with `luno credentials create <key> --slug <slug>` and can see with `luno credentials list`. It's also the only way to use a user-scoped credential.

| Command | Key flags | Description |
| - | - | - |
| `integrations execute` | `--input <json>`, `--credential <slug>`, `--project <slug>` | Run a custom MCP app's remote tool |

### Triggers

```bash theme={null}
luno triggers list
luno triggers list --endpoint stripe   # webhooks on a shared endpoint
luno triggers url incoming-message     # print a webhook URL
luno triggers invoke inbox-sync        # fire a poll/cron/webhook on demand
luno triggers invoke signup --input '{"email":"a@b.com"}'
# invoke returns { runId, triggerSlug, targets }; then:
luno triggers runs get signup <runId>  # workflowRuns[] once dispatched
luno triggers runs list inbound-email-poll
luno triggers runs list inbound-email-poll --workflow signup-pipeline
luno triggers disable signup                        # pause the trigger (all attachments)
luno triggers disable signup --workflow signup-pipeline   # pause just one attachment
luno triggers enable signup                         # resume
```

| Command | Key flags | Description |
| - | - | - |
| `triggers list` | `--endpoint <endpoint>` | List discovered triggers |
| `triggers get` | | Get a trigger by key, or all webhooks on an endpoint |
| `triggers url` | | Print the webhook URL for a trigger |
| `triggers invoke` | `--input <json>`, `--workflow <slug>`, `--agent <slug>` | Manually invoke a trigger (platform only; `--input` is webhook-only). Returns trigger `runId` + `targets` (workflow run ids appear later via `triggers runs get`). |
| `triggers disable` | `--workflow <slug>`, `--agent <slug>` | Pause a trigger — all attachments, or one target |
| `triggers enable` | `--workflow <slug>`, `--agent <slug>` | Resume a trigger — all attachments, or one target |
| `triggers runs list` | `--limit <n>`, `--cursor <cursor>`, `--trigger-type <type>`, `--outcome <outcome>`, `--workflow`, `--agent` | List runs for a trigger (`--outcome` is `dispatched`, `skipped`, or `failed`) |
| `triggers runs get` | `--include <parts>` (`workflows,trace`), `--workflow`, `--agent` | Full details for a single trigger run |

Machine-oriented commands print JSON on stdout and human hints on stderr (so `| jq` stays clean).

### History (cloud)

```bash theme={null}
luno history list --kind workflow --status failed
luno history get <run-id>
```

| Command | Key flags | Description |
| - | - | - |
| `history list` | `--project <id>`, `--status <s>`, `--kind <workflow\|agent>` | List runs across projects in the organization |
| `history get` | | Get details for a single run |

## Integrations and secrets

Connect third-party accounts and manage the credentials your agents and workflows use.

```bash theme={null}
luno integrations list                                  # apps registered in your org
luno integrations search "github"                       # search the live catalog
luno integrations actions list github --search issue         # actions an app exposes
luno connect google                            # connect an app (opens the web flow)
luno connect google --print-url                # headless: print the URL to share instead
luno credentials create exa --set apiKey=@env:EXA_API_KEY
luno credentials list
```

| Command | Key flags | Description |
| - | - | - |
| `integrations list` | | List apps registered/connectable in your org |
| `integrations search "{query}"` | `--category <c>`, `--limit <n>`, `--cursor <c>` | Search the apps your org can connect (slug, name, description) |
| `integrations get <slug>` | | Get one app: official catalog entry (`kind:catalog`) or custom org template (`kind:custom`) |
| `integrations actions list [slug]` | `--search <q>` | Custom MCP (after connect): live remote tools (`kind:mcp`) — not TypeScript yet. Official: `kind:official` guidance (actions live in the integration package). Other custom: `kind:custom` guidance |
| `integrations actions get <app> <tool>` | | Explains where an official app's actions live (no hosted schema) |
| `integrations execute <app> <tool>` | `--input <json>`, `--credential <slug>`, `--project <slug>` | Run a connected custom MCP app's remote tool |
| `integrations create` | `--name`, `--slug`, `--description`, `--logo <url>`, `--field <f>`, `--mcp <url>`, `--openapi <url>`, `--graphql <url>`, `--auth <kind>`, `--preview` | Create a custom app (manual fields or auto-detect from URL) |
| `integrations delete <slug>` | | Delete a custom org app and its credentials |
| `integrations sync <slug>` | `--dir <path>` | Write `src/integrations/<name>/integration.ts` from the platform template |
| `connect <slug>` | `--print-url`, `--kind <kind>`, `--wait` | Open the web flow to connect an app (scope chosen there) |
| `credentials list` | `--key <key>` | List stored credential instances |
| `credentials get` | | Show a credential instance |
| `credentials create` | `--set <field>`, `--scope <scope>`, `--project-slug <slug>`, `--label <label>`, `--default` | Create an `api_key` credential instance |
| `credentials reconnect` | `--print-url` | Open the web flow to reconnect an existing credential (or print the URL in headless environments) |
| `credentials update` | `--label`, `--default`, `--set <field>`, `--scope <scope>`, `--project-slug <slug>` | Rename, set default, rotate secret fields, or move scope in place (single `--scope`) |
| `credentials duplicate` | `--name` / `--label`, `--scope <scope>`, `--project-slug <slug>` | Copy a credential into one or more scopes (`"{name} (copy)"` if unnamed) |
| `credentials rotate` | | Rotate a credential's key |
| `credentials delete` | | Delete a credential instance |

`connect` requires an app slug (see `luno integrations list` for connectable slugs) and chooses scope in the web flow — scope and project pinning are set on `credentials create`, not `connect`. In headless or hosted sessions (coding agents, the in-app Luno Builder, CI), always pass `--print-url` and hand the printed URL to the user — those environments cannot open a browser. `connect slack` opens the three-way Slack chooser; `--kind luno|personal|custom` opens one dialog directly (`luno` = the Luno OS Slack App — catalog slug `slackbot`, `personal` = Personal Slack Account, `custom` = Custom Slack App wizard), and `--wait` (Luno OS Slack App only) polls until the gateway workspace registers. For credential values, `--set key=value` takes a literal, and `--set key=@env:VAR` reads from your shell (falling back to the project `.env`). `credentials update --scope` moves one existing instance (exactly one of `org`, `user`, or `project`); `credentials duplicate` fans out copies like `create`. See [connect and manage apps](https://docs.os.meetluno.ai/learn/credentials/connect-credentials.md#change-a-credentials-scope). `integrations create`'s `--field` syntax is `key`, `key:secret`, `key:optional`, or `key:secret:optional` (repeatable). For manual custom apps, `--name` and at least one `--field` are required; `--description` defaults to `--name` when omitted. Optional `--logo <url>` sets a public image URL for the Integrations catalog (same as **Logo URL** in the web create dialog). Example: `luno integrations create --name Acme --description "Internal Acme API" --logo https://example.com/acme-logo.png --field apiKey:secret`. With `--mcp`, `--openapi`, or `--graphql`, auth and credential fields are auto-detected from the URL (this registers a connectable org catalog app, not only local scaffolding); use `--preview` to print the assembled request without creating, and `--name`, `--slug`, `--description`, `--logo`, `--field`, or `--auth` (MCP only) to override detected values. After create, connect with `luno connect <slug>`, then author actions with `defineIntegration` / `integrations sync` — see [custom apps and MCP](https://docs.os.meetluno.ai/learn/credentials/custom-integrations.md).

LLM provider API keys (BYOK for model inference) are **not** app credentials — connect those with [`luno managed-services`](#managed-services-cloud) instead.

## Managed services (cloud)

Bring your own LLM provider API keys for organization-wide inference. See [Managed services](https://docs.os.meetluno.ai/learn/settings/managed-services.md).

```bash theme={null}
luno managed-services list
luno managed-services connect xai --api-key "xai-..."
luno managed-services update xai --api-key "xai-..."
luno managed-services disconnect xai
```

| Command | Key flags | Description |
| - | - | - |
| `managed-services list` | `--kind <kind>` | List connected provider keys |
| `managed-services connect <provider>` | `--api-key <key>` | Connect a provider (`openai`, `anthropic`, `google`, `groq`, `xai`) |
| `managed-services update <provider>` | `--api-key <key>` | Rotate the key for a connected provider |
| `managed-services disconnect <provider>` | | Disconnect a provider and fall back to platform keys |

## Channels

Bind agents to external channels (like Slack) so people can talk to them where they already work. See [external channels](https://docs.os.meetluno.ai/learn/agents/external-channels.md).

```bash theme={null}
luno connect slack --kind luno --wait      # Luno OS Slack App OAuth; wait until workspace appears
luno channels setup support --channel support   # create/bind Luno OS path
luno channels setup support --custom            # open custom-app wizard URL
luno channels platforms list
luno channels accounts --platform slack
luno channels directory --platform slack --account <team-id>
luno channels list support
luno channels bind support --platform slack --account <team-id> --channel <id>
luno channels unbind support <binding-id>
luno channels update-binding support <binding-id> --replies mentions
luno channels update-binding receptionist <dm-binding-id> --dm-agents hr,contracts
luno channels create-slack-app hr --config-token <token>   # dedicated @HR Slack app
```

`channels bind` / `update-binding` use `--replies mentions|mentions-followups` (same choices as the External Channels UI) and `--listen mentions|all` (**Respond to**: only @mentions, or every message in the channel). Bind defaults to `mentions-followups` and mentions. On a direct-messages binding, `--dm-agents` sets the agents people can switch to in DMs (`""` clears); see [several agents in one workspace](https://docs.os.meetluno.ai/learn/agents/external-channels.md#several-agents-in-one-workspace).

## Organization and access

Manage members and platform API keys for your active organization. Most of these are org-admin operations.

```bash theme={null}
luno organization members list
luno organization members invite --email teammate@acme.com --role builder
luno api-key create --name "CI"
luno api-key list
```

| Command | Key flags | Description |
| - | - | - |
| `organization update` | `--name <name>` | Rename the active organization |
| `organization members list` | | List members |
| `organization members invite` | `--email <email>`, `--role <role>` | Invite members (`admin` or `builder`) |
| `organization members role` | `--role <role>` | Change a member's role |
| `organization members remove` | | Remove a member |
| `api-key list` | | List org-scoped platform API keys |
| `api-key create` | `--name <name>`, `--scope <read\|write\|admin>` (default `write`), `--expires-in <days>`, `--service-account <builder\|admin>`, global `--project <slug>` with repeatable `--agent <slug>` / `--workflow <slug>` | Create an API key, optionally restricted to one project and some of its agents/workflows |
| `api-key revoke` | `-y, --yes` | Revoke an API key |

## Docs

Read the Luno OS documentation from the CLI. These commands need **no authentication, organization, project, or config** — they work the moment the CLI is installed, for you and your coding agent alike.

```bash theme={null}
luno docs search "webhook trigger"      # find pages by topic
luno docs query "cat /quickstart.mdx"   # read a page by path
```

| Command | Description |
| - | - |
| `docs search <query>` | Search the docs for relevant pages and examples |
| `docs query <command>` | Read the docs filesystem with a shell-style command (`cat`, `rg`, `ls`, `tree`, `head`) |

See [docs for agents](https://docs.os.meetluno.ai/build-with-ai/docs-for-agents.md) for how `query` works (stateless calls, output caps) and more examples.

## Feedback

Coding agents can report build friction directly to the Luno OS team. Use this after a build loop when the agent encountered unclear documentation, confusing errors, unexpected framework constraints, missing capabilities, or non-obvious workarounds.

`feedback create` requires authentication and an active organization. The platform attaches the signed-in user's identity and organization automatically; the CLI also includes its version and the linked project slug when available.

```bash theme={null}
luno feedback create --message "$(cat <<'EOF'
*Quick Recap and Context*

We were building a workflow that turns a social media post into a structured roleplay scenario.

-------------------------

*Feedback for Luno OS Team*

*1. One-action-per-file only failed at deploy*
We grouped related actions in one file because local build passed. Deploy rejected it, so we split the actions into separate files. Catching this during lint or documenting it more prominently would have saved a deploy cycle.
EOF
)"
```

The message is freeform; the recap and numbered feedback above are a suggested structure. Write it for a Luno OS team member with zero context on the session: plain language first, technical detail (paths, commands, error text) second, one numbered item per issue. Run `luno feedback create --help` for the full writing guide. Do not include secrets, tokens, credentials, private source dumps, proprietary code, or personal data from project files or user inputs. Success prints `{ "ok": true }`.

| Command | Key flags | Description |
| - | - | - |
| `feedback create` | `--message <text>` | Send an authenticated build-experience report to Luno OS |

See [CLI for agents](https://docs.os.meetluno.ai/build-with-ai/cli-for-agents.md#report-build-friction) for when coding agents should use this command.

## Global options

`--project` applies to platform-targeting commands; docs commands ignore organization/project scope. `--version` and `--help` work on every command.

| Flag | Description |
| - | - |
| `--project <slug>` | Target a specific cloud project for this command (does not change your default) |
| `--version` | Print the CLI version and exit |
| `--help` | Show help for the CLI or a specific command |

> **[Using the CLI with AI agents](https://docs.os.meetluno.ai/build-with-ai/cli-for-agents.md)**
>
> Luno OS is built for coding agents. Learn how agents use the CLI, the docs commands, and headless mode to build and operate your project.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.