---
name: tenki-onboarding
description: >-
  Get a user up and running with Tenki Cloud: launch Tenki Sandbox VMs
  from the CLI or SDKs, migrate GitHub Actions workflows to Tenki runners
  (faster, cheaper CI on bare metal), and enable Tenki Code Reviewer on pull
  requests. Use when the user mentions Tenki, needs an isolated environment
  to run agents or untrusted code, asks for faster or cheaper GitHub Actions,
  or wants AI code review on GitHub.
license: MIT
compatibility: >-
  Account creation or sign-in, device approval, and GitHub App installs are
  browser steps delegated to the user. Sandbox needs the Tenki CLI or a
  Go/TypeScript/Python SDK; Runners and Code Reviewer need a GitHub organization
  connected to the Tenki workspace.
metadata:
  author: Tenki Cloud
  version: "1.1"
---

# Tenki Cloud onboarding

Tenki Cloud has three products:

- **Tenki Sandbox** — disposable Linux VMs for AI agents, untrusted code, and one-off compute, driven by a CLI or Go/TypeScript/Python SDKs.
- **Tenki Runners** — drop-in replacements for GitHub-hosted Actions runners on bare metal. ~30% faster builds, up to 60% cheaper.
- **Tenki Code Reviewer** — an AI agent that reviews every pull request on GitHub.

## Pick the right product

| User goal                                               | Product       | What you do                                         |
| ------------------------------------------------------- | ------------- | --------------------------------------------------- |
| Isolated VM for agents, untrusted code, or one-off jobs | Sandbox       | Install the CLI or SDK, create a session            |
| Faster / cheaper GitHub Actions CI                      | Runners       | Edit `runs-on:` labels in `.github/workflows/*.yml` |
| AI review on every pull request                         | Code Reviewer | Walk the user through the GitHub App install        |

## Agent vs. human steps

You can edit workflow files, install and drive the CLI/SDKs, and verify results. These steps need the user in a browser:

1. Create or sign in to a Tenki account: run `tenki onboard`, then open the emitted login URL in the user's browser (`open`/`xdg-open`) rather than only printing it. For a new user, the Tenki-owned URL starts GitHub sign-up directly; the user can choose another sign-in method if needed. Tenki automatically provisions and uses the new account's default workspace.
2. Approve the CLI sign-in: the user reviews the requesting device and clicks **Approve device**. A new account or an existing account with one workspace does not require workspace selection; only an existing user with multiple workspaces must choose which workspace will scope the device key. You never need an API key pasted to you; onboarding stores everything in the CLI config.
3. Install the relevant Tenki GitHub App from the dashboard (Runners and Code Reviewer). A Tenki workspace connects to exactly one GitHub organization, and vice-versa.

Ask the user to complete the step you're blocked on, then continue.

## Onboarding: `tenki onboard`

Install the CLI (or an SDK):

```bash
curl -fsSL https://tenki.cloud/install.sh | bash   # installs ~/.local/bin/tenki
```

SDKs: `npm install @tenkicloud/sandbox` · `go get github.com/LuxorLabs/tenki-sdk-go/sandbox` · `pip install tenki` (Python 3.10+)

Then run the agent-first flow:

```bash
export TENKI_OUTPUT=json   # structured output for every command this session
tenki onboard              # emits JSONL events with instruction + next_command
```

1. The CLI registers a login request and emits a `login_url` event with a Tenki-owned link to `https://app.tenki.cloud/auth/cli-login`.
2. Open that URL in the user's browser yourself — don't just print it and wait:

   ```bash
   open "<login_url>"        # macOS
   xdg-open "<login_url>"    # Linux desktop
   ```

   Print the URL as well, so the user can approve from a phone or another machine, and skip the open command on a headless box (SSH, container, sandbox) where it would fail. If they aren't signed in, the link starts GitHub OAuth directly (other sign-in methods are available). For a new user, Tenki creates the account and provisions its default workspace automatically.

3. The approval page names the requesting device and the workspace that will scope its key. A new workspace, or an existing user's only workspace, is used automatically; only an existing user with several workspaces must choose one (until then **Approve device** stays disabled). Approving mints a workspace API key named "Tenki CLI · &lt;device&gt;", valid for 30 days.
4. Poll: each run polls once and exits, so re-run `tenki onboard` about every 2 seconds until you get `login_complete`, giving up after the `expires_in_s` from the `login_url` event. A `login_pending` event means keep going. Every step is checkpointed in the CLI config, so nothing blocks and no state is lost — do not stop and ask the user to tell you when they have approved.
5. The CLI stores the key itself and ends with a `ready` event suggesting the next commands.

Follow each event's `instruction` and `next_command` rather than parsing prose.

