Skip to main content

Catalog and discovery

Browse the server catalog, search it by intent, and manage per-user provider connections from the terminal.

8 min read
View MarkdownEdit on GitHub

Eight commands cover the catalog and the per-user connections behind it: servers list, servers show, tools list, discover, connect list, connect start, connect revoke and wizard. None of them moves money, and only connect start and connect revoke change anything. Six go straight to a REST route. discover and wizard take a longer path: they open a session, run a meta-tool inside it, and close the session on the way out.

Every flag, message and exit code on this page was run against @codespar/cli 0.10.0 — the version on npm — and the transcripts are the captured bytes of those runs.

What every command here shares

Credentials and scope

Resolution order, first match wins: the root flag, then the environment variable, then ~/.codespar/config.json.

SettingRoot flagEnvironmentConfig key
API key--api-key <key>CODESPAR_API_KEYapiKey
API host--base-url <url>CODESPAR_BASE_URLbaseUrl
Project--project <id>CODESPAR_PROJECTproject

With nothing set, the host is https://api.codespar.dev. On the six commands that call REST directly, a resolved project rides as the x-codespar-project header and an unresolved one leaves the header off. discover and wizard hand the project to the SDK constructor instead.

Without a key, every command on this page refuses before it opens a socket:

codespar servers list
stderr, exit 1
✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.

That line is identical on all eight, and discover and wizard give it too: the key is resolved before the SDK is constructed. A key the API rejects is a different story, and the per-command tables below carry it.

stdout, stderr and --json

Tables, key/value blocks and JSON go to stdout. Status lines go to stderr, prefixed , or , and an empty table prints (no results) there too. A pipe into jq therefore receives the data alone.

--json is declared on the root command, but Commander accepts it on either side of the subcommand: codespar --json servers list and codespar servers list --json both printed the same JSON with an empty stderr. Colour is dropped when stdout is not a TTY, when NO_COLOR is set, or when FORCE_COLOR=0.

Exit codes

CodeWhenFirst line of stderr
0The command finished, including --helpnothing
1A refusal the CLI raises itself, or an argument Commander rejects✗ <message>, or error: <message> for Commander's own
2Any other exception. The stack trace follows✗ internal error:

discover and wizard reach the API through the SDK, and the SDK throws a plain Error, not the CLI's own error type. Measured: a 401 or a 403 on either command comes out as ✗ internal error: plus a stack trace and exit 2, where the six REST commands give exit 1 and one line. A tool call that answers success: false does the same. On these two commands, exit 2 is not evidence of a bug in the CLI.

codespar servers list

Lists the server catalog your key can see, one row per server, filtered server-side by whatever you pass.

GEThttps://api.codespar.dev/v1/servers
NameTypeRequiredWhat it does
-c, --category <name>stringnoSent as the category query parameter. The CLI does not validate the value
-r, --region <code>stringnoSent as the region query parameter. The flag's help names BR and MX as examples; any string is passed through
--jsonbooleannoRoot flag. Prints the array inside the response envelope, not the envelope

Measured wire: codespar servers list -c payments -r BR issued GET /v1/servers?category=payments&region=BR. An absent filter is left off the query string, never sent empty.

Command
codespar servers list
stdout
exit 0
ID          NAME        CATEGORY  REGION  TOOLS  STATUS
asaas       Asaas       payments  BR      12     live
stark-bank  Stark Bank  banking   BR      8      live
pomelo      Pomelo      issuing   -       -      beta

A column with no value prints -. With no rows at all, stdout is empty and stderr carries (no results).

Calls GET /v1/servers, documented at GET /v1/servers in the HTTP reference.

WhenWhat you getExit
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1
Key rejected or under-scoped✗ GET /v1/servers → 403: <the API's own message>1
Host unreachable, or slower than 30s✗ Network error calling GET /v1/servers: <cause>, or ✗ Request to GET /v1/servers timed out after 30000ms.1

codespar servers show <id>

Reads one server's detail record and prints its metadata, its description and the tools it exposes.

GEThttps://api.codespar.dev/v1/servers
GEThttps://api.codespar.dev/v1/servers/{id}/tools
GEThttps://api.codespar.dev/v1/servers/{id}/auth-schema
NameTypeRequiredWhat it does
<id>stringyesPositional. Percent-encoded into the path
--jsonbooleannoRoot flag. Prints the response body as received
Command
codespar servers show asaas
stdout
exit 0
ID        asaas
Name      Asaas
Category  payments
Region    BR
Status    live
Auth      api_key
Tools     12

