# ambiguous

CLI for [Ambiguous Workspace](https://ambiguous.io) — manage docs, tasks, mail, calendar, CRM, and more from the terminal. Built for humans and LLMs.

The CLI is a dynamic shell: it fetches the workspace's OpenAPI spec at startup and builds its command tree from the operations' `x-cli` vendor extensions. `--help` at any level reflects exactly what the live API supports.

## Install

```bash
npx ambiguous
```

Or install globally:

```bash
npm install -g ambiguous
```

## Authenticate

```bash
# Browser login (opens your default browser)
ambiguous auth login

# Direct token (for agents and CI)
ambiguous auth login --token ak_your_api_key

# Check who you're logged in as
ambiguous auth status
```

## Commands

| Command | Description |
|---------|-------------|
| `auth` | Login, logout, status, print token |
| `docs` | Create, read, update, delete, import, export documents |
| `sheets` | Spreadsheets — data, cells, tabs, columns, rows, import |
| `slides` | Presentations — slides, elements, layouts, settings, import |
| `chat` | Channels, messages, threads, reactions, members |
| `mail` | Inbox, send, star, snooze, send-as, signature |
| `tasks` | Create, assign, update, subtasks |
| `drive` | Upload, download, folders, storage |
| `calendar` | Calendars, events, RSVP, availability, .ics export |
| `crm` | Contacts, deals, pipelines, activities |
| `forms` | Form builder, publish, responses, submit |
| `wiki` | Spaces, pages, databases, search, backlinks |
| `admin` | Users, roles, settings, audit log, API keys, usage |
| `search` | Cross-module search |
| `notifications` | List and manage notifications |
| `webhooks` | Register and manage webhook endpoints |
| `assistant` | Chat with the built-in AI assistant |
| `api` | Raw API escape hatch for any endpoint |
| `config` | Manage CLI configuration |

## Usage

```bash
# Create a document
ambiguous docs create -f title="Weekly Report"

# List your tasks
ambiguous tasks list --status in_progress

# Send an email
ambiguous mail send -f to=ryan@ambi.cc -f subject="Update" -f body="Ship is ready."

# Send a chat message
ambiguous chat messages send CHANNEL_ID -f content="Deployed to staging"

# Create a CRM contact
ambiguous crm contacts create -f name="Jane Smith" -f email=jane@acme.com -f type=person

# Check calendar availability
ambiguous calendar availability --user-ids USER_ID --start 2026-04-01T09:00:00Z --end 2026-04-01T18:00:00Z

# Search across everything
ambiguous search "quarterly report"

# Raw API access
ambiguous api GET /api/users/me
ambiguous api POST /api/tasks --data '{"title": "Review PR", "priority": "high"}'
```

## LLM-friendly design

The CLI is designed to be used by AI agents as easily as by humans:

- **`--json`** on every command — outputs structured JSON (auto-enabled when stdout is piped)
- **`-q` / `--quiet`** — suppresses non-essential output
- **stdin JSON** — pipe JSON input for complex payloads
- **Consistent noun-verb pattern** — `ambiguous <module> <action> [id] [options]`
- **`ambiguous api`** — raw escape hatch for any API endpoint

```bash
# Pipe-friendly: JSON output when piped
ambiguous tasks list | jq '.[0].title'

# Agent workflow: create doc, get its ID
DOC_ID=$(ambiguous docs create -f title="Report" --json | jq -r '.id')
ambiguous docs get $DOC_ID
```

## Configuration

Config is stored in `~/.config/ambiguous/config.json`.

```bash
# Point to a different API server
ambiguous config set apiUrl https://your-instance.example.com

# View all config
ambiguous config list

# Print config file path
ambiguous config path
```

## Development & Publishing

### Building

```bash
cd apps/cli
npm run build          # outputs dist/index.js (~950 KB, all deps bundled)
npm run typecheck      # TypeScript check without emitting
```

The build bundles all runtime dependencies (`commander`, `chalk`, `ora`, `conf`,
`open`, `mime-types`) directly into `dist/index.js` so the binary is fully
self-contained. No `node_modules` needed at runtime.

**Note for worktree builds:** The workspace root has older hoisted versions of
some packages. Before building in a git worktree, install the correct CLI deps
locally:

```bash
# From a directory without the @ambiguous workspace context
cd /tmp && mkdir cli-deps && cd cli-deps
npm install commander@^13 chalk@^5 ora@^8 conf@^13 open@^10 mime-types@^3
cp -r node_modules /path/to/worktree/apps/cli/node_modules
```

### Testing locally before publishing

Run the smoke test against a **local dev server**, not production. Creating test
data on prod is messy to clean up (no workspace/user deletion endpoint exists).

**Step 1 — Start the local API and web app:**

```bash
# Terminal 1 — API server (http://localhost:3001)
cd apps/api && npm run dev

# Terminal 2 — Web app (http://localhost:3000) — only needed for browser login
cd apps/web && npm run dev
```

**Step 2 — Build and pack the CLI:**

```bash
cd apps/cli
npm run build
npm pack          # creates ambiguous-0.7.0.tgz
```

**Step 3 — Install the packed tarball in a temp location:**

```bash
cd /tmp
npm install /path/to/apps/cli/ambiguous-0.7.0.tgz
```

The pack contains exactly 3 files: `package.json`, `README.md`, `dist/index.js`.

**Step 4 — Point the CLI at localhost and smoke test:**

```bash
# Point at local
npx ambiguous config set apiUrl http://localhost:3001

# Register a test user via the API, then log in with the returned token
npx ambiguous auth login --token <token-from-registration>
npx ambiguous auth status                 # authenticated=true

# Core read commands
npx ambiguous api GET /api/users/me
npx ambiguous docs list
npx ambiguous tasks list
npx ambiguous chat channels list
npx ambiguous mail inbox

# Core write commands
npx ambiguous docs create -f title="CLI smoke test"
npx ambiguous tasks create -f title="CLI smoke task" -f priority=high
npx ambiguous crm contacts create -f name="Smoke Test" -f email=smoke@test.com -f type=person
```

**Step 5 — Reset after testing:**

```bash
npx ambiguous config set apiUrl https://app.ambi.cc
npx ambiguous auth logout
```

### Publishing

```bash
cd apps/cli
npm run release             # default: patch
npm run release minor       # 0.7.x → 0.8.0
npm run release -- --dry-run   # bump + restore, no publish
```

Wraps `scripts/release.sh`. Runs preflight (on develop, clean tree, in sync with `origin/develop`, `npm whoami` succeeds), then `npm version <bump> --no-git-tag-version` → `npm publish --access public` (the existing `prepublishOnly` hook runs `clean && build` so the bundled `dist/index.js` matches the new version) → auto-commits the bumped `apps/cli/package.json` and pushes to `develop`. The auto-commit is the point of the wrapper — it's the step that gets forgotten and lets the registry drift ahead of develop. `--no-git-tag-version` is intentional: the bump rides as a single chore commit; tag explicitly only when cutting a marked release.

The package is published under the `ambiguous` name on the public npm registry. No special registry config is needed — it's a plain npm package. Publish from `apps/cli/` specifically; running `npm publish` from the repo root tries to publish the whole monorepo.

## License

UNLICENSED
