@answerlayer/cli
v0.3.0
Published
Open-source command line client for the AnswerLayer API.
Maintainers
Readme
AnswerLayer CLI
Open-source command line client for the AnswerLayer API.
Use it three ways: as a global command, on demand with npx, or as a Claude
Code plugin that lets Claude configure and drive it for
you.
Install
npm install -g @answerlayer/cliOr run it without installing:
npx -y @answerlayer/cli --helpThe CLI is zero-dependency and runs on Node 20+. It also runs on Bun, if you prefer it:
bun install -g @answerlayer/cli # or: bunx @answerlayer/cli --helpFor local development:
git clone https://github.com/AnswerLayer/answerlayer-cli.git
cd answerlayer-cli
npm linkUse with Claude Code
This repo is also a Claude Code plugin. Installing it gives Claude the CLI (on its PATH, no separate install) plus a skill that configures your host + API key and then answers questions against your data.
/plugin marketplace add AnswerLayer/answerlayer-cli
/plugin install answerlayer@answerlayerThen just ask — for example "set up AnswerLayer and tell me revenue last
month." Claude will prompt for your API key (and host, if you're self-hosted),
run answerlayer configure, and start asking questions for you. Your key is
stored locally in ~/.answerlayer/config.json; it is never sent anywhere except
to your AnswerLayer host as the X-API-Key header.
The plugin and the standalone CLI are the same tool — installing the plugin does
not change how answerlayer works from your terminal.
Configure
Create an API key in AnswerLayer with the scopes needed by your workflow, then
initialize the CLI. init verifies the key before it writes the config file, so
an invalid or expired key never overwrites a working local setup:
answerlayer init --api-key al_live_...The CLI talks to the hosted SaaS at https://app.answerlayer.io by default. For a
BYOC or self-hosted install, point it at your own URL:
answerlayer init --api-key al_live_... --base-url https://answerlayer.your-company.comThe first API key is currently created in the AnswerLayer app under Settings → API Keys. A browser/device login flow is planned; until then, the CLI will tell you exactly what credential is missing rather than saving an unverified value.
You can also skip the config file and use environment variables:
export ANSWERLAYER_API_KEY=al_live_...
export ANSWERLAYER_BASE_URL=https://answerlayer.your-company.com # optional overrideThe CLI sends API keys using the X-API-Key header.
Operate API pipelines
API pipeline authoring and lifecycle operations are CLI-first. The AnswerLayer web application is a read-only observability surface for pipeline health, run history, provenance, and failures.
Create a pipeline and upload an immutable package revision:
answerlayer pipelines create --name "REMPLAN Census" --json
answerlayer pipelines revisions push <pipeline-id> \
--package ./dist/remplan-census.zip \
--config-file ./pipeline-config.json \
--jsonInspect and update pipeline metadata, or explicitly pause and resume new production executions without losing the active revision:
answerlayer pipelines get <pipeline-id> --json
answerlayer pipelines update <pipeline-id> --description "National census" --json
answerlayer pipelines disable <pipeline-id> --json
answerlayer pipelines enable <pipeline-id> --jsonUse --clear-description to remove the description. Disabling a pipeline does
not prevent administrators from uploading and validating a replacement
revision; it prevents production execution until the pipeline is enabled.
Validate and promote the returned revision ID. --wait polls the exact run to
a terminal state and exits unsuccessfully when validation fails or is
cancelled:
answerlayer pipelines revisions validate <pipeline-id> <revision-id> --wait --json
answerlayer pipelines revisions connection-test <pipeline-id> <revision-id> --wait --json
answerlayer pipelines revisions probe <pipeline-id> <revision-id> \
--request-limit 2 --row-limit 100 --byte-limit 1048576 \
--runtime-limit 60 --wait --json
answerlayer pipelines revisions promote <pipeline-id> <revision-id> --jsonRevision history is immutable and inspectable. Compare the candidate revision against the current or previous revision before promotion:
answerlayer pipelines revisions list <pipeline-id> --json
answerlayer pipelines revisions get <pipeline-id> <revision-id> --json
answerlayer pipelines revisions diff <pipeline-id> <candidate-revision-id> \
--against <base-revision-id> --jsonThe diff contains artifact hashes and a secret-safe, JSON-pointer-addressed configuration diff. Configuration descriptors are digest-verified before they are returned.
Run and operate the promoted revision:
answerlayer pipelines runs start <pipeline-id> --wait --json
answerlayer pipelines runs start <pipeline-id> \
--dataset agep --dataset agepxbplp \
--idempotency-key census-2021-backfill --wait --json
answerlayer pipelines runs get <pipeline-id> <run-id> --json
answerlayer pipelines runs retry <pipeline-id> <run-id> \
--idempotency-key census-2021-retry-1 --wait --json
answerlayer pipelines runs cancel <pipeline-id> <run-id> --json
answerlayer pipelines archive <pipeline-id> --jsonDataset scope is explicit and fail-closed: every requested dataset must be in the promoted package's resolved catalog. Retrying a publish run reuses the previous run's durable dataset checkpoint, so completed datasets are not republished. Reusing an idempotency key returns the original matching run instead of launching a duplicate.
Create and operate the pipeline's install-local EventBridge schedule:
answerlayer pipelines schedule set <pipeline-id> \
--expression 'cron(0 2 * * ? *)' --json
answerlayer pipelines schedule get <pipeline-id> --json
answerlayer pipelines schedule resume <pipeline-id> --json
answerlayer pipelines schedule update <pipeline-id> \
--expression 'rate(12 hours)' --json
answerlayer pipelines schedule pause <pipeline-id> --json
answerlayer pipelines schedule delete <pipeline-id>Creating a schedule only defines it; new schedules are unarmed by default.
Run schedule resume after review, or pass --armed to schedule set when
immediate activation is intentional. --paused remains an explicit spelling
for creating the schedule unarmed.
Scheduled tasks invoke the isolated extractor directly and continue when the AnswerLayer web process is unavailable. Disabling or archiving a pipeline also stops its schedule from launching new work.
Roll back by selecting a revision that was previously promoted. This moves the active pointer back to the existing immutable revision; it does not copy or re-upload the package:
answerlayer pipelines revisions rollback <pipeline-id> <revision-id> --jsonUse --include-archived with pipelines list. Package ZIPs are built from the
customer-owned package repository; credentials and CA material must not be
included in the ZIP or revision configuration. They remain in the install's
managed secret interfaces.
Run locally with an agent
The package includes an answerlayer agent skill for evaluating AnswerLayer
against your own database without first creating a hosted account. Install it
for Codex with:
answerlayer skills installThis installs to ~/.codex/skills/answerlayer by default. Use --path for a
different skill directory; an existing skill is never replaced unless you pass
--force.
The recommended path is one command:
answerlayer local quickstartQuickstart asks for confirmation before it changes local state, then initializes and starts the supported public-image runtime, authenticates the CLI, installs the deterministic demo, and verifies the provider-free demo query. If no model provider is configured during an interactive run, quickstart offers to collect the Anthropic key through a hidden terminal prompt, verifies it, and continues directly to one real model-backed inquiry. The key is never accepted as a command argument or printed to output. Successful inquiry details are retained in the local runtime state, so repeating quickstart reuses the verified session instead of creating duplicate demo resources or inquiry sessions.
The provider step can be declined and resumed later by rerunning the same
answerlayer local quickstart command. Noninteractive --json runs never ask
for secret input and instead return a credential-free provider-required
handoff for an agent to report.
For agent automation after the user has explicitly approved starting
containers, use answerlayer local quickstart --yes --json. Progress is written
to stderr; stdout is one stable, credential-free JSON object containing the CLI
version, image digest, runtime directory, demo and provider status, local URL,
inquiry result, and next actions. --yes must not be used to bypass user
approval.
The underlying lifecycle commands remain available when manual control is needed:
answerlayer local init
answerlayer local startlocal init selects the CLI's supported public image by default. Use
--image <tag-or-digest> to select a different published version and --port
to change the local port. Fresh runtimes use http://127.0.0.1:8172; existing
runtimes keep their previously selected port. The CLI:
- Verifies Docker, its architecture and version, the port, and available disk.
- Pulls the public AnswerLayer image and pins its resolved immutable digest.
- Generates permission-restricted Compose, state, and secret files in the platform application-data directory.
- Starts Postgres, runs migrations, and waits for AnswerLayer readiness.
- Creates a local-only organization and scoped key, verifies the key, and saves the CLI configuration without printing the key.
- Seeds a versioned synthetic retail demo in a separate Postgres database, registers its dedicated read-only connection, creates starter semantic objects and a saved query, and verifies a deterministic result.
The local stack does not require a hosted AnswerLayer account, a source checkout, private registry credentials, or a model-provider key for first boot. Add an optional provider key later only when using features that call that provider. The skill requires agent confirmation before it starts containers, creates a connection, or sends queries to a real database, and it instructs agents not to print or persist database passwords.
The demo is installed by default. Use answerlayer local start --no-demo to
skip it, or install/verify it later with:
answerlayer local demo
answerlayer local demo --jsonlocal demo --json returns the demo version, connection ID, saved-query ID,
semantic-resource IDs, the verified result, and suggested natural-language
questions without returning credentials. The saved query works before a model
provider is configured:
answerlayer saved-queries execute <saved-query-id> --format tableNatural-language inquiry still requires provider configuration. Re-running the
demo command reuses the same connection and semantic resources rather than
duplicating them. local reset --force explicitly removes both application and
demo data because they share the selected runtime's isolated Postgres volume.
Configure Anthropic privately from your own terminal when you are ready to use model-backed features:
answerlayer local provider set anthropic
answerlayer local provider status --jsonThe interactive command disables terminal echo while you enter the key. It stores the credential only in the selected runtime's mode-0600 environment, recreates the application container without touching Postgres, and verifies the key with Anthropic's model-list API from inside that container. The key is never accepted as a command argument or returned by status output.
For non-interactive automation, place the key in a mode-0600 file and pass only its path:
answerlayer local provider set anthropic --from-file /secure/path/anthropic.key
# Or set ANSWERLAYER_PROVIDER_KEY_FILE to that path.Use local provider rotate anthropic to replace a working key. If validation
fails, the previous credential is restored. Use
local provider remove anthropic --force to disable model-backed features while
preserving all application and demo data.
Inspect and manage the lifecycle with:
answerlayer local status [--json]
answerlayer local logs [--follow] [answerlayer|migrate|postgres]
answerlayer local stop # preserves Postgres data
answerlayer local upgrade # moves to this CLI's supported default
answerlayer local upgrade --image <tag> # selects an explicit release
answerlayer local reset --force # permanently deletes local dataThe selected tag and resolved digest are recorded in state.json and displayed
by local status. Set ANSWERLAYER_LOCAL_DIR to override the application-data
directory or ANSWERLAYER_LOCAL_IMAGE to override the default image.
Each runtime directory receives stable, isolated Compose project, volume, and
network names, so stopping or resetting one runtime cannot affect another.
Useful scopes:
api_key:managefor API key managementconnection:readfor listing connectionsquery:executefor raw SQLsaved_query:read,saved_query:execute, andsaved_query:writefor saved-query workflowssemantic:read,semantic:write, andsemantic:generatefor semantic-layer workflowsdashboard:read,dashboard:write,tile:read, andtile:writefor dashboard workflowsinquiry:readto inspect inquiry sessions and evaluation suites/runsinquiry:executefor natural-language inquiry and to manage/run evaluations
Commands
Semantic optimization
Launch a durable, eval-driven optimization run without changing the active semantic layer:
answerlayer optimize start \
--name "Exoplanet semantic optimization" \
--connection CONNECTION_ID \
--suite SUITE_ID \
--model openai.gpt-5.6-terra \
--mode recommendationThe proposal model runs one bounded optimization session that reviews failed-case
traces, edits a detached candidate, validates it, and repairs diagnostics before
submission. Tune its bounds with --max-agent-turns,
--max-validation-attempts, and --max-targeted-evals.
Inspect and operate the registry with answerlayer optimize list,
get RUN_ID, pause RUN_ID, resume RUN_ID, stop RUN_ID, clone RUN_ID,
approve RUN_ID, and reject RUN_ID. Promotion is a separate, explicit atomic
compare-and-swap using the frozen hash shown by get RUN_ID:
answerlayer optimize promote RUN_ID --base-hash FROZEN_BASE_SHA256answerlayer health
answerlayer openapi --output openapi.json
answerlayer local init
answerlayer local start
answerlayer local quickstart --yes --json
answerlayer local demo --json
answerlayer local provider status --json
answerlayer local status
answerlayer local logs
answerlayer local stop
answerlayer connections list
answerlayer connections get <connection-id>
answerlayer connections create --data-file ./postgres-connection.json
answerlayer metadata structure <connection-id>
answerlayer query run <connection-id> --sql "select * from orders limit 10"
answerlayer query validate <connection-id> --sql "select * from orders"
answerlayer query run <connection-id> --file ./query.sql --format csv
answerlayer saved-queries list
answerlayer saved-queries create --name "Revenue by month" --connection <connection-id> --file ./revenue.sql
answerlayer saved-queries execute <saved-query-id> --format table
answerlayer semantic entities create --connection <connection-id> --name Orders --source-table public.orders --identifier id
answerlayer semantic metrics list --connection <connection-id>
answerlayer semantic metrics generate --connection <connection-id> --prompt "SaaS revenue metrics"
answerlayer inquiry ask --connection <connection-id> "What changed in revenue this month?"
answerlayer inquiry ask --session <session-id> "Break that down by region"
answerlayer inquiry models
answerlayer inquiry ask --connection <connection-id> --model claude-opus-4-6 "Investigate unusual revenue changes"
answerlayer evals suites create --name "Revenue checks" --connection <connection-id>
answerlayer evals suites get <suite-id> --json # complete suite for authorized inspection
answerlayer evals cases create <suite-id> --title "Monthly revenue" --question "What was revenue last month?" --category Revenue --expected-sql "select sum(amount) from orders where ..." --oracle-sources '[{"kind":"external","title":"Revenue policy","url":"https://example.com/revenue-policy"}]'
answerlayer evals cases create <suite-id> --title "Unseen revenue check" --question "How much revenue did we make?" --partition holdout --expected-sql "select sum(amount) from orders"
answerlayer evals runs create <suite-id> --label "Before prompt change"
answerlayer evals runs create <suite-id> --case <case-id> --case <case-id> --label "Focused smoke run"
answerlayer evals runs create <suite-id> --category Revenue --category Finance --case <case-id> --label "Focused category run"
answerlayer evals runs create <suite-id> --model claude-opus-4-6 --label "Model comparison"
answerlayer evals runs create <suite-id> --concurrency 4 --label "Parallel smoke run"
answerlayer evals runs create-batch --suite <suite-id> --suite <suite-id> --concurrency 4 --label "Release candidate"
answerlayer evals runs update <run-id> --label "Prompt experiment B"
answerlayer evals runs compare <run-id> --baseline <baseline-run-id>
answerlayer evals runs analyze <run-id> --json
answerlayer generation start --connection <connection-id> --component-type metrics --eval-suite <suite-id> --eval-case <authoring-case-id> --prompt "Improve these concepts"
answerlayer ontologies create --domain-key exoplanet-archive --name "Exoplanet Archive"
answerlayer ontologies version create <ontology-id> --file ./ontology.tff
answerlayer ontologies version validate <version-id>
answerlayer ontologies version review <version-id> # admin-only
answerlayer ontologies version freeze <version-id> # admin-only
answerlayer ontologies version export <version-id> --output ./ontology.tff
answerlayer dashboards create --title "Executive overview" --visibility org
answerlayer tiles create --title "Revenue" --source-type saved_query --source <saved-query-id>
answerlayer dashboards attach-tile <dashboard-id> --tile <tile-id> --x 0 --y 0 --w 6 --h 4
answerlayer documents upload ./definitions.md --title "Business definitions"
answerlayer documents link <document-id> --connection <connection-id>
answerlayer api-keys create --name "CI" --scope query:execute --scope saved_query:executeMost read commands support --json. Query results support --format table|json|csv.
For complex create/update payloads, pass structured JSON:
answerlayer connections create --data-file ./connection.json
answerlayer dashboards update <dashboard-id> --data '{"default_filters":[{"key":"region","type":"string_enum","label":"Region"}]}'
answerlayer branding update --data-file ./branding.jsonCommand groups
- Core:
api-keys,connections,metadata,query,query-results - Data products:
saved-queries,semantic,inquiry,evals,ontologies,generation,tiles,dashboards - Supporting resources:
documents,branding,uploads,chains,users,org,roles,billing,stats
Development
npm testThe package intentionally has no runtime dependencies. It requires Node.js 20 or newer for built-in fetch.
Releasing
Releases are automated with semantic-release.
Every push to main derives the next version from commit messages and publishes
to npm via OIDC — no manual version bump, tag, or token:
fix:/feat:/chore:/ unprefixed … → patch (0.0.X)feat(minor): …→ minor (0.X.0)type!: …orBREAKING CHANGE:in the body → major (X.0.0)
Related projects
answerlayer-go— Go client/SDK for the Inquiry API.