Brazilian payment provider: Pix, boleto and card acquiring.

Tools:
  • codespar_charge — Issue an inbound charge
  • codespar_pay — Send an outbound payment

The Tools count prefers the record's own count and falls back to the length of the returned tool list. The description paragraph and the Tools: block are printed only when the response carries them.

WhenWhat you getExit
codespar servers show with no iderror: missing required argument 'id'1
Unknown id✗ GET /v1/servers/<id> → 404: <the API's own message>1
Key rejected or under-scoped✗ GET /v1/servers/<id> → 403: <the API's own message>1
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1

codespar tools list

Lists the tools of one server, with each description cut to fit a terminal column.

GEThttps://api.codespar.dev/v1/servers/{id}/tools
NameTypeRequiredWhat it does
-s, --server <id>stringyesThe server whose tools to list. It is the address of the listing, not a filter
--jsonbooleannoRoot flag. Prints the array with descriptions at full length

Changed in 0.8.0. --server used to be an optional filter and is now required: the API lists tools per server, so the server is the address of the listing. Without it the command refuses without touching the network, and names the two commands that lead to an id.

Command
codespar tools list --server asaas
stdout
exit 0
NAME                 DESCRIPTION
cancel_subscription  Cancel an active subscription.
create_customer      Create a customer. Required before creating any payment — Asaas requi…
create_payment       Create a payment charge (Pix, boleto, or credit card) linked to a cus…

24 tool(s) on asaas.

The DESCRIPTION column is truncated to 70 characters; --json carries the full text.

Calls GET /v1/servers/{id}/tools, which the HTTP reference documents.

WhenWhat you getExit
No --serverThe refusal above, naming codespar servers list and codespar tools meta. Nothing is sent1
Unknown server id✗ GET /v1/servers/<id>/tools → 404: <the API's own message>1
Key rejected✗ GET /v1/servers/<id>/tools → 401: <the API's own message>1
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1

codespar discover <query>

Searches the catalog by intent instead of by name: it opens a session attached to no server, runs the codespar_discover meta-tool inside it, prints the ranked matches and closes the session.

POSThttps://api.codespar.dev/v1/sessions/{id}/execute
NameTypeRequiredWhat it does
<query>stringyesPositional. Sent as use_case
--limit <n>integernoMust parse as a positive integer or the command refuses. Sent as limit, and used again locally as the number of rows printed. With the flag absent the CLI prints at most 10 and sends no limit
--category <name>stringnoSent as category when present
--country <code>stringnoSent as country when present. The flag's help names BR and MX as examples
-u, --user <id>stringnoThe session's user_id. Defaults to the literal cli-user. The default lives in the command body, not in Commander, so --help does not print it
--jsonbooleannoRoot flag. Prints the whole result object, not the table's five columns

Measured wire, in order: POST /v1/sessions with {"servers":[],"user_id":"cli-user"}, then POST /v1/sessions/{id}/execute with {"tool":"codespar_discover","input":{"use_case":"…","category":"…","country":"…","limit":5}}, then DELETE /v1/sessions/{id}. The session is closed in a finally, so it is closed even when the call fails.

Command
codespar discover "issue an NF-e for a service"
stdout and stderr, interleaved
exit 0
ℹ Strategy: embedding  ·  use_case: "issue an NF-e for a service"
#  SCORE  SERVER.TOOL                CONN          DESCRIPTION
1  0.887  codespar.codespar_invoice  connected     Issue an NF-e / NFS-e fiscal document after settlement.
2  0.609  codespar.codespar_charge   not_required  Issue an inbound charge so there is something to invoice.

ℹ Next steps:
  - Connect a fiscal provider
  - Call codespar_invoice with the charge id

Three things the table does not say for itself:

  • SCORE is computed by the CLI, not returned by the API. It is 1 - cosine_distance when a cosine distance is present, the trigram similarity when it is not, and - when neither is, always to three decimals. The stub's cosine_distance: 0.1132 printed as 0.887.
  • The Strategy line and the Next steps: label go to stderr; the table and the step items go to stdout. The label and its list are split across the two channels.
  • CONN is the match's connection status, one of connected, disconnected or not_required, taken from the SDK's own type. It is what tells you whether the tool you just found is callable today or needs a connection first.

With no match at all, stderr carries (no matches) and stdout stays empty.

Calls the codespar_discover meta-tool over POST /v1/sessions/{id}/execute. The tool's own arguments and result are documented at codespar_discover.

