Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions apps/docs/app/[lang]/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,21 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
// Academy lessons are video-first: drop the "On this page" TOC and go full
// width so the lesson hero/video gets the room (chapters live in-page instead).
const isAcademy = slug?.[0] === 'academy'
const isCli = slug?.[0] === 'cli'

const pageTreeRecord = source.pageTree as Record<string, Root>
const pageTree = pageTreeRecord[lang] ?? pageTreeRecord.en ?? Object.values(pageTreeRecord)[0]
const rawNeighbours = pageTree ? findNeighbour(pageTree, page.url) : null
// Academy and API Reference are self-contained sections; keep prev/next inside
// the section instead of spilling into the main documentation tree. Match both
// the section's pages (`/<slug>/...`) and its index (`/<slug>`).
const sectionSlug = isApiReference ? 'api-reference' : isAcademy ? 'academy' : null
// Academy, API Reference, and CLI are self-contained sections; keep prev/next
// inside the section instead of spilling into the main documentation tree.
// Match both the section's pages (`/<slug>/...`) and its index (`/<slug>`).
const sectionSlug = isApiReference
? 'api-reference'
: isAcademy
? 'academy'
: isCli
? 'cli'
: null
const inSection = (url?: string) =>
url != null && (url.includes(`/${sectionSlug}/`) || url.endsWith(`/${sectionSlug}`))
const neighbours = sectionSlug
Expand Down
44 changes: 37 additions & 7 deletions apps/docs/components/navbar/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,53 @@ import { SimWordmark } from '@/components/ui/sim-logo'
import { ThemeToggle } from '@/components/ui/theme-toggle'
import { cn } from '@/lib/utils'

/**
* Sections that own a tab, in reading order: the main docs, then the two
* reference surfaces, then Academy. `Documentation` matches by exclusion, so
* every section listed here is one it must not claim.
*/
const SECTION_TABS = ['api-reference', 'academy', 'cli'] as const

/**
* Whether a pathname is inside a section, matched by whole path segment.
*
* A substring test is wrong: `/integrations/clickup` and
* `/integrations/clickhouse` both contain `/cli`, which lit the CLI tab and
* unlit Documentation on two existing integration pages. Anchoring to the start
* is also wrong, because a non-default locale prefixes the path (`/ja/cli`), so
* the segment can sit anywhere.
*/
function isInSection(pathname: string, section: string): boolean {
return (
pathname === `/${section}` ||
pathname.endsWith(`/${section}`) ||
pathname.includes(`/${section}/`)
)
}

const NAV_TABS = [
{
label: 'Documentation',
href: '/introduction',
match: (p: string) => !p.includes('/api-reference') && !p.includes('/academy'),
match: (p: string) => !SECTION_TABS.some((section) => isInSection(p, section)),
external: false,
},
{
label: 'Academy',
href: '/academy',
match: (p: string) => p.includes('/academy'),
label: 'API Reference',
href: '/api-reference/getting-started',
match: (p: string) => isInSection(p, 'api-reference'),
external: false,
},
{
label: 'API Reference',
href: '/api-reference/getting-started',
match: (p: string) => p.includes('/api-reference'),
label: 'CLI',
href: '/cli',
match: (p: string) => isInSection(p, 'cli'),
external: false,
},
{
label: 'Academy',
href: '/academy',
match: (p: string) => isInSection(p, 'academy'),
external: false,
},
] as const
Expand Down
34 changes: 34 additions & 0 deletions apps/docs/components/ui/command-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { ReactNode } from 'react'

interface CommandTableProps {
children: ReactNode
}

