Common Room CLI

Last updated Jun 15th, 2026

Overview

The Common Room CLI (cr) is a headless, scriptable interface to your Common Room workspace. It provides direct access to your buyer intelligence — contacts, organizations, activities, segments, and signals — from a terminal or inside any custom AI agent.

The CLI exposes the same identity-resolved, continuously enriched data that powers the Common Room platform, with JSON-first output, typed filters, and a machine-readable command map for agents (cr agent-context). Every mutation supports --dry-run so you can preview a payload before sending it.

The CLI is published on npm as @commonroomio/cli.

Prerequisites

Before installing the CLI, you'll need:

  • A Common Room workspace and an account with access to it
  • Node.js >=22.0.0 if installing from npm

Installation

npm

npm install -g @commonroomio/cli

This installs the cr binary globally. Verify the install with:

cr --version

Homebrew

brew install common-room/tap/cr

This installs the cr binary globally. Verify the install with:

cr --version

Authentication

The CLI supports three authentication modes.

ModeWhen to useHow
Browser OAuth (PKCE)
Interactive terminal sessions
cr auth login — opens a browser
Device flow
Headless or SSH environments
cr auth login --device — prints a verification URL and code, polls for the grant
Static token
Deployed agents and scripts
export COMMONROOM_API_TOKEN=… — skips cr auth login entirely

Common commands:

cr auth login# Sign in via browser
cr auth login --device
# Sign in via device flow
cr auth status
# Check current auth state
cr auth logout
# Clear stored credentials
cr config set communityId
# Switch active workspace
cr config get
# Show current config (credentials are not emitted)

Using the CLI

Once authenticated, you interact with Common Room through structured commands. The following examples show common workflows.

Building agents on the CLI

The cli-sample repo is a working reference implementation of cr as the tool layer in an LLM agent. cr-agent is built on the Vercel AI SDK and uses cr to produce meeting briefs and prospecting shortlists, with Claude or GPT as the model.

Get started:

git clone https://github.com/common-room/cli-sample.git
cd cli-sample
npm install
npm install -g @commonroomio/cli
npm run compile

Exploring the catalog

Start by discovering what object types are available in your workspace.

Example commands:

cr catalog list# List all object types
cr catalog describe Contact
# Inspect fields available on Contact
cr catalog describe Organization
# Inspect fields available on Organization

What you'll get: A list of every queryable object type (Contact, Organization, Activity, Segment, Tag, Provider, LeadScore, and more), and for each type, the full set of fields, filters, and sort keys you can use. This is also the primary discovery surface for object types like CustomField, LeadScore, and Provider whose IDs you'll need when building filters.

Listing and fetching records

Query any object type with typed filters, sorting, and pagination.

Example commands:

cr object list Contact --limit 5
cr object list Organization --filter-file org_filter.json
cr object get c_8812 # Type inferred from ID prefix
cr object get o_44217 --type Organization

What you'll get: Records returned in a paginated envelope (see Output below). IDs follow consistent prefixes — c_ for contacts, o_ for organizations, s_ for segments — and most get commands infer the type from the prefix.

The CLI also includes convenience subcommands for the most common resources:

cr contact list --email jane@acme.com
cr contact list --full-name "Tracy"
cr contact get c_8812
cr organization list --domain acme.com
cr organization list --name "Acme"
cr organization get o_44217

Creating and updating records

Write data back to Common Room with full CRUD support. Contact and organization creation use upsert semantics — if a matching record already exists (matched by email, LinkedIn URL, or domain), the existing record is updated rather than duplicated.

Example commands:

# Create a contact with inline flags
cr contact create --email jane@acme.com --full-name "Jane Doe" --title "VP Engineering"

# Create a contact from a JSON payload
cr contact create --file payload.json

# Convert a Prospector contact into a workspace contact
cr contact create --prospector-contact-id pc_98abc

# Update an existing contact
cr contact update --contact-id c_8812 --title "Senior Director of Engineering"

