# Command line

The app is a thin shell over a command-line tool, bundled inside it. Every
action the app takes is one of these commands, and every read screen is
one of them with `--json`.

## Running it

From a source checkout: `pnpm dev <command>`.

From the installed app:

```bash
alias inboxminder='"/Applications/InboxMinder.app/Contents/Resources/runtime/bin/node" "/Applications/InboxMinder.app/Contents/Resources/runtime/cli/dist/cli.js"'
```

Put that line in `~/.zshrc` to keep it. `inboxminder --help` lists every
command; `inboxminder <command> --help` the options.

Global option, placed before the command: `--profile <name>` runs against
an isolated [profile](profiles.md). `INBOXMINDER_PROFILE=<name>` does the
same for scripts and is how the agent's plist selects its profile.

Conventions:

- Secrets are never passed as arguments. `set-key` and `license activate`
  prompt, or read from stdin with `--stdin`.
- Every read command takes `--json`. A failure is one `{"error": …}`
  object with a non-zero exit.
- `classify` and `draft` are previews: they create nothing and label
  nothing.

## Setup and lifecycle

| Command | What it does |
|---|---|
| `init` | Interactive setup: provider, model, keys to the Keychain, knowledge sources, Gmail client, then an offer to go live. Keeps Keychain secrets if a config already exists |
| `init --answers-stdin [--force]` | Non-interactive: a JSON answers document on stdin writes `config.toml` (secrets excluded; store them with `set-key --stdin`). `--force` overwrites an existing file |
| `set-key <name> [--stdin]` | Store or rotate a secret: `anthropic`, `openai`, `google`, `openai-compatible`, `notion`, `linear`, `slack`, `gmail-client-id`, `gmail-client-secret`, `license`, or any MCP secret name. Restart the agent afterwards (`agent install`) so it picks up the new value |
| `auth` | Browser OAuth flow for Gmail. Safe to repeat; re-run it when the menu bar says Gmail needs re-authorization |
| `index [--source <name>] [--full]` | Pull sources and (re)build the local index. Incremental by default; `--source` limits to one connector (`files`, `llmstxt`, `github`, `notion`, `linear`, `slack`, `sent`, `notes`, `answers`); `--full` refetches everything but still skips re-embedding unchanged content |
| `up` | Go live: authorize Gmail if needed, build the index, install the agent. Idempotent |
| `watch` | Run the agent in the foreground (what the launchd agent runs) |
| `agent install` | Render the launchd plist and (re)start the agent. Also the way to restart it after a settings or key change |
| `agent uninstall` | Remove the launchd agent. Data and config stay |
| `agent status` | Installed, running, pid, last tick, paused; warns when stalled |
| `agent pause` / `agent resume` | Stop and restart watching without unloading the agent. Mail arriving while paused is handled on resume (unless paused beyond about a week, when Gmail expires the cursor) |
| `license activate [key] [--stdin]` | Bind this Mac to a license key and store it in the Keychain |
| `license status [--json]` | Licensed, grace days left, expiry; or why not |
| `license deactivate` | Free the seat for another Mac |
| `profiles` | List the default profile and every one under the data dir's `profiles/`, with agent state |

## Previews

| Command | What it does |
|---|---|
| `classify <messageId>` | The verdict for one message: reply-worthy, category, urgent. Labels nothing |
| `draft <messageId>` | Verdict plus the draft it would write, plus docs-gap and ticket verdicts when those features are on. Creates nothing |

The message id is the long hex string in a Gmail message URL after
`#inbox/`, or in Show original. `draft` is the tuning loop: change an
instruction, a note or a source, re-run, compare.

## Configuration surfaces

| Command | What it does |
|---|---|
| `config get-sources` | The connectors section as JSON |
| `config set-sources --stdin` | Replace the connectors section from a JSON document on stdin. Every other key in the file is preserved |
| `config get-settings` | The curated behavior settings (what Preferences shows) as JSON |
| `config set-settings --stdin` | Merge a settings document into `config.toml`. Restart the agent to apply |

Provider, model, embedding dimensions, `repoPath`, `teamId` and the `[mcp]`
section are hand edits in the file by design. See
[Configuration](configuration.md).

## Reading what it did

| Command | What it does |
|---|---|
| `drafts list [--limit N]` | Recent drafts, newest first (max 500) |
| `drafts show <id>` | One draft with the passages and sent emails it drew on |
| `knowledge docs [--source X]` | Indexed documents (sent mail is under `voice`) |
| `knowledge passages <docKey>` | Every passage of one document, in order |
| `knowledge search --stdin [--limit N]` | What a draft would retrieve for a question read from stdin (max 20) |
| `knowledge exclude <docKeys...>` | Stop using documents (or sent emails) in drafts; survives re-indexing |
| `knowledge include <docKeys...>` | Use excluded documents again (each returns on its next index pull) |
| `voice list` | Every indexed sent email, newest first, with skipped ones and their reasons |
| `voice audit [--limit N]` | Dry run: which recent sent emails look automated, and why. Writes nothing |
| `notes list` / `notes get <slug>` | Your notes |
| `notes save --stdin` | Save a note (markdown on stdin; the first heading is the title) and index it at once |
| `notes delete <slug>` | Delete a note and remove it from the index |
| `written list` | Docs pages, suggested answers and Linear tickets the app produced |
| `stats [--days N]` | Day-by-day counts: labeled, drafts, urgent, handled (max 366 days) |
| `linear status` / `linear teams` / `linear members` | Is a Linear key connected and as whom; the teams; workspace members for hand-off labels |
| `polish --stdin` | Polish text you wrote: in on stdin, out on stdout. `--json` wraps it |

## Examples

```bash
# preview a draft for one message, creating nothing
inboxminder draft 18c2f4a9e1b07d3c

# what would a draft find for this question?
echo "how long do refunds take?" | inboxminder knowledge search --stdin

# polish the clipboard in your tone
pbpaste | inboxminder polish --stdin | pbcopy

# the last hundred log lines, for support
tail -n 100 ~/.inboxminder/logs/watch.log | pbcopy

# a second mailbox, fully separate
inboxminder --profile support init
inboxminder --profile support up
```
