Skip to content

Commit 8adc72f

Browse files
committed
docs(cli): add a CLI section, generated from the command tree
The `sim` CLI shipped with no coverage in the docs site. Adds a fourth top-level tab for it, and moves Academy last. The command reference is generated. `sim` exposes 147 leaf commands across 33 groups, most of them derived at runtime from the v2 route contracts, so a hand-written reference would be wrong the week after it was written. The generator walks the command tree `buildProgram()` hands to commander — the same tree the terminal parses — rather than re-deriving it from the contract, which would be a second implementation free to describe commands nobody can invoke. `check:cli-docs` is a zero-arg `check:*` script, so the existing audit runner picks it up and stale pages fail CI. Generating against the real tree surfaced a collision it had been hiding: `bulkUpdateKnowledgeDocuments` and `updateKnowledgeDocument` both derived to `sim knowledge documents update`. Commander resolves a duplicate to the first match, so the bulk form shadowed the single-document one and its flags were unreachable while still appearing in `--help`. The bulk form is now `batch-update`, matching how `tables rows batch-delete`/`batch-update` already handle the same REST overload, and the generator fails on any duplicate path so the next one cannot land silently. Five hand-written guides cover install, auth, configuration, output formats, and scripting. Also corrects two commands in the package README that do not exist as documented (`tables columns <tableId>`, and `--sort score:desc`, which is JSON).
1 parent 76318e4 commit 8adc72f

29 files changed

Lines changed: 4240 additions & 85 deletions

apps/docs/app/[lang]/[[...slug]]/page.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,21 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
113113
// Academy lessons are video-first: drop the "On this page" TOC and go full
114114
// width so the lesson hero/video gets the room (chapters live in-page instead).
115115
const isAcademy = slug?.[0] === 'academy'
116+
const isCli = slug?.[0] === 'cli'
116117

117118
const pageTreeRecord = source.pageTree as Record<string, Root>
118119
const pageTree = pageTreeRecord[lang] ?? pageTreeRecord.en ?? Object.values(pageTreeRecord)[0]
119120
const rawNeighbours = pageTree ? findNeighbour(pageTree, page.url) : null
120-
// Academy and API Reference are self-contained sections; keep prev/next inside
121-
// the section instead of spilling into the main documentation tree. Match both
122-
// the section's pages (`/<slug>/...`) and its index (`/<slug>`).
123-
const sectionSlug = isApiReference ? 'api-reference' : isAcademy ? 'academy' : null
121+
// Academy, API Reference, and CLI are self-contained sections; keep prev/next
122+
// inside the section instead of spilling into the main documentation tree.
123+
// Match both the section's pages (`/<slug>/...`) and its index (`/<slug>`).
124+
const sectionSlug = isApiReference
125+
? 'api-reference'
126+
: isAcademy
127+
? 'academy'
128+
: isCli
129+
? 'cli'
130+
: null
124131
const inSection = (url?: string) =>
125132
url != null && (url.includes(`/${sectionSlug}/`) || url.endsWith(`/${sectionSlug}`))
126133
const neighbours = sectionSlug

apps/docs/components/navbar/navbar.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ import { SimWordmark } from '@/components/ui/sim-logo'
88
import { ThemeToggle } from '@/components/ui/theme-toggle'
99
import { cn } from '@/lib/utils'
1010