# Create an organization by domain
cr organization create --domain acme.com

# Log an activity on a contact
cr activity create --contact-id c_8812 --activity-type "demo" --activity-body "Completed product demo, interested in enterprise plan"

# Add a note to a contact
cr note create --contact-id c_8812 --note "Follow up next week about pricing"

# Create a static segment
cr segment create --name "Enterprise Prospects Q3" --entity-type organization

cr contact create --email jane@acme.com --full-name "Jane Doe" --dry-run

Custom fields

Set custom field values on creates or updates using the cf_<id>=<value> syntax. Custom field IDs come from the CustomField object type (cr object list CustomField). Values are parsed as booleans (true/false), numbers (if numeric), or strings.

cr contact update --contact-id c_8812 --custom-field cf_123456="Platinum"
cr organization update --organization-id o_44217 --custom-field cf_8283655=4.5

For larger payloads, pass a JSON file with an array of { customFieldId, customFieldValue }:

cr contact update --contact-id c_8812 --custom-fields-file fields.json

Discovering the full command surface

The CLI ships with a machine-readable description of every command, flag, and supported object type. This is the recommended way to introspect the surface programmatically — and the recommended way to make the CLI available to a custom AI agent.

cr agent-context --json

What you'll get: A JSON document describing every command, every flag, every object type, every filter, and the example prompts each one is designed for. Inject this into an agent's system prompt to give it instant awareness of the entire CLI without parsing --help output.

Output

The CLI emits JSON when stdout isn't a TTY (or when --json is passed) and a shell-friendly text format otherwise. List commands wrap records in an envelope so pagination survives pipes:

{
"records": [/* ... */],
"nextCursor": "abc123",
"truncated": true,
"hint": "Pass --cursor=abc123 to fetch the next page, or narrow with --filter / --limit."
}

In text mode the cursor is printed to stderr as [next page: --cursor=…] so stdout stays clean for piping into downstream tools.

To page through a complete result set, feed the nextCursor from each response into the next call. A shell loop with jq handles this cleanly:

cursor=""
while :; do
page=$(cr object list Contact --limit 100 ${cursor:+--cursor "$cursor"} --json)
echo "$page" | jq -c '.records[]'
cursor=$(echo "$page" | jq -r '.nextCursor // empty')
[ -z "$cursor" ] && break
done

The loop exits when the response no longer contains a nextCursor, signaling no more pages.

Common flags that shape output:

FlagDescription
--json
Force JSON output even when stdout is a TTY
--limit
Maximum records to return
--cursor
Pagination cursor from a prior response
--field
Property/column to include in the response (repeatable)
--sort
Field to sort by
--sort-direction
Sort direction — ascending or descending

Filtering

--filter accepts inline JSON; --filter-file reads from a file (use - for stdin):

{
"type": "and",
"clauses": [
{ "type": "stringFilter", "field": "fullName", "params": { "op": "like", "value": "Tracy" } }
]
}

For the common cases, the contact and organization subcommands build simple filters for you so you don't have to write JSON by hand:

cr contact list --email jane@acme.com
cr contact list --full-name "Tracy"
cr organization list --domain acme.com
cr organization list --name "Acme"

Reach for --filter / --filter-file when you need cross-object filtering, multi-clause logic, or operators beyond the convenience flags.

Tips for Best Results

Use --dry-run for any new automation. Every create and update accepts --dry-run. Use it to inspect the payload before running scripts that touch many records.

Prefer --filter-file over inline JSON for complex filters. File-based filters version control cleanly and are easier to review. - reads from stdin so you can pipe a generated filter into a command.

Pipe JSON into jq rather than parsing text output. The text format is for humans; the JSON envelope is the stable contract. Pass --json or redirect stdout away from a TTY to get structured output every time.

Use cr agent-context --json to ground AI agents. Rather than describing the CLI to your agent in prose, inject the agent-context output into its system prompt. Every command, flag, and supported object type comes from a single authoritative source.

