Skip to main content

Command-line client for the SellerClaw Agent API — LLM-friendly JSON output, device-flow auth, auto-generated from OpenAPI.

Project description

sellerclaw-cli

Command-line client for the SellerClaw Agent API.

sellerclaw-cli is designed to be driven either directly from a terminal or, more commonly, as a subprocess by automation and LLM agents. Every command:

  • returns structured JSON on stdout on success,
  • returns structured JSON on stderr on failure,
  • exits with a stable, categorical exit code,
  • reads credentials only from env / config file — never from argv.

Every documented endpoint of the SellerClaw Agent API is reachable: the CLI's typed subcommands are generated from the API's OpenAPI schema, so there are no hand-written wrappers that can fall behind.


Table of contents


Requirements

  • Python 3.11+ (3.11, 3.12, 3.13 are all tested in CI).
  • Linux, macOS, or Windows (POSIX file-permission handling applies only on Linux/macOS).
  • Network access to your SellerClaw Agent API endpoint.

Installation

Install from PyPI:

pip install sellerclaw-cli

or with uv:

uv pip install sellerclaw-cli
# or, to install as a tool you can run anywhere:
uv tool install sellerclaw-cli

Verify the install:

sellerclaw --version
# 0.1.0

The installed binary is sellerclaw (not sellerclaw-cli).

Quick start

# 1. Install
pip install sellerclaw-cli

# 2. Authenticate (opens a URL + code you confirm in a browser)
sellerclaw auth login

# 3. Call an endpoint
sellerclaw stores list-listings <STORE_ID> --status active --limit 5

That's it. See below for details on configuration, other auth flows, and output conventions.


Configuration

