Skip to main content

AppXen CLI

Command-line tool for managing your AppXen MCP Gateway and RAG Engine. Ingest documents, search your knowledge base, and manage sources — all from the terminal.

Install

curl -sSL https://appxen.ai/install.sh | sh

Or install from PyPI:

pip install appxen

For local development:

pip install -e products/appxen-cli/

Requires Python 3.10+.

Quick Start

1. Log in with your API key

Get an API key from your appliance's console (https://) under API Keys, then:

appxen login

By default the CLI talks to https://localhost — the appliance's own Caddy origin, which fronts the console, gateway, and orchestrator behind a self-signed certificate. Running the CLI on the box itself, add --insecure (or set APPXEN_INSECURE=1) to skip TLS verification for that cert:

appxen login --insecure

Running the CLI from elsewhere? Point it at your appliance's own host:

appxen login --endpoint https://your-appliance-host

If the appliance has a domain name (set with sudo appxenctl set-domain <your-domain>), always pass --endpoint https://<your-domain>, on the box itself too. Caddy then serves only that domain, with its managed certificate, so the default https://localhost fails the TLS handshake and --insecure does not help. The default works only on a box without a domain, whose Caddy listens on :443 with the self-signed certificate.

appxen login --endpoint https://appliance.example.com

In a terminal you are prompted for your key (input is hidden). In a script, pipe it: when stdin is not a terminal, the key is the first line of stdin, and nothing is echoed:

printf '%s\n' "$APPXEN_KEY" | appxen login --endpoint https://your-appliance-host

The CLI checks the key's format (axgw_*), then verifies it with the appliance on an authenticated route. Only a key the appliance accepted is saved: a refused key, or one that could not be verified (the appliance is unreachable, its certificate is refused), is not saved and the command exits 1. For an appliance that cannot be reached yet, appxen login --no-verify saves the key unchecked.

Your key is stored in ~/.config/appxen/config.toml, mode 0600, in a directory of mode 0700.

Against the appliance's self-signed certificate (an appliance without a domain) the CLI refuses the connection and says so. --insecure (or APPXEN_INSECURE=1) skips the verification: use it for your own appliance, over a network path you trust, until it has a domain (sudo appxenctl set-domain <name>); never against a host you do not control. Every command that skips the verification says so, in one warning line on stderr.

2. Check connectivity

appxen status
CLI:       0.2.7
Endpoint:  https://localhost
Service:   mcp-gateway-pro
Gateway:   0.1.0
Status:    Connected
RAG:       12 sources, 347 chunks

3. Ingest documents

Single file:

appxen ingest ./report.pdf

Entire directory (recursive by default):

appxen ingest ./docs/

The CLI uploads each file, then polls until ingestion completes (chunking, embedding, indexing). You'll see progress bars for both stages:

Found 14 file(s) to ingest.
  Uploading architecture.pdf ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14/14
Waiting for 14 file(s) to process...
  Processing architecture.pdf ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14/14

OK 14 file(s) ingested successfully.
appxen search "how does authentication work"
╭──────────── #1 auth-design.md (score: 0.847) ────────────╮
│ Authentication uses passkeys (WebAuthn) as the primary    │
│ method with magic link email as a fallback...             │
╰──────────────────────── chunk: a1b2c3d4-e5f ─────────────╯
╭──────────── #2 api-keys.md (score: 0.723) ────────────────╮
│ API keys use the format axgw_{mode}_{version}_{hex} and   │
│ are stored as SHA-256 hashes in DynamoDB...               │
╰──────────────────────── chunk: f6g7h8i9-j0k ─────────────╯

Commands

appxen login

Save your API key to the local config.

appxen login --insecure                                    # default profile, on a box without a domain
appxen login --profile staging                              # named profile
appxen login --endpoint https://your-appliance-host          # remote appliance
appxen login --endpoint https://appliance.example.com       # appliance with a domain (on the box too)
Option Short Default Description
--profile -p the global appxen --profile, then APPXEN_PROFILE, then default Profile to save to
--endpoint -e https://localhost Appliance origin — gateway and orchestrator paths are derived from it
--insecure false Skip TLS verification, for the appliance's self-signed certificate (also APPXEN_INSECURE=1)
--verify / --no-verify --verify Verify the key with the appliance before saving it; --no-verify saves it unchecked