11+
/**
12+
* Tab order is the reading order we want: the main docs, then the two reference
13+
* surfaces, then Academy. `Documentation` matches by exclusion, so every section
14+
* that owns a tab has to be listed in its matcher or two tabs light up at once.
15+
*/
16+
const SECTION_TABS = ['/api-reference', '/academy', '/cli'] as const
17+
1118
const NAV_TABS = [
1219
{
1320
label: 'Documentation',
1421
href: '/introduction',
15-
match: (p: string) => !p.includes('/api-reference') && !p.includes('/academy'),
16-
external: false,
17-
},
18-
{
19-
label: 'Academy',
20-
href: '/academy',
21-
match: (p: string) => p.includes('/academy'),
22+
match: (p: string) => !SECTION_TABS.some((section) => p.includes(section)),
2223
external: false,
2324
},
2425
{
@@ -27,6 +28,18 @@ const NAV_TABS = [
2728
match: (p: string) => p.includes('/api-reference'),
2829
external: false,
2930
},
31+
{
32+
label: 'CLI',
33+
href: '/cli',
34+
match: (p: string) => p.includes('/cli'),
35+
external: false,
36+
},
37+
{
38+
label: 'Academy',
39+
href: '/academy',
40+
match: (p: string) => p.includes('/academy'),
41+
external: false,
42+
},
3043
] as const
3144

3245
export function Navbar() {
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
---
2+
title: Authentication
3+
description: Sign in from the terminal, authenticate CI with an API key, and keep several accounts side by side
4+
---
5+
6+
import { Callout } from 'fumadocs-ui/components/callout'
7+
8+
The CLI authenticates with a Sim API key. On a workstation, `sim login` mints and
9+
stores one for you. In CI, you supply one through the environment and nothing
10+
touches the filesystem.
11+
12+
## Signing in
13+
14+
```bash
15+
sim login
16+
```
17+
18+
The terminal prints a pairing code and a URL:
19+
20+
```
21+
Pairing code: K7M2-P9XT
22+
Confirm this code matches what the browser shows before approving.
23+
24+
https://sim.ai/cli/auth?request=…&scope=platform
25+
Waiting for approval…
26+
27+
✓ Logged in. Key stored in /Users/you/.sim/credentials
28+
Personal key, defaulting to ws_abc123. Override per command with --workspace.
29+
```
30+
31+
This is the same browser handoff shape as `gh auth login`. Nothing redeemable
32+
crosses the browser leg, and there is no loopback listener — so it works over
33+
SSH and inside containers.
34+
35+
<Callout type="warn">
36+
Confirm the pairing code in your terminal matches the one the browser shows
37+
before you approve. That check is what binds the approval to *your* terminal.
38+
</Callout>
39+
40+
| Option | What it does |
41+
| --- | --- |
42+
| `--no-browser` | Print the URL instead of opening a browser |
43+
| `--scope <scope>` | Key space to mint from: `platform` (default) or `copilot` |
44+
| `-y, --yes` | Overwrite an existing profile without prompting |
45+
46+
### Picking a workspace
47+
48+
The approval page is where you choose the workspace — the terminal has no key
49+
yet, so it cannot list them for you.
50+
51+
`sim login` issues a **personal** key. The workspace you pick becomes the
52+
profile's default `workspace`; it does **not** restrict the key to that
53+
workspace. Target another workspace the key can reach with `--workspace`:
54+
55+
```bash
56+
sim workflows list --workspace ws_other
57+
```
58+
59+
`sim login --workspace <id>` preselects a workspace in the picker, and
60+
re-logging into an existing profile preselects the one already configured.
61+
62+
## Checking who you are
63+
64+
```bash
65+
sim whoami
66+
```
67+
68+
This prints the resolved endpoint, workspace, output format, and account — and
69+
which source each value came from. Reach for it first whenever a command targets
70+
something you did not expect.
71+
72+
## Signing out
73+
74+
```bash
75+
sim logout # remove the stored key
76+
sim logout --all # remove the profile entirely, including its settings
77+
```
78+
79+
<Callout type="warn">
80+
`sim logout` removes the key from disk but does **not** revoke it. Revoke keys in
81+
Sim under **Settings → API keys**.
82+
</Callout>
83+
84+
## Authenticating CI
85+
86+
Skip `sim login` entirely. Set the key and workspace in the environment and the
87+
CLI never reads or writes a config file:
88+
89+
```bash
90+
export SIM_API_KEY="sim_…"
91+
export SIM_WORKSPACE="ws_abc123"
92+
93+
sim workflows run wf_7Yb2 --input '{"source":"nightly"}' --output json
94+
```
95+
96+
Create the key in Sim under **Settings → API keys**. Store it as a secret in your
97+
CI provider — never commit it.
98+
99+
<Callout type="info">
100+
`SIM_CONFIG_DIR` relocates both files if you do need them somewhere other than
101+
`~/.sim` — a container image, or a runner with no writable home directory.
102+
</Callout>
103+
104+
### GitHub Actions
105+
106+
```yaml title=".github/workflows/nightly.yml"
107+
jobs:
108+
digest:
109+
runs-on: ubuntu-latest
110+
steps:
111+
- uses: actions/setup-node@v4
112+
with:
113+
node-version: '20'
114+
- run: npm install --global sim
115+
- run: sim workflows run wf_7Yb2 --output json
116+
env:
117+
SIM_API_KEY: ${{ secrets.SIM_API_KEY }}
118+
SIM_WORKSPACE: ${{ vars.SIM_WORKSPACE }}
119+
```
120+
121+
## Several accounts at once
122+
123+
Each profile holds one identity and one set of defaults, so a production account
124+
and a local stack can coexist without re-authenticating:
125+
126+
```bash
127+
sim login --profile dev --endpoint http://localhost:3000
128+
sim login --profile prod
129+
130+
sim workflows list --profile dev
131+
sim workflows list --profile prod
132+
```
133+
134+
See [Configuration](/cli/configuration) for how profiles are stored and resolved.
135+
136+
## Self-hosted and non-production deployments
137+
138+
Point the CLI at any Sim deployment with `--endpoint`, then sign in against it:
139+
140+
```bash
141+
sim login --profile local --endpoint http://localhost:3000
142+
```
143+
144+
Save it so you do not have to repeat the flag:
145+
146+
```bash
147+
sim configure --set-endpoint http://localhost:3000 --profile local
148+
```
149+
150+
## Where the key is stored
151+
152+
Keys live in `~/.sim/credentials`, written with `0600` permissions, kept apart
153+
from the non-secret `~/.sim/config` so the two can be handled differently — you
154+
can commit `config` to a dotfiles repo, and never `credentials`.
155+
156+
```ini title="~/.sim/credentials"
157+
[default]
158+
api_key = sim_…
159+
160+
[dev]
161+
api_key = sim_…
162+
```
163+
164+
## Organization audit logs
165+
166+
`sim audit-logs` requires a **personal** API key — the kind `sim login` issues.
167+
A workspace-scoped key cannot read organization-level audit logs.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
title: Audit Logs
3+
description: Manage audit logs — every subcommand, argument, and flag
4+
---
5+
6+
`sim audit-logs` is also spelled `sim audit-log`.
7+
8+
Every command below also accepts the [global options](/cli/commands#global-options).
9+
10+
## sim audit-logs get
11+
12+
Get Audit Log
13+
14+
```bash
15+
sim audit-logs get <id> [options]
16+
```
17+
18+
**Arguments**
19+
20+
| Argument | Required |
21+
| --- | --- |
22+
| `id` | Yes |
23+
24+
**Options**
25+
26+
| Option | Required | Description |
27+
| --- | --- | --- |
28+
| `--organization <value>` | Yes | Organization ID (personal API key required). |
29+
30+
## sim audit-logs list
31+
32+
List Audit Logs
33+
34+
```bash
35+
sim audit-logs list [options]
36+
```
37+
38+
**Options**
39+
40+
| Option | Required | Description |
41+
| --- | --- | --- |
42+
| `--action <value>` | No | Set action. |
43+
| `--resource-type <value>` | No | Set resource type. |
44+
| `--resource-id <value>` | No | Set resource id. |
45+
| `--start-date <value>` | No | Set start date. |
46+
| `--end-date <value>` | No | Set end date. |
47+
| `--include-departed` | No | Set includeDeparted. |
48+
| `--no-include-departed` | No | Set includeDeparted to false. |
49+
| `--limit <n>` | No | Maximum items to return (0 for everything). Defaults to `100`. |
50+
| `--organization <value>` | Yes | Organization ID (personal API key required). |
51+
| `--actor-email <value>` | No | Set actor email. |
52+
| `--all-workspaces` | No | Do not filter to the configured workspace (personal API key required for account-wide access). |
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
title: Billing
3+
description: Manage billing — every subcommand, argument, and flag
4+
---
5+
6+
Every command below also accepts the [global options](/cli/commands#global-options).
7+
8+
## sim billing status
9+
10+
Show billing status and current-period credit usage
11+
12+
```bash
13+
sim billing status [options]
14+
```
15+
16+
**Options**
17+
18+
| Option | Required | Description |
19+
| --- | --- | --- |
20+
| `--all-workspaces` | No | Do not filter to the configured workspace (personal API key required for account-wide access). |
21+
22+
## sim billing logs
23+
24+
List credit usage events
25+
26+
```bash
27+
sim billing logs [options]
28+
```
29+
30+
**Options**
31+
32+
| Option | Required | Description |
33+
| --- | --- | --- |
34+
| `--source <value>` | No | Filter by usage source; sim-chat combines Copilot and workspace chat. Accepted values: `workflow`, `wand`, `sim-chat`, `mcp_copilot`, `mothership_block`, `knowledge-base`, `voice-input`, `enrichment`, `voice-output`. |
35+
| `--period <value>` | No | Billing period. Accepted values: `1d`, `7d`, `30d`, `all`, `custom`. |
36+
| `--start-date <value>` | No | Custom period start (ISO 8601). |
37+
| `--end-date <value>` | No | Custom period end (ISO 8601). |
38+
| `--limit <n>` | No | Maximum items to return (0 for everything). Defaults to `100`. |
39+
| `--all-workspaces` | No | Do not filter to the configured workspace (personal API key required for account-wide access). |

0 commit comments

Comments
 (0)