The CLI needs two pieces of configuration:

  • api_url — base URL of the Agent API (default: https://api.sellerclaw.com).
  • token — your personal sca_… agent token used for Authorization: Bearer … on every request.

Both can be supplied either via environment variables or via a config file.

Environment variables

Variable Purpose Default
SELLERCLAW_TOKEN Agent token (sca_…). Always sent as Authorization: Bearer <token>. (none)
SELLERCLAW_API_URL Base URL of the Agent API. https://api.sellerclaw.com
XDG_CONFIG_HOME Base dir for the config file (standard XDG behavior). ~/.config

Example:

export SELLERCLAW_TOKEN="sca_abc123..."
export SELLERCLAW_API_URL="https://api.example.com"
sellerclaw auth whoami

Config file

The config file is a small TOML file stored at:

  • $XDG_CONFIG_HOME/sellerclaw/config.toml if XDG_CONFIG_HOME is set, otherwise
  • ~/.config/sellerclaw/config.toml.

Format:

api_url = "https://api.example.com"
token = "sca_abc123..."

Either key is optional. The file is created automatically by sellerclaw auth login / sellerclaw auth logout, with mode 0600 (owner read/write only) on POSIX systems.

You can also create or edit the file by hand:

mkdir -p ~/.config/sellerclaw
cat > ~/.config/sellerclaw/config.toml <<'EOF'
api_url = "https://api.example.com"
token   = "sca_abc123..."
EOF
chmod 600 ~/.config/sellerclaw/config.toml

Priority / resolution order

For each of api_url and token, the CLI picks the first non-empty source, resolved independently:

  1. Environment variable (SELLERCLAW_API_URL, SELLERCLAW_TOKEN).
  2. Key in config.toml (api_url, token).
  3. Built-in default (api_url = https://api.sellerclaw.com; no default token).

This means you can, for example, keep api_url in the config file and inject the token only via env — handy for CI and container workflows:

# ~/.config/sellerclaw/config.toml has only api_url
SELLERCLAW_TOKEN="$CI_TOKEN" sellerclaw stores list-listings "$STORE_ID"

Inspecting the current config

sellerclaw auth whoami
# {"data":{"authenticated":true,"api_url":"https://api.example.com","config_path":"/home/you/.config/sellerclaw/config.toml"}}

authenticated: true means a token is configured (it is not validated against the server — make any real call to verify).


Authentication

Device flow (recommended)

Best for interactive use on your own machine:

sellerclaw auth login

The CLI prints a URL and a short code to stderr (so it never pollutes a stdout pipeline):

Open https://sellerclaw.com/activate
Enter the code: ABCD-1234
(waiting up to 600s, polling every 5s...)

Open the URL in a browser, paste the code, confirm. The CLI polls the API until the token is granted, then writes it to the config file. On success, stdout gets:

{"data":{"authenticated":true,"api_url":"https://api.sellerclaw.com","config_path":"/home/you/.config/sellerclaw/config.toml"}}

Email + password

sellerclaw auth login --password
# Email: you@example.com
# Password: ********

When stdin is not a TTY (e.g. piped), supply two lines — email, then password:

printf '%s\n%s\n' "you@example.com" "$PASSWORD" \
  | sellerclaw auth login --password

Password is never echoed and never appears in argv or environment.

Manual token

If you already have an sca_… token (for example, provisioned by a backoffice tool), just put it into the config file or export the env var:

export SELLERCLAW_TOKEN="sca_abc123..."
# OR
echo 'token = "sca_abc123..."' >> ~/.config/sellerclaw/config.toml

Logging out

sellerclaw auth logout

Removes the token key from the config file. The api_url setting (and anything else in the file) is preserved.


Using the CLI

Command structure

sellerclaw [GLOBAL OPTIONS] <group> <command> [COMMAND ARGS]

Discover what's available:

sellerclaw --help                        # list top-level groups
sellerclaw <group> --help                # list commands in a group
sellerclaw <group> <command> --help      # show args + options for one command

Typed commands (per tag)

Each OpenAPI tag becomes a top-level group (stores, ebay-listings, research-seo, agent-goals, …), and each operation within that tag becomes a subcommand. Path parameters are positional, query parameters are flags:

# GET /agent/stores/{store_id}/listings?status=...&limit=...
sellerclaw stores list-listings <STORE_ID> --status active --limit 10

# GET /agent/ebay/listings/{listing_id}
sellerclaw ebay-listings get <LISTING_ID>

# POST /agent/research/seo/keyword-ideas
sellerclaw research-seo keyword-ideas --seed widgets

Use --help on any command to see its exact arguments — the help text comes straight from the OpenAPI summary and schema.

Generic call / list-operations

If you know the OpenAPI operationId directly, or you're hitting an endpoint that hasn't been promoted to a typed subcommand, use the generic fallback:

# List every operation in the bundled OpenAPI snapshot
sellerclaw list-operations

# Filter by tag
sellerclaw list-operations --tag stores

# Invoke by operation_id, supply path/query/body manually
sellerclaw call list_listings \
  --path-param store_id=<STORE_ID> \
  --query-param status=active \
  --query-param limit=10

--path-param and --query-param are repeatable; both use KEY=VALUE syntax.

Passing request bodies

Any command whose OpenAPI operation has a requestBody accepts --json-body (short: -b). It supports three sources:

# 1. Literal JSON on the command line
sellerclaw stores publish-shopify-products <STORE_ID> \
  --json-body '{"ids": ["l1", "l2"]}'

# 2. File
sellerclaw stores create-shopify-products <STORE_ID> \
  --json-body @./product.json

# 3. Stdin (use @- as the value)
cat product.json | sellerclaw stores create-shopify-products <STORE_ID> \
  --json-body @-

The body is validated as JSON locally before any network call; invalid JSON exits with a user_error (exit 1).

Output formats

--format is a global option (before the subcommand), defaulting to json:

Value Description
json (default) Compact, single-line JSON. Ideal for pipelines (jq, LLM tools, scripts).
pretty Indented JSON (2 spaces). Still valid JSON.
yaml YAML.
table ASCII table when the payload is a list of flat dicts; falls back to pretty JSON otherwise.
sellerclaw --format pretty stores list-listings <STORE_ID>
sellerclaw --format yaml   stores list-listings <STORE_ID>
sellerclaw --format table  stores list-listings <STORE_ID>

Errors are always compact JSON on stderr, regardless of --format. Downstream error parsers can rely on a single stable shape.


Output contract

Success shape

On exit code 0, stdout contains exactly one JSON value (plus a trailing newline):

{"data": <payload>}

<payload> is whatever the API returned for that endpoint — a single object, a list, a primitive, or null.

Error shape

On any non-zero exit, stderr contains exactly one JSON value:

{
  "error": {
    "code":    "auth_error",
    "message": "Unauthorized",
    "status":  401,
    "details": { /* optional, parsed from the API response body */ },
    "hint":    "Run `sellerclaw auth login` to authenticate."
  }
}

Field presence:

  • code and message — always present.
  • status — present when the error originated from an HTTP response.
  • details — present when the API returned a structured error body.
  • hint — present for auth_error (currently always points at sellerclaw auth login).

Exit codes

Code Meaning Typical triggers
0 Success any 2xx
1 User error invalid CLI args, invalid JSON body, 4xx (non-auth), unknown operation_id
2 Server / network error 5xx after retries, connection refused, timeout
3 Auth error 401, 403, missing token

These are stable and categorical — scripts can switch on them without parsing stderr.

Retry behavior

The CLI transparently retries up to 3 attempts on these conditions:

  • HTTP status 429, 502, 503, 504
  • Transient transport errors: ConnectError, ReadError, WriteError, timeouts

Backoff between retries is exponential with a small jitter, capped at 10 seconds. When the server sends a Retry-After header (seconds), the CLI honors it exactly (no extra jitter on top). All other statuses and unknown httpx errors are returned immediately — no retries.

Requests time out after 30 seconds by default.


Using from scripts and LLM agents

The CLI was designed specifically to be wrapped as a subprocess. Conventions that make that robust:

  • Pure JSON on stdout. No progress bars, no log lines, no rich decoration leaking from stdout. Anything human-facing (login prompts, device-flow URL) is on stderr only.
  • Pure JSON on stderr on failure, with a stable shape.
  • Categorical exit codes. You can branch on returncode without touching stderr.
  • No credentials in argv. Even if you see a new CLI flag in the future, credentials will never be one of them. Pass them via env.
  • No interactive prompts in non-TTY mode. auth login --password reads from piped stdin; every other command just runs.

Minimal Python wrapper:

import json, os, subprocess

def run(*args, token=None, timeout=60):
    env = {**os.environ}
    if token:
        env["SELLERCLAW_TOKEN"] = token
    r = subprocess.run(
        ["sellerclaw", *args],
        env=env,
        capture_output=True,
        text=True,
        timeout=timeout,
    )
    if r.returncode == 0:
        return json.loads(r.stdout)["data"]

    err = json.loads(r.stderr)["error"]
    if r.returncode == 3:
        raise AuthError(err["message"])            # refresh token, retry
    if r.returncode == 2:
        raise TransientError(err["message"])       # safe to retry with backoff
    raise UserError(err["message"], details=err.get("details"))

stores = run("stores", "list-listings", store_id, "--status", "active", token=my_token)

Minimal shell wrapper:

if out=$(sellerclaw stores list-listings "$STORE_ID" --status active 2>err.json); then
    echo "$out" | jq '.data'
else
    code=$?
    jq '.error' err.json
    case $code in
        3) echo "auth failed — refresh token" ;;
        2) echo "transient — retry later" ;;
        *) echo "fatal" ;;
    esac
    exit $code