| Event            | Fields (beyond `instruction` / `next_command`)         | Meaning                                                               |
| ---------------- | ------------------------------------------------------ | --------------------------------------------------------------------- |
| `login_url`      | `url`, `expires_in_s`                                  | Open or show this URL; the user authenticates and approves the device |
| `login_pending`  | —                                                      | Not approved yet — keep polling (re-run about every 2 seconds)        |
| `login_complete` | `email`                                                | The device was approved and the CLI is signed in                      |
| `account`        | `workspace_id`, `workspace_name`, `selection_warning?` | The workspace the device's key is scoped to                           |
| `api_key`        | `key_prefix`, `note`                                   | The browser-minted API key was stored in the CLI config               |
| `ready`          | `commands`                                             | Onboarding is complete; `commands` maps names to suggested commands   |
| `error`          | `code`, `message`                                      | Something failed; `instruction` says how to recover                   |

A full session, as the agent sees it (the CLI emits one object per line; the first is expanded here for readability):

```json
{
  "event": "login_url",
  "url": "https://app.tenki.cloud/auth/cli-login?poll=...",
  "expires_in_s": 900,
  "instruction": "Open this URL for the user. They authenticate with GitHub and approve the device; only existing users with multiple workspaces must choose one. Then run next_command.",
  "next_command": "tenki onboard"
}
```

…user approves in the browser, you re-run `tenki onboard`…

```json
{"event":"login_complete","email":"you@example.com"}
{"event":"account","workspace_id":"ws_...","workspace_name":"acme"}
{"event":"api_key","key_prefix":"tk_AbC1","note":"Full key stored in CLI config; never printed."}
{"event":"ready","commands":{"create":"tenki sandbox create --name demo --cpu 2 --memory-mb 4096","status":"tenki status"},"instruction":"Onboarding complete. Create the first sandbox with commands.create."}
```

Security properties worth relaying to a cautious user:

- **No secrets on stdout.** The `api_key` event carries only the key's prefix; the full key goes straight into the CLI config, so nothing sensitive lands in your transcript or logs.
- **Explicit device approval.** Authentication alone mints nothing — the page names the device and workspace and requires a click. If the user sees an approval page they didn't initiate, they should close it.
- **Opaque, single-use polling.** The CLI holds a poll token, not a credential; the server delivers the key exactly once and the request expires after 15 minutes.
- **Scoped, expiring credential.** The key is scoped to the approved workspace for 30 days. Re-run `tenki onboard` to renew; manage or revoke it at https://tenki.cloud/docs/account/api-keys like any other key.

Alternatives:

```bash
tenki login                    # interactive browser sign-in (human at the terminal)
export TENKI_API_KEY=tk_...    # CI/automation with an existing key; the SDKs read this automatically
```

`TENKI_API_KEY` is the onboarding or dashboard-generated key beginning with `tk_`. Verify it with `tenki status`.
The key is bound to one workspace, and normal CLI and SDK requests infer that workspace automatically.

### Structured output

`tenki onboard` always emits JSON Lines. Every other command emits JSON automatically whenever stdout is piped or redirected, so `tenki sandbox list | ...` is structured without asking; an interactive terminal stays human-readable. Precedence: an explicit `--json`/`--output` flag beats `TENKI_OUTPUT` (`json | yaml | text`), which beats pipe detection, which beats the text default. `TENKI_OUTPUT=text` forces prose even when piped.

### Underlying RPCs (debugging only)

`tenki onboard` is the supported interface; these three Connect RPCs on `https://api.tenki.cloud` are what it drives, useful only when diagnosing a broken flow. Request/response bodies use protojson lowerCamelCase (snake_case accepted on input), while the CLI's own JSONL events are always snake_case.

- `tenki.cloud.identity.v1beta1.IdentityService/StartCliLoginPoll` — `{"deviceName": "..."}` → `{"loginUrl": "...", "pollToken": "...", "intervalS": 2, "expiresInS": 900}`. The Tenki-owned `loginUrl` preserves the poll request while starting GitHub OAuth; no raw GitHub authorization URL is ever exposed.
- `.../PollCliLogin` — `{"pollToken": "..."}` → `{"status": "pending"}`, then once `{"status": "complete", "apiKey": "tk_...", "email": "...", "workspaceId": "...", "workspaceName": "..."}`, or `{"status": "expired"}`. Empty fields are omitted, so `pending` and `expired` carry only `status`.
- `.../CompleteCliLoginPoll` — called by the dashboard's Approve-device page, never by clients.

## Tenki Sandbox: first session

Onboarding above leaves the CLI signed in with a workspace-scoped key. Minimal flow:

```bash
tenki sandbox create --name demo --cpu 2 --memory-mb 4096   # waits for RUNNING, prints session ID
tenki sandbox set <session-id>                              # persist as current session
tenki sandbox exec -c 'uname -a && whoami'                  # -c runs the line through a shell
echo 'hello' | tenki sandbox write --path hello.txt
tenki sandbox read --path hello.txt
tenki sandbox expose --port 3000                            # prints a public preview_url
tenki sandbox terminate
```

Gotchas:

- File operations are rooted at `/home/tenki`. Relative paths resolve there; absolute paths outside it are rejected. `/workspace/...` exists only when a volume is mounted.
- Backgrounding a server? Redirect output and detach stdin (`>/tmp/server.log 2>&1 </dev/null &`), otherwise `exec` streams its output forever.
- Without `-c`, `exec` runs the program directly — no pipes, globs, `$VAR`, or `&&`.
- Do not pass a workspace ID; Sandbox requests infer it from the API key.

