Overview
The interactive shell and file pickers are there for a human at a terminal, but nothing in 3xcode requires them. Every command that would otherwise prompt has a flag to supply the answer up front, every long-running conversion can run detached and be polled from a script, and 3xcode commands --json exposes the full command surface as structured data instead of parsed --help text.
Non-Interactive Use
Anything that would normally open an interactive picker or confirmation prompt accepts the same information as a flag instead.
| Situation | Interactive default | Non-interactive flag |
|---|---|---|
| Logging in | Browser device flow | 3xcode login --email you@co.com --password *** |
| Picking a file to convert | Interactive file picker | Pass the file path as a positional argument |
| Destructive actions | Confirmation prompt | --force / -f (session, batch, workspace) or --yes / -y (update) |
| Choosing a BYOK provider | Interactive menu | --provider anthropic (or bedrock, vertex, azure) |
| A long-running conversion | Streams to your terminal, blocks it | --detach (pyspark convert) or batch run (always detached) |
# Non-interactive login for a CI runner or service account 3xcode login --email ci-bot@company.com --password "$CI_3XCODE_PASSWORD" # No pickers, no prompts: every value supplied up front 3xcode workspace init ./migration --name "nightly-run" 3xcode session create --name "nightly-run" --dir ./sql/ 3xcode batch create <session_id> --name "batch-1" --dir ./sql/ --sort simple-first 3xcode batch seal <session_id> <batch_id> 3xcode batch run <session_id> <batch_id> --workers 4
A Machine-Readable Command Manifest
3xcode commands lists every command 3xcode has. Add --json and it emits the same information as a structured manifest instead: every command's full path, summary, arguments, and options, with types, defaults, and aliases. This is the surface to build against if you're wiring 3xcode into a script, a CI pipeline, or an AI agent that needs to discover what the CLI can do without parsing --help output.
3xcode commands --json
{
"program": "3xcode",
"version": "0.2.1",
"schema_version": "1",
"global_options": [ { "name": "--verbose", "aliases": ["-v"], "type": "boolean", ... } ],
"commands": [
{
"path": "batch run",
"summary": "Run a sealed batch as a detached background worker.",
"arguments": [ { "name": "session_id", "required": true, ... } ],
"options": [ { "name": "--workers", "aliases": ["-w"], "type": "integer", "default": 0, ... } ]
}
// ...every other command, across all eight command groups
]
}Built for tooling, not just humans
Every argument and option carries its type, default, required flag, and aliases, enough structure to generate a wrapper, validate a call before running it, or build a UI on top of the CLI without hand-maintaining a command list.
A stable contract for AI agents
An agent that needs to drive 3xcode can call commands --json once, learn the full command surface, and construct valid invocations from it, rather than being hardcoded to a specific CLI version's flags.
Exit Codes
3xcode doesn't define a large table of specific exit codes: scripts should treat 0 as success and any non-zero code as failure, and check the printed error message (or the session/batch state) for the specific cause.
| Exit code | Meaning |
|---|---|
0 | Success (including an intentional early exit, like answering "no" to a confirmation prompt) |
1 | A command failed: a validation error, an unreachable backend, a failed conversion, etc. |
130 | Interrupted with Ctrl-C (SIGINT), the standard convention for a keyboard-interrupted process |
Environment Variables
| Variable | Purpose |
|---|---|
THREEXCODE_DISABLE_UPDATE_CHECK | Set to disable the background update-check notice entirely, useful for keeping CI logs clean. See Installation & Updates. |
Provider credentials for BYOK (Bedrock, Vertex, Azure) are also resolved through environment variables under the hood once you run keys store, but those are managed for you rather than something you typically set by hand in a script. See Multi-Provider & BYOK.
A CI Example
A minimal pipeline step that converts a directory of SQL and fails the build if the batch doesn't complete cleanly:
#!/usr/bin/env bash set -euo pipefail export THREEXCODE_DISABLE_UPDATE_CHECK=1 3xcode login --email "$THREEXCODE_EMAIL" --password "$THREEXCODE_PASSWORD" 3xcode workspace init ./migration --name "ci-run" SESSION_ID=$(3xcode session create --name "ci-run" --dir ./sql/ | grep -oE 'session-[0-9a-z-]+') BATCH_ID=$(3xcode batch create "$SESSION_ID" --name "ci-batch" --dir ./sql/ | grep -oE 'batch-[0-9a-z-]+') 3xcode batch seal "$SESSION_ID" "$BATCH_ID" 3xcode batch run "$SESSION_ID" "$BATCH_ID" --workers 4 # Poll until the batch is no longer running, then check its final state until 3xcode batch list "$SESSION_ID" | grep -q "$BATCH_ID.*completed\|$BATCH_ID.*failed"; do sleep 15 done 3xcode batch list "$SESSION_ID" | grep "$BATCH_ID.*completed"
Adjust the ID-parsing lines to match your CLI version's actual output format (or prefer commands --json plus your own wrapper for anything more than a quick shell script); the pattern, non-interactive flags, a detached run, and polling for terminal state, stays the same.