fi

Environment variables reference

Variable Read by Purpose
SELLERCLAW_TOKEN every command Agent token, sent as Authorization: Bearer <token>. Highest priority.
SELLERCLAW_API_URL every command Base URL of the Agent API. Overrides config file and default.
XDG_CONFIG_HOME auth *, whoami Base dir for the config file. Defaults to ~/.config.

Troubleshooting

{"error":{"code":"auth_error",…,"status":401,…}} / exit 3 No token found, or token is wrong / expired. Run sellerclaw auth login, or check sellerclaw auth whoami to see which sources are in play and what api_url the CLI is targeting.

{"error":{"code":"network_error",…}} / exit 2 Can't reach the API. Verify SELLERCLAW_API_URL / config api_url, DNS, firewall. The CLI already retries transient failures 3× with backoff — a persistent network_error usually indicates a misconfigured URL or blocked egress.

{"error":{"code":"server_error",…,"status":5xx}} / exit 2 API itself returned 5xx after the CLI retried. If it persists, the platform is having an incident; otherwise retry later.

{"error":{"code":"user_error","message":"unknown operation_id: …"}} The generic sellerclaw call <id> can't find that operation_id in the bundled OpenAPI snapshot. Use sellerclaw list-operations to see what's available in your installed version; upgrade the package if the endpoint is newer.