Exit status of appxen login: 0 the key was saved (verified first, unless --no-verify); 1 the key was refused, could not be verified or was not given, and nothing was saved; 2 usage: a malformed endpoint, or one that carries a user name or password (checked before the key is read), an unknown option.

appxen status

Check connectivity and the API key, show gateway info and RAG stats. The key is verified on an authenticated route (/health answers anyone).

appxen status
appxen status --json              # machine-readable output

Exit status of appxen status: 0 connected, with a key the appliance accepted; 1 the gateway is unreachable, or the key was refused (401, 403) or could not be verified (the authenticated route failed another way); 2 usage: a malformed endpoint or API key, an unknown option.

On 1 nothing is printed on stdout.

appxen ingest <path>

Upload files to the RAG knowledge base. Accepts a single file or a directory.

appxen ingest ./report.pdf                    # single file
appxen ingest ./docs/                         # directory (recursive)
appxen ingest ./docs/ --glob "*.md"           # only markdown files
appxen ingest ./docs/ --no-recursive          # top-level only
appxen ingest ./docs/ --no-wait               # upload and exit (don't wait)
appxen ingest ./docs/ --json                  # JSON output: waits, then prints the final state
appxen ingest ./docs/ --json --no-wait        # JSON output of the accepted state (status: queued)
appxen ingest ./scans/ --timeout 1800         # wait up to 30 minutes for each file
Option Short Default Description
--glob -g * Glob pattern for filtering files in a directory
--recursive / --no-recursive --recursive Recurse into subdirectories
--wait / --no-wait --wait Wait until every file is ingested, with --json too; --no-wait returns once the uploads are accepted (--poll / --no-poll are the same option)
--timeout 300 Seconds to wait for EACH file before reporting it as not ready (the appliance goes on ingesting it)
--json false Output raw JSON: one array, an entry per file

With --json, stdout is the array and nothing else; the progress goes to stderr. An entry is {"file", "source_id", "filename", "status", "chunk_count"}; a file that failed has "error" with the reason. A file that is not ready when its --timeout passes is a failure, and so is one whose source disappears during the wait (someone deleted it): the command goes on waiting for the other files and its document, or its summary, holds every file with its source id. Only a refused API key ends the command at once: no other file can succeed.

Supported file types:

Category Extensions
Documents .pdf .docx .html .htm .md .txt .csv .json .xml .yaml .yml
Code .py .js .ts .jsx .tsx .css .sql .sh .rs .go .java .c .cpp .h .rb .php
Images (OCR) .png .jpg .jpeg .tiff .bmp

Unsupported file types are silently skipped when scanning directories. The maximum file size is 100 MB.

Exit status of appxen ingest: 0 every file was ingested (with --no-wait: accepted); 1 nothing could be ingested at all: no supported file, not logged in, the API key was refused; 2 some or all files failed (upload refused, ingestion failed, not ready within --timeout, the source disappeared during the wait): the other files are still waited for, and with --json the document says which failed. Also a usage error (an unknown option, a --timeout that is not a positive number, a malformed endpoint or API key), which prints no document; 130 interrupted (Ctrl-C): stderr says how many files were uploaded and each one's last status, and the appliance goes on ingesting what it accepted.

2 for files that failed is the meaning it has had since 0.2.4 ("partial failure"). A script tells it from a usage error by the output: with --json, files that failed come with the document, each failed entry carrying "error"; a usage error prints nothing on stdout.

appxen search <query>

Semantic search over your knowledge base.

appxen search "database schema design"
appxen search "error handling" --top-k 10
appxen search "deployment steps" --json
Option Short Default Description
--top-k -k 5 Number of results to return
--json false Output raw JSON

appxen sources

List and manage knowledge base sources.

