CLI¶
The SDK ships an optional xaffinity CLI that dogfoods the SDK. Install it as an extra so library-only users don't pay the dependency cost.
Key Features¶
- Query Language: Complex queries with filtering, aggregations, and includes (Query Guide)
- CSV Export: Export people, companies, opportunities, and list entries to CSV with
--csvflag (CSV Export Guide) - Filtering: Server-side filtering on custom fields with
--filter(Filtering Guide) - JSON Output: All commands support
--jsonfor programmatic use (Scripting Guide) - Datetime Handling: Local time input, UTC output for JSON (Datetime Guide)
- Pagination: Fetch all pages with
--all, control page size with--page-size(items per API call), or limit total results with--max-results - Name Resolution: Use names instead of IDs for lists, fields, and entities
- Session Caching: Share metadata across pipeline commands with
session start/end(Pipeline Optimization)
See Commands Reference for complete command documentation.
AI Integration¶
MCP Server¶
Connect desktop AI tools (Claude Desktop, Cursor, Windsurf, VS Code + Copilot) to Affinity.
Important: The CLI is a prerequisite for the MCP server. Install and configure the CLI first (see Install and Authentication below), then follow the MCP Server setup guide.
Claude Code¶
Using Claude Code? Install the CLI plugin for AI-assisted usage:
/plugin marketplace add yaniv-golan/affinity-sdk
/plugin install cli@xaffinity
This teaches Claude CLI patterns and provides hooks for API key protection and Cowork bootstrap. See Claude Code plugins for all available plugins.
Install¶
Recommended for end-users:
pipx install "affinity-sdk[cli]"
Or in a virtualenv:
pip install "affinity-sdk[cli]"
Verify Installation¶
Step 1: Check the CLI is installed:
xaffinity --version
Expected: Version number (e.g., 0.15.0)
Step 2: Verify API connectivity with your API key:
AFFINITY_API_KEY="your-key-here" xaffinity whoami
Expected: Your user information and tenant details
If whoami hangs, check network connectivity (firewall, proxy, VPN). If it returns an authentication error, verify your API key is correct (Settings → API Keys in Affinity).
Once verified, see Authentication for persistent API key configuration options.
Authentication¶
The CLI never makes "background" requests. It only calls the API for commands that require it.
Quick Setup¶
Check if a key is already configured:
xaffinity config check-key
Set up a new key securely (hidden input, not echoed):
xaffinity config setup-key
See config check-key and config setup-key for details.
API Key Sources¶
The CLI checks these sources in order (highest precedence first):
--api-key-stdinflag (reads from stdin)--api-key-file PATH(reads from file, or-for stdin)AFFINITY_API_KEYenvironment variable.envfile in current directory (requires--dotenvflag, or use--env-file <path>which implicitly enables dotenv)api_keyin user config file (~/.config/xaffinity/config.toml)
Reading from File or Stdin¶
For scripts or CI/CD pipelines, you can pass the API key via file or stdin:
# Read from a secrets file
xaffinity --api-key-file /run/secrets/affinity-key whoami
# Read from stdin (useful for piping from secret managers)
vault kv get -field=api_key secret/affinity | xaffinity --api-key-stdin whoami
# Equivalent: --api-key-file - reads from stdin
echo "$SECRET_KEY" | xaffinity --api-key-file - whoami
Using .env Files¶
For project-specific keys, use --dotenv to load from .env:
xaffinity --dotenv whoami
xaffinity --dotenv --env-file ./dev.env whoami
The config setup-key --scope project command creates a .env file and adds it to .gitignore automatically.
Output contract¶
--jsonis supported on every command.- In
--jsonmode, JSON is written to stdout. Progress/logging go to stderr. - Human/table output goes to stdout; diagnostics go to stderr.
- Commands build a single structured result and then render it as either JSON or table output (no “double implementations”).
- In
--jsonmode,datais an object keyed by section name (even for single-section commands), and pagination tokens/URLs live inmeta.pagination.<section>. - If
--max-resultstruncates results mid-page, the CLI may omitmeta.pagination.<section>to avoid producing an unsafe resume token.
Performance¶
The CLI enables SDK in-memory caching for cacheable metadata requests (e.g., field metadata) automatically.
For pipelines running multiple commands, use session caching to share metadata across invocations:
export AFFINITY_SESSION_CACHE=$(xaffinity session start)
xaffinity list export "My List" | xaffinity person get
xaffinity session end
See Pipeline Optimization for details.
Query Command Tuning¶
For the query command, advanced users can tune concurrency:
| Variable | Default | Description |
|---|---|---|
XAFFINITY_QUERY_CONCURRENCY |
15 | Max concurrent API calls for fetches/expansions |
Higher values speed up queries with include or expand but may trigger rate limits on smaller accounts.
Update Notifications¶
The CLI checks for available updates once per day and displays a notification after command execution:
┌──────────────────────────────────────────────────────┐
│ Update available: 1.0.0 → 1.1.0 │
│ Run: pip install --upgrade "affinity-sdk[cli]" │
└──────────────────────────────────────────────────────┘
The upgrade command is auto-detected based on your installation method (pipx, uv, pip).
The check is non-blocking and never delays command execution. Notifications are automatically suppressed when:
- Using
--quietor--output json - Running in CI/CD environments (
CI,GITHUB_ACTIONS, etc.) - Not attached to a terminal
- Using the
--no-update-checkflag
Configuration¶
Disable update checks via config file (~/.config/xaffinity/config.toml):
[default]
update_check = false
Or via environment variable:
export XAFFINITY_NO_UPDATE_CHECK=1
Control notification behavior with update_notify:
[default]
update_notify = "interactive" # "interactive" (default), "always", or "never"
Manual Check¶
Check your update status (queries PyPI if no recent cache):
xaffinity config update-check
Force a fresh check regardless of cache age:
xaffinity config update-check --now
See detailed update status (JSON-friendly):
xaffinity config update-check --status
Background Check (for MCP/Automation)¶
Trigger a non-blocking background update check (used by MCP server):
xaffinity config update-check --background
This spawns a background worker that checks for updates and caches the result. It exits immediately with no output on success, exit code 1 on failure.
Progress + quiet mode¶
- Long operations show progress bars/spinners on stderr when interactive.
-q/--quietdisables progress and suppresses non-essential stderr output.
Logging¶
The CLI writes logs to platform-standard locations (via platformdirs), with rotation and redaction.
Override with:
--log-file <path>--no-log-file
SDK controls¶
These flags expose useful SDK behaviors directly from the CLI:
--readonly: disallow write operations (guard rail for scripts).--max-retries N: tune rate-limit retry behavior.--trace: trace request/response/error events to stderr (safe redaction).
Advanced configuration (testing)¶
For testing against mock servers, these environment variables override API base URLs:
AFFINITY_V1_BASE_URL: Override V1 API base URL (default:https://api.affinity.co)AFFINITY_V2_BASE_URL: Override V2 API base URL (default:https://api.affinity.co/v2)
These can also be set per-profile in the config file.
Exit codes¶
0: success1: general error2: usage/validation error (including ambiguous name resolution)3: auth/permission error (401/403)4: not found5: rate limited or temporary upstream failure (429/5xx after retries)130: interrupted (Ctrl+C)143: terminated (SIGTERM)