{"error":{"code":"user_error","message":"missing required path parameter(s): …"}} You invoked sellerclaw call without supplying all --path-param KEY=VALUE entries required by the URL template.

sellerclaw: command not found after pip install The install directory isn't on PATH. On many systems pip install --user installs into ~/.local/bin; add that to PATH or use pipx install sellerclaw-cli / uv tool install sellerclaw-cli which handle it for you.

My config file keeps getting ignored Check sellerclaw auth whoami — the config_path it prints is the one it reads. Common causes: XDG_CONFIG_HOME pointing somewhere unexpected, or a typo in the TOML (it must be api_url and token, lowercase, at the top level).


Uninstall

pip uninstall sellerclaw-cli
# optional — remove config + token
rm -rf ~/.config/sellerclaw

Development

This package lives in packages/sellerclaw-cli/ of the main SellerClaw monorepo. Commands and the OpenAPI snapshot bundled into the package are generated from the backend's openapi/agent.json; do not hand-edit files under sellerclaw_cli/commands/ or sellerclaw_cli/_spec.json.

From the repo root:

make cli-sync    # regenerate commands/*.py + _spec.json from openapi/agent.json
make cli-lint    # ruff + pyright
make cli-test    # unit tests (pytest + respx)
make cli-build   # build wheel + sdist

CI enforces zero drift between openapi/agent.json and the generated files. Releases are triggered by pushing a cli-X.Y.Z tag.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sellerclaw_cli-0.0.0.tar.gz (54.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sellerclaw_cli-0.0.0-py3-none-any.whl (71.8 kB view details)

Uploaded Python 3

File details

Details for the file sellerclaw_cli-0.0.0.tar.gz.

File metadata

  • Download URL: sellerclaw_cli-0.0.0.tar.gz
  • Upload date:
  • Size: 54.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sellerclaw_cli-0.0.0.tar.gz
Algorithm Hash digest
SHA256 1f6a0063e294b82f49ffcdd3d515f440845abbefb37ceb0aaff69fd47dcd57fa
MD5 107b1ee15a309e82ce05fd7354cb6475
BLAKE2b-256 85fc2ea9c050f97e512bef1a27dc73ae37883a8cd1503e30a3d0af3c16680053

See more details on using hashes here.

Provenance

The following attestation bundles were made for sellerclaw_cli-0.0.0.tar.gz:

Publisher: cli-release.yml on sellerai-com/sellerclaw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sellerclaw_cli-0.0.0-py3-none-any.whl.

File metadata

  • Download URL: sellerclaw_cli-0.0.0-py3-none-any.whl
  • Upload date:
  • Size: 71.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sellerclaw_cli-0.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5b67145500c067f22eab0e1a09410f0040734a3db9baa904f068532d14ba350e
MD5 c71da8bc038bbbff9b4ef2e7d1042c45
BLAKE2b-256 c7c5267c614e2cc3728e1c64e4ea8696586466a3aaac9e16c6bf83fc8ecf5961

See more details on using hashes here.

Provenance

The following attestation bundles were made for sellerclaw_cli-0.0.0-py3-none-any.whl:

Publisher: cli-release.yml on sellerai-com/sellerclaw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page