/**
* Column sizing for the generated CLI reference tables.
*
* Auto layout gives a column width in proportion to its content, which is
* backwards here: descriptions are sentences and flags are short, so the flag
* column collapsed until `--enabled-filter <value>` wrapped across three lines
* while the description beside it kept most of the row empty. A fixed layout
* with explicit widths reserves the space the flag actually needs.
*
* Cells align to the top because a wrapped four-line description would
* otherwise float its flag into the middle of the row, away from the line it
* belongs to.
*/
export function CommandTable({ children }: CommandTableProps) {
return (
<div
className={[
'[&_table]:w-full [&_table]:table-fixed',
'[&_th:nth-child(1)]:w-[30%] [&_th:nth-child(2)]:w-[5.5rem]',
'[&_td]:align-top [&_th]:align-bottom',
// Long flags and dotted paths have no spaces to break on.
'[&_td:nth-child(1)_code]:break-words',
].join(' ')}
>
{children}
</div>
)
}
62 changes: 62 additions & 0 deletions apps/docs/content/docs/en/cli/audit-logs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: Audit Logs
description: Manage audit logs — every subcommand, argument, and flag
---

import { CommandTable } from '@/components/ui/command-table'

`sim audit-logs` is also spelled `sim audit-log`.

Every command below also accepts the [global options](/cli/commands#global-options).

## Get audit log

```bash
sim audit-logs get <id> [options]
```

**Arguments**

<CommandTable>

| Argument | Required | Description |
| --- | --- | --- |
| `id` | Yes | Audit-log entry identifier. |

</CommandTable>

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--organization <value>` | Yes | Organization ID (personal API key required). |

</CommandTable>

## List audit logs

```bash
sim audit-logs list [options]
```

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--action <value>` | No | Filter by exact action name. |
| `--resource-type <value>` | No | Filter by resource type. Accepts a comma-separated set; members are trimmed and deduplicated, and member order affects neither the result nor the cursor. |
| `--resource-id <value>` | No | Filter by exact resource identifier. |
| `--start-date <value>` | No | Only include runs started at or after this UTC ISO 8601 timestamp, e.g. `2026-08-06T00:00:00Z`. A date without a time, or a timestamp carrying a UTC offset instead of `Z`, is rejected, as is year `0000`, which names no storable instant. |
| `--end-date <value>` | No | Only include runs started at or before this UTC ISO 8601 timestamp, e.g. `2026-08-06T00:00:00Z`. A date without a time, or a timestamp carrying a UTC offset instead of `Z`, is rejected, as is year `0000`, which names no storable instant. |
| `--include-departed` | No | Include actions by users who have left the organization. |
| `--no-include-departed` | No | Send --include-departed as false. |
| `--limit <n>` | No | Maximum items to return (0 for everything). Defaults to `100`. |
| `--organization <value>` | Yes | Organization ID (personal API key required). |
| `--actor-email <value>` | No | Filter by actor email address. |
| `--all-workspaces` | No | Do not filter to the configured workspace (personal API key required for account-wide access). |

</CommandTable>
167 changes: 167 additions & 0 deletions apps/docs/content/docs/en/cli/authentication.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
title: Authentication
description: Sign in from the terminal, authenticate CI with an API key, and keep several accounts side by side
---

import { Callout } from 'fumadocs-ui/components/callout'

The CLI authenticates with a Sim API key. On a workstation, `sim login` mints and
stores one for you. In CI, you supply one through the environment and nothing
touches the filesystem.

## Signing in

```bash
sim login
```

The terminal prints a pairing code and a URL:

```
Pairing code: K7M2-P9XT
Confirm this code matches what the browser shows before approving.

https://sim.ai/cli/auth?request=…&scope=platform
Waiting for approval…

✓ Logged in. Key stored in /Users/you/.sim/credentials
Personal key, defaulting to ws_abc123. Override per command with --workspace.
```

This is the same browser handoff shape as `gh auth login`. Nothing redeemable
crosses the browser leg, and there is no loopback listener — so it works over
SSH and inside containers.

<Callout type="warn">
Confirm the pairing code in your terminal matches the one the browser shows
before you approve. That check is what binds the approval to *your* terminal.
</Callout>

| Option | What it does |
| --- | --- |
| `--no-browser` | Print the URL instead of opening a browser |
| `--scope <scope>` | Key space to mint from: `platform` (default) or `copilot` |
| `-y, --yes` | Overwrite an existing profile without prompting |

### Picking a workspace

The approval page is where you choose the workspace — the terminal has no key
yet, so it cannot list them for you.

`sim login` issues a **personal** key. The workspace you pick becomes the
profile's default `workspace`; it does **not** restrict the key to that
workspace. Target another workspace the key can reach with `--workspace`:

```bash
sim workflows list --workspace ws_other
```

`sim login --workspace <id>` preselects a workspace in the picker, and
re-logging into an existing profile preselects the one already configured.

## Checking who you are

```bash
sim whoami
```

This prints the resolved endpoint, workspace, output format, and account — and
which source each value came from. Reach for it first whenever a command targets
something you did not expect.

## Signing out

```bash
sim logout # remove the stored key
sim logout --all # remove the profile entirely, including its settings
```

<Callout type="warn">
`sim logout` removes the key from disk but does **not** revoke it. Revoke keys in
Sim under **Settings → API keys**.
</Callout>

## Authenticating CI

Skip `sim login` entirely. Set the key and workspace in the environment and the
CLI never reads or writes a config file:

```bash
export SIM_API_KEY="sim_…"
export SIM_WORKSPACE="ws_abc123"

sim workflows run wf_7Yb2 --input '{"source":"nightly"}' --output json
```

Create the key in Sim under **Settings → API keys**. Store it as a secret in your
CI provider — never commit it.

<Callout type="info">
`SIM_CONFIG_DIR` relocates both files if you do need them somewhere other than
`~/.sim` — a container image, or a runner with no writable home directory.
</Callout>

### GitHub Actions

```yaml title=".github/workflows/nightly.yml"
jobs:
digest:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install --global sim
- run: sim workflows run wf_7Yb2 --output json
env:
SIM_API_KEY: ${{ secrets.SIM_API_KEY }}
SIM_WORKSPACE: ${{ vars.SIM_WORKSPACE }}
```

## Several accounts at once

Each profile holds one identity and one set of defaults, so a production account
and a local stack can coexist without re-authenticating:

```bash
sim login --profile dev --endpoint http://localhost:3000
sim login --profile prod

sim workflows list --profile dev
sim workflows list --profile prod
```

See [Configuration](/cli/configuration) for how profiles are stored and resolved.

## Self-hosted and non-production deployments

Point the CLI at any Sim deployment with `--endpoint`, then sign in against it:

```bash
sim login --profile local --endpoint http://localhost:3000
```

Save it so you do not have to repeat the flag:

```bash
sim configure --set-endpoint http://localhost:3000 --profile local
```

## Where the key is stored

Keys live in `~/.sim/credentials`, written with `0600` permissions, kept apart
from the non-secret `~/.sim/config` so the two can be handled differently — you
can commit `config` to a dotfiles repo, and never `credentials`.

```ini title="~/.sim/credentials"
[default]
api_key = sim_…

[dev]
api_key = sim_…
```

## Organization audit logs

`sim audit-logs` requires a **personal** API key — the kind `sim login` issues.
A workspace-scoped key cannot read organization-level audit logs.
45 changes: 45 additions & 0 deletions apps/docs/content/docs/en/cli/billing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: Billing
description: Manage billing — every subcommand, argument, and flag
---

import { CommandTable } from '@/components/ui/command-table'

Every command below also accepts the [global options](/cli/commands#global-options).

## Show billing status and current-period credit usage

```bash
sim billing status [options]
```

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--all-workspaces` | No | Do not filter to the configured workspace (personal API key required for account-wide access). |

</CommandTable>

## List credit usage events

```bash
sim billing logs [options]
```

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--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`. |
| `--period <value>` | No | Billing period. Accepted values: `1d`, `7d`, `30d`, `all`, `custom`. |
| `--start-date <value>` | No | Custom period start (ISO 8601). |
| `--end-date <value>` | No | Custom period end (ISO 8601). |
| `--limit <n>` | No | Maximum items to return (0 for everything). Defaults to `100`. |
| `--all-workspaces` | No | Do not filter to the configured workspace (personal API key required for account-wide access). |

</CommandTable>
Loading
Loading