# CLI

> Post, plan, score and work the inbox from a terminal, a script or a CI job.

```bash
npx @orbitwrite/cli post "Shipped it." --all --next
```

Or install it globally:

```bash
npm install -g @orbitwrite/cli
```

The binary is `orbitwrite`. It has no runtime dependencies, so `npx` is one download.

## Sign in

```bash
orbitwrite login
orbitwrite whoami
```

`login` opens Orbitwrite in your browser, asks which workspace to use if you're in several, and asks you to allow the
CLI. It can do what your role allows, and never manage members, billing or API keys. The sign-in lasts until
`orbitwrite logout`, or until you disconnect **Orbitwrite CLI** under **Settings → MCP → Connected apps**.

Somewhere without a browser (SSH, a container, CI), use an [API key](https://orbitwrite.com/docs/developers/authentication#api-keys) instead:

```bash
export ORBITWRITE_API_KEY=orbit_sk_...
orbitwrite whoami
```

A key always wins: `--api-key`, then `$ORBITWRITE_API_KEY`, then your sign-in. Sign-ins are kept in
`~/.config/orbitwrite/credentials.json` (`%APPDATA%\orbitwrite` on Windows), readable only by you.

## Commands

| Command                                          | Does                                                    |
| ------------------------------------------------ | ------------------------------------------------------- |
| `orbitwrite login` / `logout`                    | Sign in through your browser / forget the sign-in       |
| `orbitwrite whoami`                              | The workspace you're working in                         |
| `orbitwrite channels`                            | List connected channels                                 |
| `orbitwrite post <text>`                         | Create a post                                           |
| `orbitwrite posts`                               | List recent posts                                       |
| `orbitwrite plan <post-id>` / `unplan <post-id>` | Plan a saved post for a time, or move it back to drafts |
| `orbitwrite score <post-id>`                     | A post's score and checklist                            |
| `orbitwrite cover <post-id>`                     | Show or set a video post's cover                        |
| `orbitwrite slots`                               | The weekly posting times                                |
| `orbitwrite alt-text <media>`                    | Suggest alt text for an uploaded image                  |
| `orbitwrite inbox`                               | Work the inbox of replies and mentions                  |
| `orbitwrite hashtags`                            | Saved hashtag sets, and each platform's rules           |
| `orbitwrite autodm`                              | DM the people who repost or reply to a post             |

## Posting

```bash
orbitwrite post "Shipped it." --channel acc_1 --now                     # right now
orbitwrite post "Morning all" -c acc_1 -c acc_2 --at "tomorrow 9am"    # at a time
orbitwrite post "Shipped it." -c acc_1 --next                          # next free slot
orbitwrite post "Shipped it." --all --now                              # every channel that can publish
orbitwrite post "half an idea" -c acc_1 --draft                        # save for later
orbitwrite post "launch thread, tbd" -c acc_1 --next --plan            # hold a slot
orbitwrite post "Our launch video" -c acc_tt --draft --ai-generated    # label as AI-generated
```

You have to say *when*: exactly one of `--now`, `--at`, `--next` or `--draft`. There's no default, and two together
is refused rather than resolved.

### Times in plain English

`--at` takes `1pm`, `9:30am`, `noon`, `tomorrow 9am`, `wednesday`, `next friday 2pm`, `in 2 hours`,
`2026-10-01 14:00`, or an ISO 8601 instant.

- Wall-clock times are read in the **workspace's** timezone, and the CLI prints the time it settled on.
- A time that's already passed rolls forward to its next occurrence.
- Anything ambiguous is refused: `--at 9` could be 9am or 9pm.
- A day with no time (`--at wednesday`) books that day's posting slot.

With several channels, `--next` books the earliest slot free on all of them.

## Scoring

```bash
orbitwrite score grp_123
orbitwrite score --text "3 things we learned shipping our API" -c acc_x -c acc_li
```

The same [checklist](https://orbitwrite.com/docs/guides/composer/post-score) the composer shows, per channel.

## The inbox

```bash
orbitwrite inbox                                  # open conversations, newest first
orbitwrite inbox --unassigned --type mention      # a narrower view
orbitwrite inbox show c_123                       # the whole thread
orbitwrite inbox reply c_123 "Thanks, fixed now!"
orbitwrite inbox resolve c_123
orbitwrite inbox snooze c_123 --until "tomorrow 9am"
orbitwrite inbox assign c_123 user_789
orbitwrite inbox sync                             # pull new replies now
orbitwrite inbox held                             # replies waiting for approval
orbitwrite inbox approve h_123 --text "Reworded"
```

## Hashtags and Auto-DM

```bash
orbitwrite hashtags create "Launch" buildinpublic saas
orbitwrite post "$(orbitwrite hashtags apply hs_123 "Shipping today" --channel acc_ig)" --channel acc_ig --now

orbitwrite autodm channels
orbitwrite autodm start grp_123 "Thanks {first_name}! Here's the guide: https://…" --trigger reply --keyword guide --days 7
orbitwrite autodm pause adm_123
```

## Scripting

- `--json` prints the raw API response for any command, so the CLI composes with `jq`.
- Exit codes: `0` worked, `1` the API refused or couldn't be reached, `2` something about the command was wrong.

```bash
orbitwrite channels --json | jq -r '.[].id'
```

The CLI is the [SDK](https://orbitwrite.com/docs/developers/sdk) with argument parsing in front; anything it doesn't cover, the SDK does.
