Overview
The CLI, 3xcode, is a single command-line app with a set of top-level commands plus eight sub-command groups: config, keys, workspace, session, batch, schedule, org, and pyspark (the SQL-to-PySpark conversion agent). Running 3xcode with no arguments at all launches the interactive shell rather than printing help.
Every command and flag below is also available as structured data: run 3xcode commands --json for a machine-readable manifest, useful for scripts, CI, or an AI agent driving the CLI. See Automate & Script the CLI.
# Available on the root app, before any subcommand 3xcode --verbose <command> # -v, enables debug logging 3xcode --version # prints the installed version and exits 3xcode -v pyspark convert file.sql
No subcommand → interactive shell
Bare 3xcode launches the interactive shell instead of showing --help. Use 3xcode --help or 3xcode shell explicitly if you want the shell on purpose.
Several groups have a default action
Bare workspace runs workspace list, bare session runs session list, bare org runs org me. config and keys have no default: they show the standard missing-command error.
Top-Level Commands
These are registered directly on the root 3xcode app: no sub-command prefix needed.
| Command | Flags | Description |
|---|---|---|
3xcode login | --email/-e, --password/-p, --signup, --name | Authenticate: device-flow OAuth by default (opens a browser), or direct email/password login/signup with flags. |
3xcode logout | none | Clears stored credentials and invalidates the local session cache. |
3xcode status | none | Account status: plan tier, license validity/tier/remaining conversions/expiry, conversions this month, avg confidence, success rate. |
3xcode profile | none | Full profile: name, email, plan, admin flag, member-since, organization detail, default model, usage stats, device count. |
3xcode history | --limit/-n (default 20) | Show recent conversion history. |
3xcode version | none | Prints CLI version, Python version, platform/machine. |
3xcode health | none | Runs 5 system health checks: AI runtime available, backend API reachability, stored auth, active workspace, CPU/RAM + recommended worker count. |
3xcode ui | --port (default 3210) | Launches the local web UI and opens it in your browser. |
3xcode shell | none | Starts the interactive REPL, the same as running `3xcode` with no arguments. |
3xcode contact-admin | --message/-m (prompts if omitted) | Send a message to your admin (e.g. to request BYOK access or account verification). Requires login; message must be non-empty and ≤2000 chars. |
3xcode commands | --json | Lists every 3xcode command. With --json, emits the full machine-readable command manifest instead, for scripts, CI, and AI agents. |
3xcode update | --check, -y/--yes | Checks PyPI for a newer release and, unless --check is passed, offers to run the upgrade command for however you installed (pip/pipx/uv). Never installs silently. |
3xcode login # device flow (opens browser) 3xcode login --email you@co.com --password *** # direct login 3xcode login --email you@co.com # prompts for password securely 3xcode login --signup --email you@co.com --password *** --name "Your Name" 3xcode contact-admin -m "Please enable BYOK for my account" 3xcode commands --json > commands.json 3xcode update --check
config: Manage CLI Configuration
| Command | Flags | Description |
|---|---|---|
3xcode config show | none | Renders a table of every field in the loaded config. |
3xcode config set <key> <value> | positional `key`, `value` | Sets a config field. Short aliases: `model`→`default_model`, `effort`→`default_effort`, `input-dir`→`input_dir`, `output-dir`→`output_dir`, `port`→`web_ui_port`. Value is auto-coerced to the field's type; errors on unknown key. |
3xcode config show 3xcode config set model <tier> 3xcode config set output-dir ./converted
keys: Manage API Provider Keys (BYOK)
Valid providers everywhere: anthropic, bedrock, vertex, azure. BYOK must be enabled for your account by an admin before keys store/keys test are fully usable. Request it with 3xcode contact-admin. Keys are stored only locally (OS keychain, falling back to a file under ~/.3xcode/providers/) and are never sent to the backend; only the provider name and preferred models are registered server-side.
| Command | Flags | Description |
|---|---|---|
3xcode keys store | --provider (interactive menu if omitted) | Prompts for the chosen provider's credential fields and preferred models, then stores the key locally. |
3xcode keys list | none | Table of stored providers, masked credentials, preferred models, and storage backend (keyring vs file). |
3xcode keys delete <provider> | positional `provider` | Deletes a stored provider's key from local storage. |
3xcode keys status | none | Lists locally configured BYOK providers and storage backend, or reports "Using platform key" if none. |
3xcode keys test | --provider (default resolves to anthropic), --model | Makes a minimal live API call to verify a BYOK key works. Only available in BYOK mode: reports latency, model tested, key source, and approval state. |
3xcode login 3xcode contact-admin -m "Please enable BYOK for my account" 3xcode keys store --provider anthropic 3xcode keys list 3xcode keys test --provider anthropic 3xcode keys status
workspace: Manage Conversion Workspaces
Bare 3xcode workspace (no subcommand) runs workspace list.
| Command | Flags | Description |
|---|---|---|
3xcode workspace init [path] | positional `path` (default `.`), `--name/-n` | Initializes a new workspace in an empty directory (creates `input/`, `output/`, `.sessions/`, `logs/`) and sets it as active. |
3xcode workspace set [path] | positional `path` (default `.`) | Activates the workspace at the given directory path. |
3xcode workspace status | none | Table: path, version, created, default model/effort, session count, input/output file counts, last session ID, last accessed. |
3xcode workspace list | none | Table of all registered workspaces, marking the active one with ●. Also the default action of bare `workspace`. |
3xcode workspace prune | none | Removes stale registry entries whose path no longer exists or no longer contains a workspace config file. |
3xcode workspace delete <path> | positional `path`, `--yes/-y` | Deletes workspace metadata (`.sessions/`, `.locks/`, `logs/`); input/output files are preserved. |
3xcode workspace switch [path] | positional `path` (interactive picker if omitted) | Switches to a different registered workspace; auto-selects if exactly one is registered. |
3xcode workspace init ./my-migration --name "my-migration" 3xcode workspace list 3xcode workspace status 3xcode workspace switch ./my-migration 3xcode workspace prune
session: Manage Conversion Sessions
Bare 3xcode session runs session list. A session is a container for a body of migration work, single files, or one or more batches, and is resumable if interrupted. See Sessions & Batches for how sessions and batches relate. session status, cancel, delete, and rename all resolve the session ID across every registered workspace, not just the active one.
| Command | Flags | Description |
|---|---|---|
3xcode session create | --name/-n, --dir/-d (interactive picker if omitted), --model (optional model-tier override) | Creates a new session, optionally for a directory of SQL files. Requires an active workspace. |
3xcode session list | none | Table of sessions: ID, name, state (created/in_progress/completed/partially_completed/cancelled), file counts, cost, created date. Default action of bare `session`. |
3xcode session info <id> | positional `session_id` | Session summary (name, state, model, file counts, cost, duration, success rate) plus a per-file status table. |
3xcode session resume <id> | positional `session_id`, `--model`, `--verbose/-v` | Resumes an interrupted or partially-completed session. |
3xcode session status <id> | positional `session_id`, `--watch/-w`, `--verbose/-v` | Status table with counts by file status, worker PID/phase/current file/heartbeat if running, per-phase durations, and an ETA estimate. `--watch` tails live events (Ctrl-C to stop). |
3xcode session pause <id> | positional `session_id`, `--force/-f` | Pauses a running session. |
3xcode session cancel <id> | positional `session_id`, `--force/-f` | Signals a running worker to stop cleanly; already-completed files stay completed. No-op if no worker is running. |
3xcode session rename <id> <new_name> | positional `session_id`, `new_name` | Renames a session (does not change its ID). |
3xcode session delete <id> | positional `session_id`, `--force/-f` | Deletes a session's input/output/log files. Refuses if a worker is currently running; cancel first. |
3xcode session list-all | none | Table of currently-running sessions across all workspaces (ID, workspace, PID, phase, current file, model). |
3xcode session create --dir ./sql/ --name "batch-1" 3xcode session list 3xcode session status session-20260321-batch-1 --watch 3xcode session resume session-20260321-batch-1 3xcode session cancel session-20260321-batch-1 3xcode session list-all
batch: Manage Batches Within a Session
A batch is a named group of SQL files converted together inside a session, with its own worker pool and report. See Batch Conversion & Sessions for the full lifecycle, reports, and metrics.
| Command | Flags | Description |
|---|---|---|
3xcode batch create <session_id> | --name/-n, --dir/-d, --sort (default simple-first), --workers/-w (default 0) | Creates a new, open (unsealed) batch inside a session, optionally adding files from a directory immediately. |
3xcode batch add <session_id> <batch_id> | --dir/-d (required) | Adds every `.sql` file in a directory to an open batch. Refuses once the batch is sealed. |
3xcode batch list <session_id> | none | Table of every batch in a session, with state and file counts. |
3xcode batch seal <session_id> <batch_id> | none | Freezes the batch's file membership so it can be run. Idempotent once sealed. |
3xcode batch run <session_id> <batch_id> | --model, --workers/-w (default 0), --dry-run, --skip-validation, --skip-audit | Runs a sealed batch as a detached background worker; returns immediately. Refuses if a runner is already live for this batch, and refuses an unsealed batch. Also resumes a batch left running by a crashed worker. |
3xcode batch watch <session_id> [batch_id] | --tail (default 20) | Live dashboard for one batch, or every batch in the session if `batch_id` is omitted. Falls back to the last N events if nothing is currently running. |
3xcode batch pause <session_id> <batch_id> | --force/-f | Pauses a running batch; its quota hold stays alive while paused. |
3xcode batch resume <session_id> <batch_id> | none | Resumes a paused batch on the same run. If its pause window has expired, use `batch run` instead. |
3xcode batch cancel <session_id> <batch_id> | --force/-f | Cancels a running batch. |
3xcode batch schedule <session_id> <batch_id> | --at, --in, --model, --workers/-w, --dry-run, --skip-validation, --skip-audit | Schedules a sealed batch to run later as an in-app, one-off wake-up. See Scheduled Conversions. |
3xcode batch schedule-cancel <session_id> <batch_id> | none | Cancels a scheduled batch, returning it to sealed. Idempotent. |
3xcode batch create session-abc --name "phase-1" --dir ./sql/views/ 3xcode batch seal session-abc batch-phase-1 3xcode batch run session-abc batch-phase-1 --workers 4 3xcode batch watch session-abc batch-phase-1 3xcode batch schedule session-abc batch-phase-1 --in +2h
schedule: Durable, Reboot-Surviving Schedules
A separate group from batch schedule: these commands manage durable schedules backed by a real OS-level mechanism (launchd on macOS, cron on Linux, Task Scheduler on Windows), so they survive a reboot and can repeat. See Scheduled Conversions for how the two scheduling mechanisms compare.
| Command | Flags | Description |
|---|---|---|
3xcode schedule install | none | Registers the recurring, once-a-minute OS tick that dispatches due schedules. |
3xcode schedule uninstall | none | Removes the OS tick this CLI installed (only its own entry). |
3xcode schedule add <session_id> <batch_id> | --at, --in, --repeat, --model, --workers/-w, --dry-run, --skip-validation, --skip-audit | Adds a durable schedule for a sealed batch. `--repeat` accepts `hourly`, `daily`, or `every N unit` (`s`/`m`/`h`/`d`). |
3xcode schedule list | --session (filter) | Lists durable schedules, optionally filtered to one session. |
3xcode schedule remove <schedule_id> | positional `schedule_id` (integer) | Cancels a durable schedule by ID. Idempotent. |
3xcode schedule status | none | Whether the OS tick is installed, how many schedules are pending, and when the next one fires. |
3xcode schedule run-due | none | Dispatches every currently-due schedule immediately. This is what the installed tick calls every minute. |
3xcode schedule daemon | --interval (default 60.0 seconds) | A fallback that loops `run-due` while the command itself stays running, for environments where installing an OS-level tick isn't possible. |
3xcode schedule install 3xcode schedule add session-abc batch-phase-1 --at 2026-07-17T02:00 --repeat daily 3xcode schedule status 3xcode schedule list 3xcode schedule remove 14
org: Create or Join an Organization
Bare 3xcode org runs org me. Organizations share licensing and visibility with teammates: individual per-account licenses remain the default, and an org can additionally get an admin-provisioned shared license (resolution is org-first, individual-fallback). Organization-shared licenses are exempt from the per-machine cap.
| Command | Flags | Description |
|---|---|---|
3xcode org create | --name (prompted if omitted) | Creates and joins a new organization; prints a shareable join code. |
3xcode org join <code> | positional `code` | Joins an organization using a code shared by a teammate. |
3xcode org me | none | Shows your org (name, code, role, member/seat count, shared-license status, usage mode: per-seat vs shared pool). Default action of bare `org`. |
3xcode org create --name "Acme Data Team" 3xcode org join ABCD-1234 3xcode org me
pyspark: SQL-to-PySpark Conversion
The conversion agent, mounted as its own sub-app. Both commands require an active workspace and a valid login/license. analyze also makes LLM calls, so it is not a free or local operation. Internally these run the 5-phase pipeline (discovery, planning, conversion, validation, auto-fix).
| Command | Flags | Description |
|---|---|---|
3xcode pyspark convert [file] | input_path (positional, interactive picker if omitted) | Convert a single SQL file to PySpark. |
--dir | Convert every `.sql` file in a directory (bulk mode), creating and running an implicit batch. | |
--model | Optional model-tier override (an interactive picker shows the available tiers). | |
--verbose/-v | Show streaming output and tool calls. | |
--dry-run | Discovery + planning only: no conversion. | |
--skip-validation | Skip the validation phase. | |
--skip-audit | Skip the auto-fix phase. | |
--phases | Run specific phases only: comma-separated `analyze,convert,validate,audit`. | |
--workers/-w (default 0) | Ceiling for adaptive parallel workers during bulk conversion; `0` lets it auto-tune up to the built-in default. | |
--schedule (default simple-first) | Bulk scheduling order: `simple-first` or `complex-first`. | |
--session | Session name for bulk conversion tracking/resume. | |
--resume | Resume an interrupted session by ID (short-circuits straight to resume logic). | |
--detach/-d | Run as a detached background worker that survives CLI exit; prints the session ID immediately. Capped at 3 concurrent detached workers per machine. | |
3xcode pyspark analyze <file> | positional `input_path` (required) | Runs discovery + planning only (dry run) and reports the object inventory without converting. |
--output/-o | Output directory (default: configured output dir). | |
--model | Optional model-tier override (an interactive picker shows the available tiers). | |
--verbose/-v | Verbose output. |
3xcode pyspark convert your_file.sql 3xcode pyspark convert --dir ./sql/ --session "my-migration" -w 4 3xcode pyspark convert --dir ./sql/ --schedule complex-first --session "batch-1" --detach 3xcode pyspark convert --resume session-20260321-batch-1 3xcode pyspark analyze your_file.sql
Note on 3xcode convert: a bare, top-level 3xcode convert alias exists for backward compatibility with the old convert-sql entry point, but 3xcode pyspark convert is the documented, current entry point for SQL-to-PySpark conversion; use it going forward.
Environment Variables
| Variable | Purpose |
|---|---|
THREEXCODE_DISABLE_UPDATE_CHECK | Set to disable the background update-check notice entirely. See Installation & Updates. |
BYOK provider credentials are also resolved through environment variables once you run keys store, but those are set for you rather than configured by hand. See Multi-Provider & BYOK.
Exit Codes
3xcode doesn't define a large table of specific exit codes. Treat 0 as success and any non-zero code as failure, and read the printed error message (or check session/batch state) for the specific cause.
| Exit code | Meaning |
|---|---|
0 | Success, including an intentional early exit like declining 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 |
Cross-Cutting Notes
Default subcommands
Bare workspace → workspace list. Bare session → session list. Bare org → org me. config, keys, batch, and schedule have no default action.
Auth + workspace required
pyspark convert, pyspark analyze, and every batch/session command that touches conversion require an active workspace and a valid login/license before any LLM call is made.
Cross-workspace session lookup
session status, cancel, delete, and rename resolve the session ID across all registered workspaces, not just the active one.
Detached worker cap
pyspark convert --detach and batch run (always detached) share a hard cap of 3 simultaneously-running detached workers per machine, regardless of workspace.
Adaptive workers under a ceiling
-w / --workers sets a ceiling, not a fixed count. Actual parallelism auto-tunes underneath it based on how the run is going. See Sessions & Batches.
Two scheduling mechanisms
batch schedule is a one-off, in-app wake-up; the schedule group is durable and survives a reboot. See Scheduled Conversions.
BYOK gating
keys store and keys test both check with the backend that BYOK is enabled for your account before proceeding. Keys themselves are always stored only locally, never sent to the backend.
Session cache
Auth/license/provider-config results are cached client-side for 5 minutes to avoid repeated backend round-trips on successive commands; logout invalidates the cache.