Billing is metered per second — the user pays only while a session is active. The hourly figures below are what the per-second rates aggregate to, shown for easy comparison: Nano $0.08/hr, Small $0.17/hr (default — 2 vCPU / 4 GiB / 5 GiB), Medium $0.33/hr, Large $0.66/hr, XLarge $1.32/hr.

## Tenki Runners: migrate a repo

Prerequisites (human): Tenki account + Tenki GitHub App installed on the organization.

1. Find the workflow files in `.github/workflows/`.
2. In each job, replace the `runs-on:` value with a Tenki label:

```yaml
jobs:
  build:
-    runs-on: ubuntu-latest
+    runs-on: tenki-standard-medium-4c-8g
```

No other workflow changes are needed — GitHub Actions secrets work natively.

| Label                               | Compute | Memory  |
| ----------------------------------- | ------- | ------- |
| `tenki-standard-autoscale`          | dynamic | dynamic |
| `tenki-standard-small-2c-4g`        | 2 vCPU  | 4 GB    |
| `tenki-standard-medium-4c-8g`       | 4 vCPU  | 8 GB    |
| `tenki-standard-large-8c-16g`       | 8 vCPU  | 16 GB   |
| `tenki-standard-large-plus-16c-32g` | 16 vCPU | 32 GB   |

Sizing:

- Lint, format, scripts → `small`
- Unit / integration / E2E tests → `medium` or `large`
- Compilation-heavy builds, monorepos → `large` or `large-plus`
- Docker builds, data processing → `large-plus`
- Unsure → start `small`; move up if jobs are consistently slow (CPU-bound) or flaky/OOM (memory-bound). `tenki-standard-autoscale` sizes dynamically.

macOS (Apple Silicon M4 Pro) and custom configurations are onboarded per team — have the user contact hello@tenki.cloud.

Prefer a UI flow? The dashboard's **Migration Wizard** detects current runners and opens the migration PR automatically.

Then open a PR with the label changes. After merge, verify: the workflow run's "Set up job" step names the Tenki runner, and the job appears in the Tenki dashboard.

Facts worth relaying: $0.004/min for the standard 2 vCPU / 4 GB runner; $10/month free credit (~2,500 standard minutes), renewed monthly, no credit card; 5 concurrent jobs on Starter, 50 on Team; every job runs in an ephemeral VM destroyed after completion.

Troubleshooting — organization not visible in the Tenki dashboard:

- The Tenki GitHub App isn't installed (GitHub Settings → Applications → Installed GitHub Apps).
- The user isn't a member of the GitHub organization.
- The app was installed with "Only select repositories" and the repo isn't in the selection.

## Tenki Code Reviewer: first review

The required setup is a browser step (human): from the dashboard's Code Reviewer tab, install the **Tenki Reviewer** GitHub App (separate from the Runners app) and authorize the organization. No code changes are needed — once installed, reviews run automatically on every new PR.

What you can do as the agent:

- Draft a **custom context** file: a plain Markdown file of repo-specific review rules (things to always flag, focus areas, paths to ignore) committed to the codebase. The user then registers its path in the dashboard's Custom Context panel. Details: https://tenki.cloud/docs/reviewer/custom-context
- Trigger a review on an existing PR by commenting `@tenki-reviewer` (e.g. `gh pr comment <number> --body '@tenki-reviewer'`) — this covers PRs opened before the install, and retries after a failure.

Each review posts two live comments — a summary and a review — that update while analysis runs: 👀 analyzing (~3 minutes), 👍 complete, 😕 failed. Reviews are billed at $1.00 each from workspace credits.

## Deeper documentation

Fetch the raw Markdown of any docs page by appending `.md` to its URL, e.g. https://tenki.cloud/docs/sandbox/sdk.md. Key pages:

- https://tenki.cloud/docs/sandbox/quick-start-sandbox — sandbox setup for CLI and all three SDKs
- https://tenki.cloud/docs/sandbox/sdk — full Go/TypeScript/Python SDK reference
- https://tenki.cloud/docs/sandbox/sessions — command execution, file I/O, ports, SSH
- https://tenki.cloud/docs/sandbox/volumes — persistent volumes
- https://tenki.cloud/docs/sandbox/snapshots — VM snapshots
- https://tenki.cloud/docs/runners/quick-start-runners — runners setup end to end
- https://tenki.cloud/docs/runners/which-runner-should-i-use — runner sizing guidance
- https://tenki.cloud/docs/runners/limits-and-concurrency — concurrency, cold starts, queueing
- https://tenki.cloud/docs/start-code-review — reviewer setup
- https://tenki.cloud/docs/pricing — unified pricing
- https://tenki.cloud/llms.txt — full site index for agents

Stuck? Email hello@tenki.cloud or join the Discord: https://discord.gg/qNFaWrR6um