WhenWhat you getExit
codespar discover with no queryerror: missing required argument 'query'1
--limit 0, --limit abc, any non-positive or unparseable value✗ --limit must be a positive integer.1
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1
Key rejected or under-scoped✗ internal error: and a stack trace naming createSession failed: 403 …2
The tool call answers success: false✗ internal error: and a stack trace naming discover failed: <the tool's message>2

codespar connect list

Lists the per-user provider connections your project holds, with the dates cut to the day.

GEThttps://api.codespar.dev/v1/connections
NameTypeRequiredWhat it does
-u, --user <id>stringnoSent as the user_id query parameter. Unset means every user
--status <s>stringnoSent as status. The flag's help names connected, pending, revoked and expired; the CLI validates nothing and passes the string through
--jsonbooleannoRoot flag. Prints the array inside the envelope, with full timestamps

This route answers a connections envelope where servers list and tools list get a data envelope. It matters only if you read the raw HTTP; --json unwraps it either way.

Command
codespar connect list --user user_42 --status connected
stdout
exit 0
ID         SERVER       USER     STATUS     CONNECTED   EXPIRES
ca_7Fq2xb  asaas        user_42  connected  2026-09-02  -
ca_9Kd0mn  mercadopago  user_42  connected  2026-09-09  2026-12-08

CONNECTED and EXPIRES are the first ten characters of the ISO timestamp, so the time of day is visible only under --json. A null date prints -.

Calls GET /v1/connections, documented at GET /v1/connections in the HTTP reference.

WhenWhat you getExit
Key rejected or under-scoped✗ GET /v1/connections → 403: <the API's own message>1
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1
No connection matches the filters(no results) on stderr, empty stdout0

codespar connect start <server>

Opens a Connect Link flow for one end user and prints the authorize URL they have to visit.

POSThttps://api.codespar.dev/v1/connect/start
NameTypeRequiredWhat it does
<server>stringyesPositional. Sent as server_id in the body
-u, --user <id>stringnoSent as user_id. Defaults to the literal cli-user, a default that lives in the command body and not in --help
-r, --redirect-uri <url>stringnoSent as redirect_uri. Defaults to http://localhost:3000/connect/success so the flow completes without a hosted page of your own
--scopes <scopes>stringnoSent as scopes when present, omitted from the body when absent. Passed through as one string
--openbooleannoAsk for the link to be opened in the system browser. See the note below: it is a request, not a guarantee
--no-openbooleannoNever open the browser. Print the link only
--jsonbooleannoRoot flag. Prints the response body and nothing else

Measured body: {"server_id":"asaas","user_id":"user_42","redirect_uri":"https://app.exemplo.com.br/connect/done","scopes":"payments:read"}.

Command
codespar connect start asaas --user user_42
stdout and stderr, interleaved
exit 0
ℹ Connect asaas for user user_42:

  https://connect.codespar.dev/l/lnk_3Bq8

ℹ Link expires 13/09/2026, 15:00:00
ℹ Tip: pass --open on a future run to launch the link automatically.

The authorize URL is the only thing on stdout: a blank line, the URL indented by two spaces, a blank line. The expiry is rendered in the machine's own locale and timezone, so it is not a stable string to parse; --json carries the expires_at instant.

--open opens the browser only when stdout is a TTY, despite its help text reading "Force-open the link". Measured with stdout in a pipe: --open opened nothing, and a bare run and --no-open printed byte-identical output. The one visible difference in a pipe is that --open suppresses the Tip: line. The TTY branch itself was not exercised, because exercising it opens a real browser.

Before the OS opener is called, the URL is parsed and checked to be http or https, then passed as a literal argument with no shell in between, so a link carrying shell metacharacters cannot run a command. Both refusals, the malformed URL and the non-http scheme, are swallowed by a catch in this command: nothing is printed and the exit code stays 0. The URL is on stdout either way, which is what the fallback assumes.

Calls POST /v1/connect/start, documented at POST /v1/connect/start in the HTTP reference. The concept behind it is Connect Links.

WhenWhat you getExit
codespar connect start with no servererror: missing required argument 'server'1
Key rejected or under-scoped✗ POST /v1/connect/start → 403: <the API's own message>1
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1

codespar connect revoke <connection-or-server>

Revokes one connection, taking either the connection id or a server id it resolves on your behalf.

