CLI reference. Every command and flag.
This is what karts prints when you run it with no arguments:
karts: run this branch in a fresh micro-VM with its own database and a URL.
karts login sign in (device code; works over SSH)
karts logout revoke this device's token
karts whoami who you are signed in as
karts init link this repository to a project (writes project: into karts.yml)
karts onboard [-o FILE] the prompt that lets your coding agent write karts.yml
karts check-config check karts.yml and the upload locally, as the host would
--output text|json json: one object for agents and CI
karts up build this branch and serve it
--new a second environment for this branch
--commit [ref] upload a commit's tree instead of the working tree (default HEAD)
--branch NAME the branch name (needed with a detached HEAD)
--workspace ID the workspace id (default: this clone's)
--base REF the base commit's ref (default: origin/<default branch>)
--reseed run this branch's seed after its migrations
--from-scratch empty database, all of this branch's migrations, its seed
--allow-destructive apply migrations that drop or rewrite data
--snapshot FILE seed the template from a masked snapshot (default: karts.yml seed_snapshot:)
--no-snapshot ignore seed_snapshot:
--timings print how long each step took
--output text|json|url json: one object for CI (--json is the same); url: only the URL
karts fork [NAME] a new environment copied from a running one, memory and all
--name N the fork's name (default: the branch's slug and 4 hex)
--restart-app restart the fork's app with its own URLs (Postgres keeps running)
--output text|json|url as karts up; --timings as karts up
karts down [NAME] tear the environment down (--output json for CI)
karts status [NAME] the environment, its revisions and warnings
karts url [NAME] the public URL of a serving environment (--output json for CI)
karts list [--branch B] this project's environments (--output json for CI)
karts logs [NAME] [--follow] [--building|--failed|--revision N] [--tail N]
--template the build log of the revision's database template (its seed's output)
karts exec [NAME] [-i] [--building|--failed|--revision N] -- CMD...
-i, --stdin send local stdin to CMD (without it, CMD gets an empty stdin)
karts fakes calls [NAME] what the app sent to karts.yml fakes: and stubs: (and unmatched hosts)
--fake F, -f, --output json one fake's calls; keep following; one JSON call per line
karts egress log [NAME] [-f] what karts.yml internet: let the app reach, and what it refused
--since 24h, --output json from when (90m, 7d, a date); kept up to 30 days, gone envs too
karts egress off|on [--team T] the team's internet kill switch (owners)
karts egress approvals production approvals (karts egress help: allow-production)
karts recordings list|rm|promote the project's recorded calls (karts.yml recordings:; karts recordings help)
karts claims [release] migration-number claims in this project
karts secret set|list|rm|import values the app needs that stay out of karts.yml (karts secret help)
karts db snapshot [--check] a masked copy of real data, made here (karts db snapshot help)
karts project delete [PROJECT] delete a project (owners only): its claims, uploads and templates
--down-all take its environments down first (refused otherwise)
--yes do not ask to type the project name
karts webhook send [ENV] stripe TYPE a signed Stripe event from the fake, to the app (--local)
karts webhook send [ENV] --url /PATH any provider's webhook, --sign github|slack (karts webhook help)
karts report [FILE] [--yes] send the Karts team a problem report (shows it, then asks)
karts mcp the same commands as MCP tools on stdio
karts version [--capabilities] the version, commit and build date; or the karts.yml keys
Local mode: this branch on this machine, its own database and a *.localhost URL; no account,
no upload (macOS; Postgres in Docker).
karts up --local build this branch here and print its URL
--new, --branch, --base, --snapshot FILE, --no-snapshot, --output text|json|url, --timings as above
--reinstall run install: even when its inputs are unchanged
--pass-unmatched outside calls no karts.yml fake or stub answers reach the internet
--allow-destructive apply migrations that drop or rewrite data
--keep-db keep this environment's database (the default on a repeat up) or fail
--fresh-db rebuild it from scratch instead
--reuse-template with seed: or migrate:, clone the base's template when nothing
Karts can see changed (those steps may read what it cannot see)
karts exec --local [NAME] [--service S] -- CMD... run CMD here with the environment's variables
karts psql --local [NAME] [-- ARGS] psql into its database
karts list --local local environments and their URLs
karts logs --local [NAME] [-f] [--tail N] [--service S] [--build]
karts fakes calls --local [NAME] [--fake F] [-f] [--output json]
karts egress log --local [NAME] [-f] [--since 24h] [--output json]
karts status --local [NAME] an environment (or the daemon and every environment)
karts down --local [NAME|--all [--yes]] stop it, drop its database and role, free its ports
karts check-config --local also report what local mode does not support
karts local serve|stop the per-user daemon (started on demand)
karts local uninstall [--yes] remove everything this install made, after listing it; the shared
--all-installs Postgres container and volume too, when other installs use them
Environment: KARTS_API (control API URL), KARTS_TOKEN (token; overrides the stored one),
KARTS_TOKEN_STORE=file (keep the token in a 0600 file, never the OS keychain).
karts login, logout, whoami
karts login signs in with a device code: the CLI prints a code and a link, and you approve it in a browser. The token is stored in the macOS Keychain or the Linux Secret Service where available. karts logout revokes this device's token on the server. karts whoami shows who you are signed in as, your teams and when the token expires.
karts init
Links the repository to a project in your team and writes project: into karts.yml, creating a starter karts.yml if there is none. Run it once per repository and commit the file.
karts onboard
Prints the onboarding prompt: instructions any coding agent follows to explore the repository, write karts.yml, check it, run karts up, fix failures, and report what Karts runs every time. -o FILE writes it to a file instead (--force overwrites). The same prompt is at /onboard.md; the CLI's copy matches its own version. No sign-in needed.
karts check-config
Checks karts.yml and the files karts up would upload, locally and offline, with the Karts host's own parser and migration rules: indentation, keys, reserved variables, services: references, the upload limits, the migrations directory (including git-ignored migration files), service directories, and heuristics for credentials in karts.yml and credential files that would be uploaded. It warns about downloads the VM cannot make (hosts outside the package registries), about a start bound to 127.0.0.1, and when the default branch has no karts.yml yet. It then lists what this karts.yml runs. --output json prints one object for agents and CI. Exit status 0 means no errors. It covers this tree only: karts up still checks migrations against the default branch, destructive SQL, the runtime image and links, and runs your commands. The secret checks are heuristics, not proof.
karts up
Builds the current branch and serves it. The first run on a branch creates its environment; each later run builds a new revision beside the current one and switches to it when it is ready. If the new revision fails, the old one keeps serving.
| Flag | Use it when |
|---|---|
--new | You want a second environment for the same branch, beside the first. |
--commit [ref] | You want an exact snapshot: upload a commit's tree instead of the working tree. Use it in CI. |
--branch NAME | The checkout has a detached HEAD, as in CI. The name is also what migration claims use. |
--workspace ID | You want repeated CI runs to update one environment. |
--base REF | The template should come from another ref than usual: origin/<default branch>, or the base: branch when karts.yml sets one. |
--reseed | Your branch changes the seed and you want it run on top of the template. |
--from-scratch | Your branch edits or removes a migration main already ran. Builds an empty database, then all of the branch's migrations, then its seed. |
--allow-destructive | You mean to drop or rewrite data. The statements are printed. |
--snapshot FILE | The template should load a masked copy of real data instead of running seed. Without it, seed_snapshot: in karts.yml is used. See karts db snapshot. |
--no-snapshot | You want the plain seed, ignoring seed_snapshot:. |
--timings | You want the time each step took. |
--output json | A script or agent is reading the result: one JSON object on stdout (--json is the same). See the fields. |
--output url | You want only the URL, for example in CI. Exits 1, with the reason on stderr, if the environment did not become ready. |
karts fork
Copies a running environment into a new one, with its memory and its data: what the app holds in memory and every row written so far. The source pauses for about 0.1 s while it is copied (66 to 134 ms in our runs, median 82 ms). The first fork of a new revision pauses it longer. After that, each side's changes stay its own.
With no name it forks this branch's environment. --name N names the fork. --restart-app restarts the fork's app so it uses its own URLs; the app's in-memory state is lost, and the database keeps running. --output and --timings work as in karts up. Forking is hosted only.
karts down
Tears the environment down: its VM and database are destroyed. The branch's migration-number claims are kept. Environments it linked to keep running, and the CLI names them. --output json prints {schema_version, env, name, state: "gone"}.
karts status, url, list
With no name, status, url, logs, exec and down act on this branch's environment in this clone; --branch and --workspace pick another, as in CI.
karts statusprints the environment's state, URL, revisions, warnings and links.karts urlprints the public URL of a serving environment and exits 0, or exits 1 when none serves.--output jsonadds its name, state and key.karts listlists every environment of this project, with its branch, state and URL.--branch Bnarrows it to one branch.
karts logs, exec
logs and exec use the serving revision; --building, --failed or --revision N pick another. logs --follow streams; --tail N shows the last lines.
exec runs a command inside the VM with DATABASE_URL set. Its stdin is empty unless you pass -i (--stdin), which sends your local stdin, up to 1 MiB: karts exec -i -- psql < dump.sql. Without -i, karts exec never waits for your stdin, so it does not hang in an agent's shell. It has no terminal: interactive prompts do not work.
karts fakes calls
karts fakes calls [NAME] [--fake F] [-f] [--output json] [--local]
Lists what your app sent to its fakes and stubs, oldest first: the time, the fake, the request and the answer. Calls to hosts nothing answers are listed as unmatched. Keys, passwords, cookies and card numbers are removed before a call is stored.
--fake Fshows one fake's calls, for examplestripe,stuborunmatched.-f(--follow) keeps printing new calls.--output jsonprints one call per line.- It reads the serving revision, like
karts logs;--building,--failedand--revision Npick another.--localreads a local environment.
karts egress
karts egress log [NAME] [-f] [--since 24h] [--branch B] [--output json] [--local] karts egress off|on [--team T] karts egress approvals karts egress allow-production PROVIDER [--for 7d] [--remove]
Shows and controls what internet: lets your app reach.
loglists each outside connection and refusal: the time, host, port, result and bytes each way, never what was sent. Records are kept for up to 30 days, also for environments that are gone: name one by its old name.--sincetakes90m,24h(the default),7dor a date.-fkeeps printing.--output jsonprints every record.--localreads this machine's records.offturns the team's internet off on every Karts host: new connections are refused and open ones close.onturns it back on. Team owners only.allow-productionlets branches whosekarts.ymlhasallow_production: [PROVIDER]reach that provider's production hosts, or, forstripe, use live keys. Team owners only. It lasts 7 days, or what--forsays, from1hto30d.--removerevokes it at once.approvalslists the project's approvals and the team's switch.
karts recordings
karts recordings list [--branch B] [--host H] [--output text|json] karts recordings rm [--branch B] [--host H] [--key K] karts recordings promote --branch B
Manages the project's recorded calls on its Karts host. list shows them without their bodies. rm deletes the ones that match its flags, and needs at least one. promote makes a branch's recordings the default branch's, so every branch can replay them.
karts webhook send
karts webhook send [ENV] stripe EVENT-TYPE [--id OBJ] [--data FILE.json] --local
karts webhook send [ENV] --url /PATH [--body FILE|-] [--header 'K: V']... [--method POST]
[--sign github|slack --secret-env VAR] [--local]
Sends your app a fake webhook, signed the way the real service signs it, so you can test the code that receives it.
- Stripe: the environment's fake Stripe sends an event of that type, such as
checkout.session.completed, about its latest object of that kind (or--id), to yourwebhook_path.--datachanges fields of the object. This works with--localonly for now; in the cloud the fake Stripe still sends its own webhooks as payments happen. - Any other service:
--urlposts the body to that path on the environment's own URL, in the cloud or locally.--sign githubor--sign slacksigns it as GitHub or Slack does, with the secret in the variable--secret-envnames. The secret is never printed. - It exits 0 only when your app answered with a 2xx.
karts claims
Lists the migration numbers main has, the numbers other branches have claimed, and the next free number. karts claims release gives up your branch's claims, for example when you abandon it.
karts secret
karts secret set NAME [--project | --branch B | --env E] [--local] karts secret list [--local] [--output json] karts secret rm NAME [--project | --branch B | --env E] [--local] karts secret import FILE [--project | --branch B | --env E] [--yes] [--local]
Stores values your app needs that must not be in karts.yml or the repository. set reads the value from stdin, or asks for it without showing it. list shows names, scopes and times, never values. import reads a .env file, lists the names and asks first.
A value is for the whole project (the default), one branch or one environment; the most specific wins. --local keeps it on this machine for karts up --local. The app gets only the names listed in secrets:, and a change reaches an environment at its next karts up. Logs show ‹secret› in place of a value.
karts db snapshot
karts db snapshot [--from URL] [--out FILE] [--check] [--salt-file FILE] [--allow-kept-pii] karts db snapshot ls karts db snapshot push FILE karts db snapshot rm FILE|SHA
Makes a masked copy of real data, on this machine. It reads the Postgres database at --from (or KARTS_SNAPSHOT_FROM; a replica is best) in one read-only transaction, replaces personal data with fakes, keeps the links between tables, and writes a file. The raw data never leaves your machine.
--checkprints the plan and the decision for every column, and writes nothing.--salt-file FILEkeeps masked values the same across snapshots. The file must be outside the repository.--allow-kept-piiallows columns you markedkeep_pii.lslists the snapshots here and on the project's host.pushuploads one;karts updoes that for you when it needs one. Only the masked file is uploaded, and it is stored encrypted.rmdeletes one here and on the host, with the templates built from it.
The rules live under masking: in karts.yml. Branches use the file through seed_snapshot: or karts up --snapshot FILE.
karts project delete
Deletes a project: its migration-number claims, uploads and template databases, and frees one of your team's project places. Only a team owner can delete a project. It prints the project's name, team and environments, and asks you to type the name; --yes skips that. A project that still has environments is refused unless you pass --down-all, which takes them down first. With no argument it deletes the project named in karts.yml; the file itself is not changed.
karts report
Sends the Karts team a plain-text report when Karts itself fails. It reads FILE, or the report on stdin, adds the CLI's version and OS, and shows you exactly what it will send before it asks. Keys and passwords it can spot are removed, on your machine and again before the report is stored. --dry-run shows it and sends nothing. --yes sends without asking, once you have said yes. An agent without the CLI can send the same plain text to https://api.karts.kartikey.fyi/report; opening that address says what to include.
karts mcp
Runs an MCP server on stdio with the tools up, down, status, logs, exec and check_config. See MCP setup.
karts version
Prints the CLI's version, the commit it was built from and the build date. karts version --capabilities prints instead the karts.yml keys, service keys and features this CLI accepts, one line each.
Local mode
karts up --local runs this branch on your own Mac with the same karts.yml. No account, and nothing is uploaded. Each branch gets its own database and its own *.localhost URL. You need Docker Desktop running: Karts keeps Postgres (and MySQL) in its own containers, named karts-local-…, and never touches yours. SQLite needs no container. Apple Silicon Macs are tested.
karts check-config --local # also says what local mode does not support karts up --local # build this branch here and print its URL karts list --local # local environments and their URLs karts status --local # one environment, or the daemon and all of them karts logs --local -f # the app's output karts exec --local -- CMD # run CMD here with the environment's variables karts psql --local # psql into its database karts down --local # stop it, drop its database, free its ports
- Each branch's URL stays the same:
http://<branch>.<project>.localhost:7400.KARTS_URL,${services.<name>.url}, links, the mail inbox and the fakes' sign-in pages all use that one host, so cookies and sign-in callbacks meet. The longer hashed name an environment also has still answers; a browser that opens it is sent to the short one. - If port 7400 is taken the first time local mode starts, and
KARTS_LOCAL_PORTis not set, Karts takes the next free port, keeps it, and everykarts up --localsays so. Later starts use the kept port; if something else holds it then, the daemon does not start and names what holds it. WithKARTS_LOCAL_PORT=N, Karts uses exactly port N and refuses to start if N is taken. To choose the port:karts local stop --apps, thenKARTS_LOCAL_PORT=7400 karts up --local(andkarts up --localagain in each other environment). Karts moves the port only while no environment runs. karts up --localchecks free disk space first, on the disks that hold the worktree and Karts' local files. Below 2 GB it refuses before it stops or builds anything. Below 8 GB it warns. An install and a build can take several GB, and when a Mac's disk fills, Docker Desktop stops its VM and every container on the machine stops with it, Karts' Postgres included. A failure caused by a full disk saysthe disk is fullfirst. The variables below change both limits.karts up --localtakes--new,--branch,--base,--snapshot FILE,--no-snapshot,--output,--timingsand--allow-destructive, as hosted.- A repeat
karts up --localkeeps the database. Rows you made by hand stay, only new migrations run, and the seed does not run again. If the database can't be kept (an applied migration was edited, or the database settings changed), it is rebuilt andupsays why.--keep-dbfails instead of rebuilding.--fresh-dbalways rebuilds. Postgres only: MySQL and SQLite are rebuilt each time. --link NAME=BRANCHpoints alinks:entry at another branch, or environment, of the linked project. Repeat it for more links.--pass-unmatchedlets outside calls that no fake or stub answers through to the real internet. Without it they are caught. Production hosts, ports 25 and 53, IP addresses and live keys stay refused, as withinternet:.installruns again only when what it reads changes: the lockfiles, anypackage.json, patches, Prisma schemas,.npmrc,.env, or the Node and package manager on yourPATH. Editing your code or adding a migration does not re-run it, even with aprepareorpostinstallscript: husky only installs git hooks. A script that generates code from your source files belongs in a servicebuild:, which runs on everyup. Aninstallthat does more than the package manager's install (npm ci && npm run build) runs every time.--reinstallruns it anyway.- With
seed:ormigrate:, anupthat has no database to keep builds it from scratch: those steps may read files Karts cannot see.--reuse-templateclones the base's template instead when nothing Karts can see changed. It is faster, and you take on what Karts cannot see. - Your machine's own Node and package managers run the app. Use the versions the repository pins.
- Not in local mode:
redis:,storage:,karts fork,--reseedand--from-scratch. karts exec --local -- CMDruns a command on your machine, in the environment's folder, with the variables itsstartgets:DATABASE_URL,PORT, the fakes' keys and proxy, and the rest. Your shell's own variables are kept, but every name Karts sets replaces the shell's value.--service Spicks a service. It can read your terminal, so interactive tools work.karts psql --localopenspsqlon the environment's Postgres database; arguments after--go topsql. Withoutpsqlon your machine, it uses the one in Karts' Postgres container. In the cloud, usekarts exec -i -- psql.- Two branches at once: one git worktree per branch, and
karts up --localin each. karts down --local --allstops every local environment.karts local serveandkarts local stopstart and stop the background daemon, whichkarts up --localstarts when it needs it.
karts local uninstall
Removes everything this install of local mode made: every local environment with its database, the background daemon, and Karts' local files. It lists them first and asks; --yes skips the question. Karts' Postgres container and its volume go too, unless another install of Karts on this machine still keeps databases in them; --all-installs removes them anyway.
Environment variables
| Variable | Effect |
|---|---|
KARTS_TOKEN | The token to use. Overrides the stored one. For CI and agents. |
KARTS_API | The control API URL. You don't need to set it. |
KARTS_LOCAL_PORT | Local mode's port (default 7400). Read when the background daemon starts, and kept for later starts. Karts uses exactly this port: if it is taken, the daemon does not start. Without it, a first start takes the next free port after 7400 and says so. |
KARTS_LOCAL_MIN_FREE_GB | The free disk space, in GB, below which karts up --local refuses to start (default 2). 0 turns the check off. Read from the shell at each up. |
KARTS_LOCAL_WARN_FREE_GB | The free disk space, in GB, below which karts up --local warns (default 8). 0 turns the warning off. Read from the shell at each up. |