Reference
CLI#
agent-connector <command> [flags]. Run agent-connector <command> --help for command-specific flags. --help/-h/help print usage; --version/-v prints the program name and version.
Shared flags#
| Flag | Description |
|---|---|
--scope user|project | Install scope (default user). |
--targets a,b,c | Comma-separated PlatformId allow-list. |
--connector <path> | Explicit config module. |
--project <dir> | Project directory (defaults to cwd). |
--dry-run | Render and diff without writing. |
--json | Emit machine-readable output (where noted). |
Commands#
detectagent-connector detect [--project <dir>] [--json]Probes every registered adapter and prints, per installed host: name, id, hook paradigm, install scope, the native config path that would be written, confidence + reason, and a one-line capabilities summary. --json emits the raw DetectedPlatform[].
installagent-connector install [<source>] [--method direct|marketplace] [--scope user|project] [--targets …] [--connector <path>] [--project <dir>] [--dry-run] [--force]Per target: backup settings → render server config → if hooks & paradigm≠mcp-only, synthesize the entrypoint + write hook config + set exec bit → write command/skill/subagent files → upsert memory managed blocks (last among the content surfaces) → register in the plugin registry. Prints a readable diff plus warnings and a summary tally. Idempotent and reversible. The optional <source> may be a local path, GitHub/raw git source, npm:<package>[@version], archive:<path-or-url>, or a direct .tgz/.tar.gz/.zip source; fetched sources are cached under ~/.agent-connector/sources/ and must contain agent-connector.config.*. --method marketplace (drivable: claude-code, codex, opencode, kilo, kilo-cli, antigravity, antigravity-cli + droid, qwen-code + gemini-cli[legacy, sunsetting→Antigravity]) drives the host's own plugin flow instead — stage the bundle, register a local marketplace where the host has one, run the host's plugin-install verb (claude/codex `plugin install`/`add`, `gemini extensions install`, `agy plugin install`) or write a local `file://` entry for npm-plugin hosts (opencode/kilo) — with a guard refusing a double install by both methods; `uninstall --method auto` reverses whichever is present. Live-verified on Linux, native Windows, AND macOS (claude/codex/agy across all three; opencode npm-local on Linux+Windows; gemini on Linux/macOS, degrades to an actionable warn on gemini ≥0.41's folder-trust gate); other marketplace-format hosts print manual commands. --force overwrites USER-EDITED memory blocks (hash drift) after a timestamped backup; default is warn-and-leave. Exit code 1 if any change is a warn, else 0.
upgradeagent-connector upgrade [--channel stable|latest] [same flags as install]The single “bring everything current” verb (aliases: update, sync). Re-renders the connector into every target host idempotently (byte-identical entries report skip — this is also the self-heal path: run upgrade to repair a drifted install), then refreshes the stable home-bin pointer and prints managed update guidance (the exact npm i -g @ken-jo/agent-connector@<dist>). With no resolvable connector it does the tool-only refresh from anywhere. Never silently auto-updates. Same diff output + exit semantics as install for the re-render; exit 1 if the pointer refresh fails.
uninstallagent-connector uninstall [--method auto|direct|marketplace] [--connector-id <id>] [--connector <path>] [--scope …] [--targets …] [--project <dir>] [--dry-run] [--purge]Full inverse — excises memory managed blocks FIRST (a prefix scan over the connector's marker namespace plus the memory ledger, so even an id-only uninstall reclaims blocks; user-edited blocks are backed up before removal), then removes the connector's MCP + hook registrations and content files from every resolved target, using registered metadata so it works even when the source module is gone. The id comes from --connector-id, else inferred from the local config. With --purge it also removes the connector's ~/.agent-connector state record and, when no connectors remain, the shared home-bin launcher; without it the record lingers so the connector can be re-synced without re-registering.
doctoragent-connector doctor [--targets …] [--connector <path>] [--scope user|project] [--project <dir>] [--json] [--probe] [--heal] [--explain] [--dry-run]For each detected host (or --targets), loads its adapter, builds an InstallContext, and runs the adapter's doctor checks; prints [pass] / [warn] / [FAIL] with any suggested fix. Non-zero exit if any check FAILs (warns alone do not fail). With --probe it also spawns the connector's REAL stdio server and runs a live MCP handshake (initialize → negotiated protocolVersion + capabilities + serverInfo → ping → tools/list); probe FAILs fold into the exit code. Version checks come first, under agent-connector: the home-bin launcher exists and execs an existing CLI (FAIL when it points at a removed install — hooks, statusline and actions would silently stop), that CLI is the same agent-connector version as the one running doctor, and each registered connector was rendered by this framework version (connector.json frameworkVersion, stamped at install) with a registered version equal to the source connector's; any drift is a fixable warn that names upgrade. With --heal it self-heals — re-syncs every connector that has fixable findings (a missing memory block, an absent configPatch key, version drift, a stale home-bin), then re-diagnoses and reports healed / still-failing / deferred (drifted user-edited values are deferred, never overwritten). With --explain it prints an offline per-(host, event) hook-honor matrix — honored / degraded / dropped — for every declared event, resolved from the connector's OWN targets (or --targets) BEFORE installing, NOT from detection; it exits 1 only when a declared event is degraded (the host fires it but silently won't honor the reply) on an explicitly-targeted host, while a dropped event (a host with no native equivalent) is always informational (exit 0). --dry-run pairs with --heal to preview what would be healed/deferred without writing anything (always exits 0).
statusagent-connector status [--connector <path>] [--scope user|project] [--project <dir>] [--json]A light, glanceable install-state summary: one line per detected host showing which connectors are present (server / hooks). There is no MCP standard for local install state, so this is agent-connector infra — it reuses detect + a read-only config-present check, adds no adapter methods, and ALWAYS exits 0 (descriptive, never a gate — that contrast with doctor is why it exists).
secretsagent-connector secrets set <name> [--connector <path>] [--connector-id <id>] [--backend keychain|secret-service|credential-manager|file] [--stdin]
agent-connector secrets delete <name> [--connector <path>] [--connector-id <id>]
agent-connector secrets list [--connector <path>] [--connector-id <id>] [--json]
agent-connector secrets check [--connector <path>] [--connector-id <id>] [--backend <backend>] [--json]Store the secrets a connector references as ${secret:NAME} in the OS keystore, keyed by connector id: macOS Keychain (keychain, via /usr/bin/security), Linux Secret Service (secret-service, via secret-tool over D-Bus), Windows Credential Manager (credential-manager, via PowerShell; values ≤ 2560 bytes), or the opt-in file backend (~/.agent-connector/secrets/file-store.json, mode 0600, plaintext — NOT encrypted). The value never reaches a host config: hosts see the serve wrapper's --secret-env NAME={secret:NAME} placeholder and the wrapper injects the real value into the server's environment at launch, refusing to start the server when a name is not set. set writes to --backend, else $AGENT_CONNECTOR_SECRETS_BACKEND, else the OS-native backend; the backend holding each name is recorded (names only) in ~/.agent-connector/secrets/<id>.index.json and reads follow it. Connector resolution: --connector-id, --connector <path>, a local agent-connector.config.*, the single registered connector; check alone falls back to the id agent-connector and says so (no connector resolved — keystore check only). No output ever includes a value. Exit 2 on a usage error, 1 on any other failure. install warns per unset name; doctor reports the framework check <id>: secrets.
<name>Secret name: [A-Za-z0-9][A-Za-z0-9._-]{0,63} — the NAME in ${secret:NAME}. Values are non-empty strings of at most 8192 characters.--stdinset: read the value from stdin (one trailing newline stripped); a non-TTY stdin is read the same way. On a TTY the value comes from the hidden prompt `Enter value for <name> (input hidden):`. There is no --value flag.--backend keychain|secret-service|credential-manager|fileset: which store to write to (check: which store to test). Default: $AGENT_CONNECTOR_SECRETS_BACKEND (keychain|secret-service|credential-manager|file|auto), else the OS-native backend. file is plaintext and opt-in only.--jsonlist: a SecretListEntry[] ({ name, backend, updatedAt, present }) instead of the `name backend present updated` table; check: the availability + self-test result as JSON.
authagent-connector auth login <key> [--connector <path>] [--connector-id <id>] [--project <dir>] [--device|--loopback] [--port <n>] [--json]
agent-connector auth status [--connector <path>] [--connector-id <id>] [--project <dir>] [--json]
agent-connector auth logout <key> [--connector <path>] [--connector-id <id>] [--project <dir>]
agent-connector auth token <key> [--connector <path>] [--connector-id <id>] [--project <dir>]Log in to the OAuth 2.0 providers a connector declares under oauth.<key> (presets: google, microsoft, github, bing-webmaster, posthog, generic) and keep the refresh tokens in the OS keystore, keyed by connector id — the store secrets writes to, under the secret name oauth.<key>.refresh-token. login runs the browser loopback flow (PKCE S256, one request on 127.0.0.1; stderr: `Opening <label> authorization in your browser…` then the URL on its own line; with no browser available the engine prints `Authorize <label> at: <url>` instead) or the device-code flow (stderr: `Visit <verification_uri> and enter code <user_code>`), stores the refresh token and prints `logged in to "<key>" (<label>) for connector <id> — refresh token stored in <backend>`; a provider that returns no refresh token fails the login (`the provider returned no refresh token — <preset hint>`). status prints `key provider present obtained via` without touching the network; a missing login never fails it (only an unresolvable connector exits 1). logout revokes at the provider when it can, then forgets the token: `logged out of "<key>" for connector <id>` (+ ` (revoked at the provider)`, or ` (nothing was stored)`); a key with nothing stored still exits 0. token prints ONLY the access token to stdout — the one command that ever prints one; not logged in → exit 1 with `login "<key>" is not present for connector <id> — run auth login <key> --connector-id <id>`. Connector resolution: --connector-id, --connector <path>, a local agent-connector.config.*, the single registered connector. Exit 2 on a usage error (incl. an undeclared key: `auth <verb>: connector <id> declares no login "<key>" (declared: a, b)`), 1 on an engine failure (the message, then ` hint: <hint>` when present). Nothing prints a token, an authorization code, a PKCE verifier or a client secret except auth token; the engine writes human text to stderr only. install warns per missing login (`login "<key>" (<provider>) is not present — run auth login <key> before the server needs it`) and, before that line, per referenced secret that is not set (`login "<key>" (<provider>) references secret "<NAME>" which is not set — run secrets set <NAME> before auth login <key>`); doctor reports the framework check <id>: logins (pass `<n> login(s) present`; warn `secrets not set for login(s) <key>[, <key>…]: <NAME>[, <NAME>…] — run secrets set <name>` with the fix `run secrets set <name> --connector-id <id> for each of: <NAME>[, <NAME>…]` (<name> is literal placeholder text, <NAME> a real name) when a login references an unset secret, else warn `not logged in: a, b — run auth login <key>`; no network). With tokenExchangeUrl set, login first says `Tokens are exchanged through <tokenExchangeUrl> (the connector's token exchange service)` on stderr, and the code exchange, every refresh and device-code polling go to that URL with client_id and never a secret. Access tokens live in process memory only; the metadata file ~/.agent-connector/oauth/<id>.json (mode 0600) carries no token. agent-connector ships no client ids: the developer registers the app and ships clientId (with no secret, a literal clientSecret for google only — Google documents it as not confidential — or a tokenExchangeUrl), or each user registers their own and stores clientId and clientSecret as ${secret:NAME} references with secrets set.
<key>The login key — the property name under oauth.<key> (^[a-z0-9][a-z0-9-]{0,31}$). login, logout and token take exactly one; status lists them all.--device|--loopbacklogin: force the device-code or the browser loopback flow. Default: the config's flow, "auto" — loopback when a browser can be opened (AGENT_CONNECTOR_BROWSER=never|always overrides the detection), else device when the preset supports it.--port <n>login: bind the loopback listener to this port (for providers that require an exact redirect URI). Default: the config's redirectPort, else an ephemeral port.--jsonlogin: the LoginResult ({ key, provider, obtainedVia, backend, scope?, expiresAt? }); status: a LoginStatus[] ({ key, provider, present, backend?, obtainedAt?, obtainedVia?, scope?, revokedAt? }) instead of the `key provider present obtained via` table.
packageagent-connector package [--connector <path>] [--format <fmt>] [--out <dir>] [--project <dir>] [--dry-run]Emit a marketplace / extension-installable bundle from a connector. Resolves the config (--connector, else auto-discovered walking up from --project), packages it for --format into --out (default <cwd>/dist-plugin), and prints the emitted file tree plus per-format install instructions. Every bundle re-renders the SAME command/skill/subagent markdown the live adapters write, the home-bin hooks, and the serve-wrapped MCP entry (--host <platform>) — so a marketplace-installed connector still reports per-tool telemetry.
--format <fmt>One of the host plugin/marketplace formats (default agent-plugin — the Agent Plugins 1.0.0 bundle Codex, GitHub Copilot CLI, VS Code / JetBrains Copilot, Kiro and Hermes install; the retired codex-plugin / copilot-plugin names still parse and resolve to it), or "all" to emit every feasible host format into <out>/<fmt>/. Two OFFICIAL MCP standard artifacts are also available by name — mcp-server-json (a registry server.json) and mcpb (an MCPB bundle manifest) — but require a `publish` block, so they are opt-in and excluded from `all`. An invalid --format exits 2.--out <dir>Output directory (default <cwd>/dist-plugin). For --format all, each format writes to <out>/<format>/.--dry-runCompute the file tree without writing anything.
auditagent-connector audit [--connector <path>] [--package-json <path>] [--project <dir>] [--json] [--strict]Pre-install lint for branded MCP packages. It loads the connector, reads the nearest package.json, then checks that package name/version/bin, @ken-jo/agent-connector runtime dependency, connector id/version, and publish files coverage describe one coherent product identity. Warnings stay exit 0 by default; --strict turns warnings into exit 1 for CI.
telemetryagent-connector telemetry <report|export|leaderboard> [flags]Per-MCP token telemetry (the server's own bytes). Rows are aggregate counts only.
report --by tool|session|project --since <window> --connector <id> [--json]Ranked footprint table (default --by tool).export --format csv|json --out <file> --since … --connector <id>Raw aggregate records (stdout or to --out).leaderboard --by mcp|tool|surface --since … --connector <id> --scope <slice> [--json]Ranks per-connector ("which MCP costs the most"), per-tool, or per-surface (the 5 developer-axis surfaces).
usageagent-connector usage <report|export|leaderboard> [flags]Host-native token usage parsed read-only from each agent host's own session logs/DBs (complement to telemetry; the two are NOT summed). Aggregate counts only.
report --by platform|project|session|model|day --since … --platform <id> [--json]Aggregated table; prints skip notes for platforms requiring a sync.export --format csv|json --out <file> --since … --platform <id>Deduped records.leaderboard --by platform|model --since … --platform <id> [--json]The host/user leaderboard ("which CLI/host spent the most").
leaderboardagent-connector leaderboard [--since <window>] [--scope <slice>] [--connector <id>] [--json]Prints THREE origin-labeled leaderboards that measure DIFFERENT things and are NEVER summed: 🔌 MCP/Plugin (mcp-self), 🖥️ Host/User (host-scan-logs), 🛰️ Host-native turns (host-native-live). --scope slices only the MCP section; --connector <id> restricts the MCP and host-native sections to one connector (the host-scan section is connector-agnostic); --json emits { mcp, host, hostSkipped, hostNativeTurns }.
--since syntax#
Used by telemetry / usage / leaderboard: Ns, Nm, Nh, Nd (seconds / minutes / hours / days), e.g. 30s, 15m, 24h, 7d. Empty = no lower bound; malformed = error.
Internal entrypoints#
Hosts point at these; they are omitted / hidden from the top-level help.
agent-connector hook <platform> <event> --connector <id>Universal json-stdio hook entrypoint. Reads the whole host payload from stdin, dispatches runHook, writes stdout/stderr, exits with the adapter's exit code. Fail-open (never rejects).
agent-connector serve --connector <id> [--scope user|project] [--host <platformId>] -- <command> [args…]Telemetry-wrapping MCP stdio proxy. Splits argv at the first literal --; the real server invocation on the right is passed through verbatim. Tolerant flag parsing (strict:false). --host bakes the install-target platform id in so telemetry rows stamp hostPlatform correctly under headless spawns.
agent-connector usage-event <platform> --connector <id>HIDDEN opt-in host-native turn-usage hook (installed by Gemini / Antigravity adapters when host-native usage is enabled). Reads stdin, records a distinct model_turn row, ALWAYS exits 0 (fail-open).
agent-connector statusline <platform> --connector <id>Universal statusline (HUD) entrypoint a host's status line config points at. Reads the entire host payload from stdin, dispatches runStatusline, writes the rendered line. FAIL-SAFE: never wedges the host — always exits 0 (even a malformed invocation degrades to exit 0 with no output).
agent-connector action <platform> <actionId> --connector <id>User-invokable action entrypoint a host affordance (slash command / keybinding) points at. Reads NO stdin, dispatches runAction. USER-TRIGGERED (unlike the fail-open hook / fail-safe statusline): an unknown actionId or throwing run surfaces as exit 1 + a stderr message.