POSThttps://api.codespar.dev/v1/connections/{id}/revoke
NameTypeRequiredWhat it does
<connection-or-server>stringyesPositional. An argument starting with ca_ is treated as a connection id and revoked directly. Anything else is treated as a server id and resolved first
-u, --user <id>stringnoOnly used on the resolve path. Defaults to the literal cli-user

The resolve path costs one extra request: GET /v1/connections?user_id=<user>&server_id=<arg>&status=connected, and then the first row of that list is the one revoked. Measured: codespar connect revoke asaas -u user_42 issued that query and then POST /v1/connections/ca_7Fq2xb/revoke.

When a user holds more than one active connection to the same server, the first row of the list wins and the output names only the id it chose. The ordering the API applies to that list was not measured. Pass the ca_ id when you need to be sure which connection goes away.

Command
codespar connect revoke ca_7Fq2xb
stderr
exit 0
✓ Revoked connection ca_7Fq2xb.

This command has no JSON path. --json is accepted and ignored: measured, codespar connect revoke ca_7Fq2xb --json exits 0 with empty stdout and the same success line on stderr. A script that pipes it into a JSON parser gets an empty string.

Calls POST /v1/connections/{id}/revoke, documented at POST /v1/connections/{id}/revoke in the HTTP reference.

WhenWhat you getExit
A server id with no active connection for that user✗ No active connection for server "<arg>" and user "<user>".1
No argumenterror: missing required argument 'connection-or-server'1
Key rejected or under-scoped✗ POST /v1/connections/<id>/revoke → 403: <the API's own message>, or the same shape on the lookup that precedes it1
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1

codespar wizard [server-id]

Answers what a provider needs before it can be connected: which are connectable, what one connection's state is, and which secrets and steps a new connection takes.

POSThttps://api.codespar.dev/v1/sessions/{id}/execute
NameTypeRequiredWhat it does
[server-id]stringnoPositional, and the only optional positional in the CLI. Sent as server_id when present
--action <name>stringnolist, status or initiate. Validated by the CLI before anything opens. When absent the CLI sends no action at all, so the default is the backend's; the flag's help says status with a server-id and list without
--country <code>stringnoSent as country. The flag's help scopes it to the list action
--environment <env>stringnolive or test, validated by the CLI. The flag's help scopes it to initiate
--return-to <path>stringnoSent as return_to. The flag's help says a dashboard path, validated /dashboard/* on the dashboard side
-u, --user <id>stringnoThe session's user_id. Defaults to the literal cli-user
--jsonbooleannoRoot flag. Prints the whole result, including the fields the human rendering drops

Measured wire for an initiate: POST /v1/sessions with {"servers":[],"user_id":"cli-user"}, then POST /v1/sessions/{id}/execute with {"tool":"codespar_manage_connections","input":{"server_id":"asaas","action":"initiate","country":"BR","environment":"test","return_to":"/dashboard/connections"}}, then DELETE /v1/sessions/{id}.

The human output has three shapes, and the shape is chosen by the action the result carries, not by the flag you passed.

list · stdout
codespar wizard
SERVER      AUTH     STATUS        DIFFICULTY  CONNECTED
asaas       api_key  connected     easy        2026-09-02
stark-bank  cert     disconnected  hard        -
initiate · stdout and stderr
codespar wizard asaas --action initiate
✓ Asaas (api_key) → disconnected
server_id    asaas
difficulty   easy
connect_url  https://app.codespar.dev/connect/asaas
next_action  open_connect_url

ℹ Required secrets:
  - api_key  (starts with $aact_)

ℹ Instructions:
  1. Open the Asaas dashboard
  2. Copy the API key
  3. Paste it into the connect page

ℹ Known pitfalls:
  - The sandbox key does not work in live mode

The third shape, status, prints a success line and a four-row block: display_name, auth_type, difficulty, connected_at. As with discover, the section headings go to stderr and their items to stdout, so a redirect of stdout alone gives you the secrets and the steps without the labels that introduce them. An empty list prints (no connections) on stderr.

Calls the codespar_manage_connections meta-tool over POST /v1/sessions/{id}/execute. The tool itself is documented at codespar_manage_connections.

WhenWhat you getExit
--action outside the three names✗ --action must be one of: list, status, initiate.1
--environment outside live and test✗ --environment must be 'live' or 'test'.1
No API key resolved✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.1
Key rejected or under-scoped✗ internal error: and a stack trace naming createSession failed: 403 …2
The tool call answers success: false✗ internal error: and a stack trace naming connectionWizard failed: <the tool's message>2

Both validations run before the session is opened, so a rejected flag costs no request.

Catalog and discovery | CodeSpar