Use static tokens in CI/CD, OAuth interactively. Static tokens via COMMONROOM_API_TOKEN skip the browser entirely — ideal for scheduled jobs. Browser OAuth and device flow are for humans on a terminal.

Capture --debug output when reporting issues. Adding --debug to any command emits a detailed log to stderr. Share this with support along with cr --version when filing a ticket.

Frequently Asked Questions

How does authentication work?

The CLI supports three modes. Browser OAuth (PKCE) is the default for interactive terminals — cr auth login opens a browser, you sign in to Common Room, and the CLI receives the grant on localhost:9876. Device flow (cr auth login --device) is for headless or SSH environments — the CLI prints a verification URL and code, you enter the code in a browser, and the CLI polls for the grant. Static tokens (COMMONROOM_API_TOKEN) are for CI/CD and scripts — set the environment variable and the CLI skips cr auth login entirely. Tokens are stored at ~/.commonroom/config.json with 0600 permissions and refreshed automatically before expiry.

Can I use the CLI in CI/CD without a browser?

Yes. Set COMMONROOM_API_TOKEN as an environment variable (for example, via your CI provider's secret store) and the CLI will use it directly, skipping interactive sign-in. This is the recommended approach for scheduled jobs, GitHub Actions, and any other non-interactive environment.

How do I switch between Common Room workspaces?

Use cr config set communityId <id> to change the active workspace. Use cr config get to see the current configuration without exposing credentials.

The command output is JSON when I expected text. Why?

The CLI emits JSON when stdout isn't a TTY — for example, when you pipe output into another command or redirect it to a file. This makes the CLI predictable in scripts and pipelines. If you want JSON in a terminal too, pass --json. If you want text output explicitly, run the command without piping or redirecting.

How do I paginate through large result sets?

List commands return a nextCursor field when results are truncated. Pass it back via --cursor:

cr object list Contact --limit 100 --json
# Response includes "nextCursor": "abc123"
cr object list Contact --limit 100 --cursor abc123 --json

In text mode the cursor is printed to stderr as [next page: --cursor=…] so stdout stays clean for piping.

Can I preview a write before sending it?

Yes. Every create and update command accepts --dry-run. The CLI validates the inputs and prints the payload that would be sent, without making the API call. Use this to verify scripts before running them against your workspace.

How do I find a custom field ID?

Query the CustomField object type:

cr object list CustomField

The response includes the field ID (cf_<id>), data type, target sub-types (e.g., salesforceContact), and the provider that owns the field.

Where can I find every command and flag?

Two options. For human-readable help, append --help to any command — for example, cr contact create --help. For a machine-readable description of the entire CLI surface, run:

cr agent-context --json

This emits a single JSON document covering every command, flag, and supported object type. It's the recommended source of truth for scripting and for grounding AI agents.

What permissions do CLI writes have?

The CLI respects the same per-user permissions as the Common Room UI and the MCP server. You can only create or update data your account has access to. There is no elevated service account or shared token — even when authenticating via COMMONROOM_API_TOKEN, the token is scoped to a specific user.

The CLI says my token has expired or is invalid. How do I fix it?

Run cr auth logout followed by cr auth login to get a fresh token. If you're using COMMONROOM_API_TOKEN, generate a new token in Common Room and update the environment variable. OAuth tokens are refreshed automatically before expiry, but a password change or revoked session will invalidate the refresh token and require a new sign-in.

Can the CLI and the MCP server be used together?

Yes — they're complementary surfaces on the same intelligence layer. The CLI is for deterministic, scripted execution (automation pipelines, scheduled jobs, batch operations, custom AI agent backends). The MCP server is for conversational execution inside AI assistants like Claude, ChatGPT, Copilot, and Cursor. Most teams use both: the CLI for production automation, the MCP server for humans using AI assistants every day.

Support

Email support@commonroom.io with the output of cr --version and the relevant --debug log when reporting issues.

Chatbot @ now

How else can I help with Common Room CLI?