appxen sources                            # list all sources
appxen sources --status ready             # filter by status
appxen sources --search "report"          # filter by filename
appxen sources --limit 50                 # more results
appxen sources --json                     # JSON output
Option Short Default Description
--status -s Filter by status (ready, processing, queued, failed)
--search -q Filter by filename
--limit -n 20 Results per page
--offset 0 Pagination offset
--json false Output raw JSON
                          Sources (47 total)
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
┃ ID           ┃ Filename              ┃ Status ┃ Chunks ┃ Created             ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
│ a1b2c3d4-e5f │ architecture.pdf      │ ready  │     23 │ 2026-02-08T14:30:00 │
│ f6g7h8i9-j0k │ api-reference.md      │ ready  │      8 │ 2026-02-08T14:28:00 │
│ ...          │ ...                   │ ...    │    ... │ ...                 │
└──────────────┴───────────────────────┴────────┴────────┴─────────────────────┘

appxen sources delete <source_id>

Delete a source and all its chunks.

appxen sources delete a1b2c3d4-e5f6-7890-abcd-1234567890ab
appxen sources delete a1b2c3d4-e5f6-7890-abcd-1234567890ab --yes   # skip confirmation
Option Short Description
--yes -y Skip the confirmation prompt

appxen stats

Show knowledge base statistics.

appxen stats
appxen stats --json
╭──────────────────────── RAG Engine Stats ─────────────────────────╮
│ Sources:  47                                                      │
│ Chunks:   1,203                                                   │
│ Storage:  24.7 MB                                                 │
╰───────────────────────────────────────────────────────────────────╯

appxen workflow

Workflows of the Agent Orchestrator: list, compile <file>, create <file>, get <id>, delete <id>, run <id>, status <execution>, output <execution>, stop <execution>.

appxen workflow create ./digest.md --name digest
appxen workflow run wf_123 -i topic=security        # starts it and waits for the end
appxen workflow run wf_123 --no-poll --json         # starts it and returns the execution id
appxen workflow status exec_456 --poll --timeout 1800
appxen workflow output exec_456 --save result.md
appxen workflow run wf_123 --json --save result.md  # the document on stdout AND the output in the file
appxen workflow stop exec_456

workflow run (unless --no-poll) and workflow status --poll wait until the execution ends: completed, failed, rejected, timed_out or aborted.

Option Default Description
--timeout 600 Seconds to wait before giving up; the execution keeps running on the appliance

Exit status of appxen workflow run: 0 the execution completed (with --no-poll: it was started); 1 it could not be started, it ended failed, rejected, timed_out or aborted (its error is printed), or it was still running when --timeout passed; 2 usage: --save together with --no-poll, an unknown option, a malformed endpoint or API key; 130 interrupted (Ctrl-C) during the wait: stderr says what status the execution was last seen in, and it keeps running on the appliance.

Exit status of appxen workflow status: 0 the status was read (with --poll: the execution completed); 1 the execution could not be read, or with --poll it ended failed, rejected, timed_out or aborted, or it was still running when --timeout passed; 2 usage: an unknown option, a --timeout that is not a positive number, a malformed endpoint or API key; 130 interrupted (Ctrl-C) during --poll: the execution keeps running on the appliance.

An execution held at an approval gate (awaiting_approval) is approved or rejected in the console. With --json, stdout is one document, {"execution": ..., "steps": [...]}: the final state, or at the deadline the state as last seen; nothing after an interrupt.

--save FILE (workflow run, workflow output) writes the output to a file, with --json too (the "saved" line is then on stderr). It is refused with --no-poll (exit 2: there is no output to save yet), and with no output to write it is an error, never an empty file.

workflow stop on an execution that had already ended changes nothing and says so (had already ended (status: completed); nothing was stopped), exit 0.

Configuration

Config file

Stored at ~/.config/appxen/config.toml:

[default]
api_key = "axgw_live_k1_..."
endpoint = "https://localhost"
insecure = true

[staging]
api_key = "axgw_test_k1_..."
endpoint = "https://staging-appliance.example.com"
insecure = false

Switch profiles with --profile or APPXEN_PROFILE:

appxen --profile staging sources
appxen -p staging search "test query"
APPXEN_PROFILE=staging appxen stats
appxen --profile staging login          # saves to [staging]

Which profile is used, nearest first: the command's own --profile (only login has one), the global appxen --profile, APPXEN_PROFILE, then default. insecure skips TLS verification only as the boolean true. The file is replaced atomically on every save.

Environment variables

Environment variables override the config file:

