A Go CLI for the Airbyte API, designed to be driven by both humans and AI agents.
The CLI exposes Airbyte's resources (organizations, workspaces, connectors, etc.) as a uniform airbyte-agent <resource> <operation> interface. Every command supports JSON input/output, schema introspection via --describe, and structured JSON errors with stable exit codes — making it safe to script and easy for agents to discover at runtime.
See AGENTS.md for the full architecture reference and CONTEXT.md for the agent-facing usage guide.
brew install airbytehq/tap/airbyte-agentGrab the archive for your platform from the latest release, extract it, and put airbyte-agent somewhere on your $PATH. Builds are published for linux/darwin/windows × amd64/arm64 (Windows arm64 excepted).
git clone https://github.com/airbytehq/airbyte-agent-cli.git
cd airbyte-agent-cli
make build # builds ./airbyte-agent
# or
make install # installs to $GOBINOr directly without the Makefile:
go build -o airbyte-agent .Per-command agent skill documents live under skills/<command>/SKILL.md, each with YAML frontmatter (name, description, command) and task-oriented guidance. They are designed to be consumed by agent harnesses (e.g. Claude Code).
The skills work alongside the CLI — they tell the agent how to invoke each command, while the airbyte-agent binary does the actual work. Install the CLI first, then install the skills into your agent.
The skills installer discovers the skills/ directory in this repo and wires each SKILL.md into your agent (Claude Code, etc.):
# Install all skills
npx skills add airbytehq/airbyte-agent-cli
# Install one skill
npx skills add airbytehq/airbyte-agent-cli --skill connectors-execute
# Preview without installing
npx skills add airbytehq/airbyte-agent-cli --list
# Install globally instead of per-project
npx skills add airbytehq/airbyte-agent-cli -gTarget a specific agent with --agent claude-code (or another supported agent). See the skills CLI docs for the full flag set.
Copy or symlink skills/<command>/ into your agent's skill directory directly (e.g. ~/.claude/skills/ for Claude Code).
Settings can be supplied via environment variables or a settings file at ~/.airbyte-agent/settings.json. Three pieces of information are always required: client ID, client secret, and organization ID.
Run airbyte-agent login to be prompted for these values and have the file written for you with the right permissions.
- Environment variables — used only if all three of
AIRBYTE_CLIENT_ID,AIRBYTE_CLIENT_SECRET, andAIRBYTE_ORGANIZATION_IDare set. If any is missing, the CLI falls through to the file. - Settings file at
~/.airbyte-agent/settings.json. All three fields must be populated. - If neither is configured, the CLI exits with an authentication error.
Env vars take precedence over the file when all three are present, so they're useful for one-off overrides (e.g. AIRBYTE_ORGANIZATION_ID=... airbyte-agent ...).
| Variable | Description | Default |
|---|---|---|
AIRBYTE_CLIENT_ID |
OAuth client ID | (required) |
AIRBYTE_CLIENT_SECRET |
OAuth client secret | (required) |
AIRBYTE_ORGANIZATION_ID |
Organization ID | (required) |
AIRBYTE_WORKSPACE |
Default workspace name (used when commands don't pass workspace) |
default |
AIRBYTE_API_HOST |
API base URL | https://api.airbyte.ai |
AIRBYTE_WEBAPP_URL |
Web app URL for credential flows | https://app.airbyte.ai |
AIRBYTE_CREDENTIAL_TIMEOUT |
Credential flow timeout (seconds) | 180 |
AIRBYTE_ALLOW_DESTRUCTIVE |
When truthy (1/true/yes/on), skip the interactive confirmation prompt on destructive commands like connectors delete. Mirrors allow_destructive in the settings file. |
false |
AIRBYTE_TELEMETRY_MODE |
Set to disabled to turn off telemetry. Any other value (or unset) falls through to telemetry_enabled in the settings file. |
(settings file) |
~/.airbyte-agent/settings.json:
{
"settings": {
"credentials": {
"client_id": "your-client-id",
"client_secret": "your-client-secret"
},
"organization_id": "your-org-id",
"workspace": "default",
"allow_destructive": false,
"telemetry_enabled": true
}
}| Key | Description | Default |
|---|---|---|
credentials.client_id |
OAuth client ID | (required) |
credentials.client_secret |
OAuth client secret | (required) |
organization_id |
Organization ID | (required) |
workspace |
Default workspace name; commands that take a workspace parameter fall back to this when not provided |
default |
allow_destructive |
When true, destructive commands (e.g. connectors delete) skip the interactive confirmation prompt. Intended as a one-time permission grant for agent harnesses without TTY input. |
false |
telemetry_enabled |
When false, anonymous usage telemetry is disabled. Can also be turned off at runtime with AIRBYTE_TELEMETRY_MODE=disabled. |
true |
airbyte-agent <resource> <operation> [flags]Parameters can be supplied two ways: as a single JSON document via --json, or as individual flags (--workspace foo --name bar). The two modes are mutually exclusive — passing both is an error. Output is JSON by default; --format table produces a human-readable table.
1. Individual flags (recommended for humans) — scalar and array parameters in the operation's schema are exposed as --<param> flags, with snake_case keys converted to kebab-case (e.g. select_fields → --select-fields):
airbyte-agent connectors describe --workspace default --name hubspot
airbyte-agent connectors execute --workspace default --name hubspot \
--entity contacts --action read \
--select-fields id,email,nameRun airbyte-agent <resource> <operation> --help to see the available flags for any command.
2. JSON (recommended for agents and complex payloads) — pass the whole parameter set as a JSON object:
airbyte-agent connectors execute --json '{
"workspace": "default",
"name": "hubspot",
"entity": "contacts",
"action": "read",
"select_fields": ["id", "email", "name"]
}'Use @filename to load JSON from a file: --json @params.json. --json is the only way to pass nested objects (e.g. the params field on connectors execute).
| Flag | Description | Default |
|---|---|---|
--json |
Operation flag for inline JSON parameters (or @filename to load from a file). Cannot be combined with per-parameter flags. |
-- |
--format |
Output format: json or table |
json |
--describe |
Print the operation's parameter schema and exit | false |
--output, -o |
Write output to a file instead of stdout | -- |
--verbose, -v |
Enable debug logging | false |
--fields |
Filter the response to only the listed fields. Comma-separated, dotted paths (e.g. data.id,data.name). Applied client-side, after the API responds. Errors are not filtered. |
-- |
--fields shapes the response payload after it returns from the API. Paths use dotted notation; when a path crosses an array, the remaining segments are applied to every element ("array broadcast"):
# Both of these work — list responses are wrapped in {"data": [...]} and the
# CLI auto-broadcasts when no path matches a top-level key.
airbyte-agent organizations list --fields id,organization_name
airbyte-agent organizations list --fields data.id,data.organization_name
# Mixed paths require explicit prefixes — the auto-broadcast only fires
# when *no* path matches a top-level key:
airbyte-agent connectors list --fields data.id,data.name,nextPath resolution rules:
- Strict match first. Paths are matched against top-level keys of the response.
- Smart wrapper fallback. When no paths match top-level keys AND the response has exactly one top-level array (e.g.
{"data": [...]}), each path is implicitly prefixed with that wrapper's key and re-applied. Lets you write--fields id,nameinstead of--fields data.id,data.namefor list-style responses. - Mixed cases stay strict. If even one path matches top-level, no rewrite happens — pass explicit dotted paths if you also want row-level fields.
- Missing paths are dropped silently. Errors are never filtered.
This is client-side: the full payload still travels from the API to the CLI. To reduce upstream work, connectors execute separately accepts select_fields / exclude_fields which are sent to the source connector. The two are complementary — combine them when you want both bandwidth savings and a clean output shape.
airbyte-agent --help # list resources
airbyte-agent connectors --help # list operations
airbyte-agent connectors execute --describe # CLI params + OpenAPI request/response schema
airbyte-agent schema connectors execute # equivalent top-level form--describe and airbyte-agent schema <resource> <operation> return the same payload: CLI-level parameters under params, plus the underlying OpenAPI route (path, method, parameters, request body, response) under api. The OpenAPI schemas are extracted at build time from api/*.json and cover only the routes the CLI actually uses, so the dump stays focused.
# Find a workspace
airbyte-agent workspaces list --json '{}'
# Discover what a connector can do
airbyte-agent connectors describe --json '{"workspace": "default", "name": "hubspot"}'
# Read data, limiting fields to keep the response small
airbyte-agent connectors execute --json '{
"workspace": "default",
"name": "hubspot",
"entity": "contacts",
"action": "read",
"select_fields": ["id", "email", "name"]
}'
# Create a new connector (opens a browser for secure credential entry)
airbyte-agent connectors create --json '{
"workspace": "default",
"name": "hubspot"
}'
# Load a complex payload from a file
airbyte-agent connectors execute --json @params.jsongo build ./...
go test ./...
go vet ./...To add a new resource: implement the Resource interface in internal/resources/<name>.go, register it in register.go, and add tests using the existing newTestTokenServer() / newTestClient() helpers. See AGENTS.md for the full guide.
Releases are cut by pushing a v* tag. The release workflow builds binaries for linux/darwin/windows × amd64/arm64 (Windows arm64 excepted) via goreleaser, uploads them as a draft GitHub release, and commits an updated Formula/airbyte-agent.rb to airbytehq/homebrew-tap.
Tags follow semver. While the API is unstable, stay on v0.x.y:
v0.x.0— new features or behavior changes (added a command, changed default behavior)v0.x.y— bug fixes onlyv1.0.0— first stable release; downgrade contract begins
Pre-releases use a suffix (v0.2.0-rc1, v0.2.0-beta); goreleaser publishes the GitHub release but skips the Homebrew formula update for these.
-
Make sure
mainis green. All tests pass,go generate ./...produces no diff (CI enforces this). -
Tag from
main:git checkout main git pull git tag v0.1.0 git push origin v0.1.0
-
Watch the release workflow. It runs in two halves:
- Builds + uploads a draft GitHub release (binaries, archives,
checksums.txt). - Commits
Formula/airbyte-agent.rbtoairbytehq/homebrew-tap@main.
- Builds + uploads a draft GitHub release (binaries, archives,
-
Review the draft release. Open it in the GitHub UI, check the auto-generated changelog, and either edit the notes or accept them.
-
Click Publish. This is intentional manual gating — easy to catch a misconfigured formula or stale changelog before users see it.
-
Smoke-test the install on a fresh machine:
brew install airbytehq/tap/airbyte-agent airbyte-agent version
Validate the release pipeline locally without pushing anything:
goreleaser check # validates .goreleaser.yaml
goreleaser release --snapshot --clean
# inspect dist/ — binaries, archives, and dist/homebrew/Formula/airbyte-agent.rbThe snapshot run produces real artifacts in dist/ so you can confirm the formula renders correctly and the version-stamped ldflags resolve as expected. Nothing is uploaded.
- Bad binaries, formula not yet committed. Delete the draft release in the GitHub UI, delete the tag locally and remotely (
git tag -d v0.1.0 && git push origin :refs/tags/v0.1.0), fix, retag. - Formula already committed but binaries broken. Delete the formula commit on
homebrew-tap(open a one-line revert PR), then retag a new patch version. Don't re-use the same tag. - Need to yank a published release. Delete the formula commit on
homebrew-tap. Existingbrew installs won't rollback automatically; users with the broken version will keep it until theybrew upgrade airbyte-agent. Consider a0.x.y+1patch release rather than a yank when possible — fewer surprises for users.