Variable Description
APPXEN_API_KEY API key. When set, NO profile is read: the endpoint is APPXEN_ENDPOINT (default https://localhost)
APPXEN_ENDPOINT Appliance origin, used with APPXEN_API_KEY
APPXEN_INSECURE 1, true, yes or on skips TLS verification, for the appliance's self-signed certificate; any other value (0, false, empty) keeps it on. Overrides the profile's insecure
APPXEN_PROFILE Profile to use when --profile is not given (default: default)

The endpoint is the appliance's origin (https://<host>[:port]). One that carries a user name or password (https://user:pass@host) is refused. Plain http:// to a host other than this machine works, with a warning on stderr that the API key travels unencrypted.

# One-off command against the appliance box itself
APPXEN_API_KEY=axgw_test_k1_abc123 APPXEN_INSECURE=1 appxen status

JSON Output

Commands that read from the appliance take --json for scripting and piping. Stdout is then exactly one JSON document, written as it is (never wrapped to the terminal width, text outside ASCII escaped); progress, warnings and errors go to stderr; a command that fails prints no document, except a wait that ended (see appxen workflow) and ingest (the array says which file failed).

# Get source IDs for all ready sources
appxen sources --json | jq '.sources[] | select(.status == "ready") | .source_id'

# Count chunks across all sources
appxen stats --json | jq '.chunk_count'

# Ingest and capture results
appxen ingest ./docs/ --json | jq '.[] | {file, status, source_id}'

Exit status

Code Meaning
0 Success
1 The command failed: not logged in, the appliance is unreachable or refused the API key, an execution did not complete
2 Usage: an unknown option, a malformed endpoint (https://host:abc, https://user:pass@host), an API key that cannot be sent, --save with --no-poll. For ingest also: some or all files failed (see appxen ingest)
130 Ctrl-C during a wait (ingest, workflow run, workflow status --poll)

Errors and warnings go to stderr, each message on one unwrapped line, and never contain the API key. A certificate that cannot be verified, a refused key and a malformed endpoint each say what to do next.

appxen status (without --json) and appxen login also look for a newer CLI at https://appxen.ai/releases/latest.json (3 seconds at most; a failure is silent, a success is remembered for a day).

Examples

Ingest a project's documentation

appxen ingest ./docs/ --glob "*.md" --recursive

Ingest only PDFs from a folder

appxen ingest ./reports/ --glob "*.pdf"

Search and get raw JSON for processing

appxen search "error handling patterns" --top-k 20 --json

Delete all failed sources

appxen sources --status failed --json \
  | jq -r '.sources[].source_id' \
  | xargs -I{} appxen sources delete {} --yes

Use in CI/CD

export APPXEN_API_KEY=${{ secrets.APPXEN_API_KEY }}
export APPXEN_ENDPOINT=https://your-appliance-host   # your appliance's origin

# Sync docs on every deploy
appxen ingest ./docs/ --glob "*.md"

Metadata

Release files for appxen 0.2.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for appxen 0.2.7
File Size Uploaded
appxen-0.2.7.tar.gz 84.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for appxen 0.2.7
File Interpreter ABI Platform
appxen-0.2.7-py3-none-any.whl Python 3 none any Details

Total release size: 125.7 kB

Release files / appxen-0.2.7.tar.gz

Download URL appxen-0.2.7.tar.gz
Size 84.6 kB
Tags Source
SHA-256 checksum
How to use checksums
d10729873538b062b32b3fd667e81532192962cdb2c597e5ea8075a5dd0d71ff
BLAKE2b-256 checksum
How to use checksums
dd9c4a9758cf87584084630aa96c3ec21abda80fd2cef13ca3df1f60ece8d701
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Release files / appxen-0.2.7-py3-none-any.whl

Download URL appxen-0.2.7-py3-none-any.whl
Size 41.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
470dd99f0fa71044458a93bd2bf6a501a168947fbfed059ccacb2219c0fdbde1
BLAKE2b-256 checksum
How to use checksums
589d58f20988956b8649de51daf9877c74c83880066d953d8198ba2c189c7649
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Release history Release notifications | RSS feed

This release

0.2.7 This release

2 release files

0.2.4

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page