Kater CLI
kater works the way dbt does: a project file, a profile with targets, --select and --exclude, one line as each object starts and ends, target/run_results.json, and dbt's exit codes. Every warehouse call goes through your Kater API, which signs in with the organisation's stored credential, so your computer never holds one (ADR 0042, ADR 0043).
Quick start
1. Install
On macOS or Linux:
curl -fsSL https://landing.kater.ai/install.sh | sh
The script installs uv, Python 3.14 and the kater-cli package from PyPI in ~/.kater, links kater in ~/.local/bin, and puts that folder on your PATH in your shell's profile when it is not there. With Python 3.14 on your computer, uv tool install --python 3.14 kater-cli installs the same package.
In a checkout of the Kater repository, from its root:
uv sync --package kater-cli
uv run --package kater-cli kater --version
The Release publishes kater-cli to PyPI as one wheel, which carries each workspace project it needs, when prod runs the same commit (scripts/build_cli_packages.py). PyPI has only the project kater-cli.
kater --help lists the commands you use each day. kater help --all lists every other command.
2. Set up with kater init
An admin who sets up a new organisation runs kater init. It signs you in, connects the warehouse, syncs its tables, runs a first query, and writes a profile with a target, step by step (see Onboarding below).
To work in an organisation that is already set up, sign in and make a local copy of its content:
kater login
kater git clone kater
cd kater
The local copy holds kater_project.yml, which marks a project and names its profile. The profile is in ~/.kater/profiles.yml (see Configuration below). A Kater engineer runs pnpm dev:setup, which writes both for the local stack.
3. Check the setup with kater debug
kater debug
15:19:40 Running with kater=0.1.0, profile=kater, target=dev (Kater API at http://127.0.0.1:8788)
15:19:40 Profile kater in ~/.kater/profiles.yml, target dev (Kater API at http://127.0.0.1:8788) ... [OK]
15:19:40 Project kater_project.yml at ~/kater ...................................... [OK]
15:19:41 Kater API 0.1.0 at http://127.0.0.1:8788 .................................. [OK]
15:19:41 Signed in as yvonne@kater.ai .............................................. [OK]
15:19:43 Warehouse snowflake_prod_connection (select 1) ............................ [OK]
15:19:43 All checks passed!
Each line that is not [OK] says what to do next. kater debug exits 1 when a check fails.
4. Build with kater build
kater build --select +connections/snowflake_prod_connection/workspaces/ad_reporting/query_contracts/spend_by_platform.sql
It compiles, runs and tests what you select and everything it reads, in the graph's order, as dbt build does: a model, a query, then each test of the model. What reads an object that failed is SKIP. It ends with Done. PASS=… WARN=… ERROR=… SKIP=… TOTAL=… and writes target/run_results.json. kater retry runs again only what failed or was skipped.
The commands you use each day
| Command | What it does |
|---|---|
kater init, kater debug, kater login, kater logout |
Set up, check the setup, sign in and out. |
kater build, kater run, kater compile, kater test, kater retry |
Build, run, compile or test what --select selects, and run again what failed. |
kater show --select ONE --limit N |
Show a model's first rows, as dbt show does. |
kater ls --select …, kater parse |
List what a selection selects, one TYPE.NAME a line, and write target/manifest.json. |
kater new KIND |
Make a workspace, query, chart, app, field, test or model. |
kater compare, kater sync |
Compare two queries or an app's figures for two weeks, and update the datasets from the warehouse. |
kater git, kater admin |
Work on your local copy, and administer members, access and connections. |
Every command that works on objects selects them with dbt's grammar: --select "one.sql two.sql", --select tag:team=finance,resource_type:query, --select +semantic.example, and --exclude to leave nodes out. A term that matches nothing prints a warning with the nearest name ("Warning: --select spend_by_platfrom matches no object. Did you mean spend_by_platform?"), as dbt warns, and --warn-error turns it into exit 1. The --help of each command of every day ends with examples. Other collection options take one value for each flag: --sources one --sources two. Common options (--json, --kater-root, --scope, --target) may come before the command or after it.
Three workflows, step by step with recordings, are in the docs: check a query (debug, ls, show), change a query and build it (state:modified+, build, retry, kater git push) and test a shared model (test list, test, --update, new test --record). apps/landing-page/scripts/docs/recordings/record.mjs records them again from real commands.
How a command prints
While a command works, it prints its progress on stdout as events with the time, as dbt does (kater_cli.events). A wait says what it waits for after 1 s and again every 10 s, and has a limit (kater_cli.waiting); reading a large project before the first object is one too ("Waiting for Kater to read the project. 1s"). --json leaves only the answer on stdout, and --log-format json prints each event as one JSON line. Every event also goes to logs/kater.log at the content root, or ~/.kater/logs/kater.log outside one. An error prints what Kater could not do, the error's words, a Next: line, and the request ID with where the log is (kater_cli.failures). An unexpected error writes its record and traceback to the log only. With --json an error is the OperationError JSON on stderr.
Exit codes follow dbt: 0 for success, warnings included unless --warn-error; 1 when an object or an operation fails; 2 when the command cannot run (a bad flag, profile or project, a Kater API that does not answer, an unexpected error); 130 when you stop it. A step of kater new field that waits for input exits 0. Help and version do not open a service or resolve credentials.
The text is for people, and it changes freely. A program reads one of three contracts (ADR 0043): --json, one JSON document on stdout and the error JSON as the last stderr line; kater worker's JSON lines, which the VS Code extension sends its operations and command lines to; or kater serve's stdout. A program in its own process calls kater_cli.calls.run(words, service=...), which answers the result, the error, the exit code and the events as objects, or opens the operations with kater_cli.service.open_service(root). Structured request commands accept --request-file PATH; - reads stdin.
API login
Model commands still run locally, and a compile works offline. They act as the person who is signed in to the Kater API that the local copy names (ADR 0042). A permission check and a warehouse call go to that Kater API, and with no sign-in they stop with "Run kater login". This is separate from inbound PropelAuth protection on kater serve --mode remote.
kater login
kater auth status
kater logout
kater debug
The CLI keeps one token for each Kater API (ADR 0042). Every command, kater login and kater logout included, works on the Kater API of the profile's target (kater_cli.profiles, see Configuration below), and every target that names the same API shares its token. In a local copy, .git/kater.json must name the same API as the target. The target's auth_url, client_id, redirect_uri and site_url come first. Without them, the first time the CLI signs in to a Kater API, it gets the Auth URL and the client ID from that API's public GET /v1/sign-in-config (the API's PROPELAUTH_AUTH_URL and KATER_CLI_CLIENT_ID), accepts only an HTTPS Auth URL or a loopback one for a loopback API, and saves them for that API in sign-ins.json in the configuration directory. Kater's own API keeps the built-in values.
Find the Client ID in PropelAuth's Frontend Integration → Advanced Settings → Edit OAuth Config, in the same environment as the portal's Auth URL. Add the exact redirect URI http://127.0.0.1:8765/callback (override with the target's redirect_uri). These are the OAuth2 settings used by /propelauth/oauth/authorize, not the separate MCP OAuth Clients or Request Validation credentials. Login uses authorization code with S256 PKCE and state, a loopback-only callback with a three-minute wait, and no client secret. The API must accept that client's access tokens and expose authenticated GET /v1/me returning a nonempty user_id. Login saves credentials only after this check succeeds. The API origin defaults to Kater's production value (kater_cli.config: https://api.kater.ai, with https://auth.kater.ai and Kater's public client); the target's own values replace each one. See PropelAuth's OAuth2 configuration guide and PKCE token reference.
Credentials live only in an allowlisted OS keychain backend: macOS Keychain, Windows Credential Locker, Linux Secret Service or KWallet. The backend must actually be available/unlocked; headless Linux often has none. No plaintext or plugin fallback is permitted. Credentials are isolated by configuration directory, API origin, auth issuer and client ID. Logout deletes the selected target's saved credentials, retaining non-secret configuration and other targets' credentials; it does not revoke the provider session.
For automation, give the target a token, as "{{ env_var('KATER_CI_TOKEN') }}", and supply the variable through your environment/secret manager. This token overrides saved credentials, bypasses keychain access and refresh, and is never persisted. An invalid override fails rather than falling back to a saved login. Status verifies /v1/me, reports the target, user ID and credential source, and distinguishes authentication rejection from API unavailability. Logout cannot remove a profile token and reports when that override remains active (profile_token_override).
The reusable kater_cli.client.api_session() yields an authenticated client whose request(method, "/v1/...", TypeAdapter(...), body=...) validates API responses. Stored sessions refresh before expiry; a GET rejected with 401 may refresh and retry once. Mutations are never automatically replayed. Requests do not follow redirects or use ambient proxy settings. API origins require HTTPS except literal loopback development hosts; auth issuers always require HTTPS. Local runtime identity variables never grant API access.
Set up Slack
kater admin slack setup
kater admin slack setup --target prod --no-browser
kater admin slack setup --guide
setup uses your API sign-in and requires settings:manage. It names missing server settings and prints the operator's setup guide, exiting with status 1 until the server is configured. Once configured, it prints and opens the server's Slack tab. Install and Update permissions stay in the portal's browser-bound OAuth flow; the CLI never takes an OAuth state or installation cookie into another browser. --no-browser prints the page only. --guide prints the steps offline, without authentication or an API call. It works on the target's Kater API, and the portal's copyable agent prompt names its own API for kater debug to check.
Send an answer in Slack
kater send --to YOUR_KATER_EMAIL --answer RESULT_ID
kater send --to YOUR_KATER_EMAIL --path connections/CONNECTION/workspaces/WORKSPACE/query_contracts/QUERY.sql --note "Here are the figures."
Send accepts exactly one result id or saved query path. It uses your Kater API sign-in, and the Kater API runs a path fresh under your access. A standalone command sends only to yourself. An agent sends to another member through kater_apply, after approval. Kater checks the recipient's access before posting. A queued reply includes a job id; use kater invoke message.status --request-file PATH with {"job":"JOB_ID"} to read it before sending again. The sender can send 20 DMs in a rolling hour. See the Slack delivery guide.
Local copy and write-back
kater git keeps a local copy of Kater's content store: an ordinary git repository holding only what you can read (see ADR 0013). kater git clone [DIR] commits a snapshot onto the hidden refs/kater/upstream ref and checks out main at it; .git/kater.json records the API target and the store head the snapshot came from. kater git pull commits a new snapshot and runs a real git merge refs/kater/upstream, so conflicts are ordinary git conflicts. kater git push [-m MESSAGE] publishes the committed diff refs/kater/upstream..HEAD as one all-or-nothing change, each file carrying its snapshot blob as the expected revision; uncommitted changes are never published, and a push refuses during an unfinished merge. If anything changed in Kater meanwhile, nothing is published: the command pulls, you resolve and commit, and you push again. A successful push records the pushed tree as the new snapshot. A pull deletes a file only when an earlier snapshot sent it and the new one does not; Kater never names a file that you cannot read. A copy that pnpm dev:setup recorded ("imported": true in .git/kater.json) starts from the store's whole tree, so its first pull lists in .git/kater-withheld each file that Kater does not send, keeps those files as your branch has them on every pull, and a push leaves out each change to them and says how many. Every other subcommand, such as kater git status or kater git log --oneline, runs git unchanged.
kater git clone kater
cd kater && kater git pull
git commit -am "Rename revenue measure" && kater git push
kater admin write-back status|connect|disconnect|run manages the optional, admin-only write-back of the shared layer to a GitHub repository, as one pull request into main. connect authorizes Kater's GitHub App in your browser, then asks for the installation, repository, folder (default kater/) and schedule (after each publish, or a UTC cron expression); --installation-id, --repository-id, --path-prefix, --schedule and --cron answer those questions up front. kater init offers the same flow as its last, optional step, and kater init --reset clears onboarding progress at any time.
Connect a warehouse
With a Kater API configured, kater admin connection create sends a Snowflake connection to POST /v1/connections, which tests the sign-in, stores the credential (ADR 0009) and commits connection.yaml to the content store. Then run kater git pull in your local copy. Without a Kater API, the command stops and says to run kater login. The CLI does not make a DuckDB connection. --dry-run prints connection.yaml and saves nothing.
kater admin connection create snowflake_prod --account myorg-myaccount --warehouse COMPUTE_WH --user KATER --private-key-file ~/.ssh/kater_key.p8 --schema ANALYTICS.PUBLIC
kater admin connection create snowflake_prod --account myorg-myaccount --warehouse COMPUTE_WH --user KATER --private-key-file ~/.ssh/kater_key.p8 --passphrase --schema ANALYTICS.PUBLIC
kater admin connection create snowflake_prod --account myorg-myaccount --warehouse COMPUTE_WH --user KATER --password --prompt --schema ANALYTICS.PUBLIC
The secret is never a flag's value or an environment variable, so an agent that runs the command never holds it (ADR 0022). A key with no passphrase needs no secret, and the command asks for nothing. With --password, or --passphrase for a key that has one, the command serves the same 127.0.0.1 page as kater init connection (secret_page.py) and opens it in the browser. The person types the secret there, and each try goes to POST /v1/connections. A wrong secret, which stops the test at the sign-in, shows the API's error on the page, and the person tries again. Any other error, such as a name already in use, closes the page, and the command stops with it, because a new secret cannot fix it. A correct one connects, and the command prints the result. The command waits 10 minutes at most. --prompt asks at a hidden prompt in the terminal instead, for a machine with no browser, such as one you reach over SSH. When no browser opens, the command stops and says to add --prompt.
kater admin connection sign-in replaces a Snowflake connection's stored sign-in, or adds one to a connection that has none, as Replace sign-in does on the connection's page in the admin console. It sends PUT /v1/connections/{name}/sign-in, which tests the new sign-in with the account, the warehouse and the role in connection.yaml and stores it only when the test passes. A failed test changes nothing. A new sign-in method also changes auth_method in connection.yaml, as one commit.
kater admin connection sign-in snowflake_prod --user KATER --private-key-file ~/.ssh/kater_key.p8
kater admin connection sign-in snowflake_prod --user KATER --password
It asks for the password or the passphrase as kater admin connection create does: on the 127.0.0.1 page, or at a hidden prompt with --prompt. Each stage of the test prints as the server passes it, with [OK], and a failed stage prints with [ERROR]. Without a Kater API, and for a DuckDB connection, the command stops before it asks for anything.
kater admin connection objects --all lists every database that the connection's role can read, and with --database, that database's schemas with their table and column counts. It reads GET /v1/connections/{name}/listing, which the Schemas step of New connection and Select schemas read too, so it needs a Kater API and the settings:manage permission. Kater keeps the listing, and its worker reads the warehouse again when the listing is more than an hour old. While the worker reads it, the command waits up to two minutes for what it asked for. Without --all, the command reads the databases that connection.yaml selects, through connection.discover.
kater admin connection objects --connection snowflake_prod --all
kater admin connection objects --connection snowflake_prod --all --database ANALYTICS
Onboarding
kater init alone opens the screen in a terminal. Its subcommands do one step each and print one JSON object, for an admin's own agent that does onboarding for them (see ADR 0022). Both work on the same record, lease and local defaults, so an admin can start with one and continue with the other.
kater init needs no kater login first. When no credentials are saved, it opens the browser and waits 15 minutes at most. The browser opens the website's trial sign-up flow (/free-trial-request/ at KATER_SITE_URL): a person with no account makes one, a person with no organisation gets one, and a person who has both goes straight on. The flow ends at PropelAuth's authorize address, which returns to the CLI as kater login does.
kater init guide # the instructions an agent follows
kater init guide about # how the agent drafts the company description with the admin
kater init status [--wait] # every step's status and the next command
kater init connection --name snowflake_prod --account myorg-myaccount --warehouse COMPUTE_WH --user KATER --password
kater init schema-sync --schema ANALYTICS.PUBLIC --no-profile-columns
kater init tables # the synced tables, their columns and the saved company description
kater init tables --values --table ANALYTICS.PUBLIC.ORDERS
kater init about --business "We sell outdoor equipment online." --audience "Finance and merchandising." --question "What is the revenue for each region?"
The other subcommands are content-store, schemas, first-query, team, local-copy, vscode, agent, write-back, skip and reset. Each answer holds ok, the step's result, onboarding (each step's status) and next (the command for the next step); a failure holds error with a code and a message, and the exit code is 1. A command claims onboarding's lease when it is free or the caller's own and keeps its id beside the local defaults, so the agent never handles it. kater init --takeover COMMAND continues another admin's onboarding.
The company description is the fifth step, after the first query, so the agent can draft it from the synced tables. kater init tables lists them from the sync's own record and costs nothing. It also gives the names of the groups and attributes the admin made, as a hint for who uses the data, and no person. With --values and one --table for each table, 20 at most, the Kater API counts each table's rows, the first and last value of each date column, and the 10 most frequent values of each column the profile marked categorical and not unique, in a sample of 100,000 rows. It leaves out a value that only one row holds. The statements are Kater's own, the admin approves each run, and Kater keeps none of the answer. kater init about refuses to replace a description that already has text unless it gets --replace; the terminal screen's form always replaces. Both commands work again after onboarding and after a skip, and neither changes onboarding's progress then.
The agent never holds the warehouse credential. A private key is given as a path. With --password or --passphrase, the command serves one page on 127.0.0.1 (secret_page.py) and opens it in the browser; the admin types the secret there, the page shows the test result, and the command waits 10 minutes at most. The agent subcommand starts no agent: it writes the MCP configuration into the local copy and names the model-table skill for the agent that runs to follow.
kater init opens a Textual screen with the steps on the left and mouse support. A first run starts on a welcome screen that lists the nine steps while Kater prepares the content store. The line at the bottom shows the keys for the focused control. Tab, Shift+Tab, Up and Down move between fields. Left and Right change a choice, and move the cursor in a text field. At the edge of a field, they move to the field beside it on the same line, and Left from the first field moves to the step list. Right moves from the step list back to the form. Enter moves to the next field, and on the last field it runs the primary action. Ctrl+S runs the primary action from any field. Escape or F6 moves to the step list, where the keys 1 to 9 open a step. F1 shows all keys. A locked step explains which prerequisite is incomplete. Only explicit actions, such as Test and connect, submit changes. Below 74 columns the step list becomes one line, and Escape opens the full list.
An error shows below the field that caused it, and focus moves to that field. A field is checked when focus leaves it and again when its action runs. A pasted Snowflake URL becomes the account identifier. Path fields suggest a value, and Right accepts the suggestion: the private key field suggests the .p8 and .pem files in ~/.snowflake, ~/.ssh and the current folder. Ctrl+R shows or hides a secret. The connection test shows each stage as the server completes it. The CLI asks POST /v1/admin/onboarding/connection for application/x-ndjson, and the Kater API answers with one JSON line for each stage (sign_in, then role), then a result or error line. A server that does not stream answers with plain JSON, and the screen shows the result only. When the test fails, the error names the stage that failed (account, sign_in, warehouse or role) as stage, and the screen marks the field to correct.
The terminal uses app-kit's dark Kater palette. Its icon is a terminal-cell version of the SVG on the successful login page. Regenerate the terminal assets after either source changes with uv run apps/cli/scripts/generate-onboarding-brand.py from the repository root. Image libraries are build-only dependencies; the installed CLI does not need them.
The schema step loads databases automatically, in two panes. Up and Down in the database pane choose a database and load its schemas. Right moves to the schemas. Space selects a schema, A selects all or none, and / filters. Selections stay when you change databases, and each database shows its selected count. Reading options does not start a sync. A failed read shows an error and a Retry loading action. A running sync shows one bar for each schema, from the counts the sync job saves in operation.progress.schemas as [tables finished, tables selected]. The bars start when the warehouse has listed the tables. The result waits for Enter.
The team step has three modes: invite people, import a CSV file, or SSO and SCIM. Enter adds an address to a list, a pasted line with many addresses adds each one, and one action sends all invitations. The write-back step shows one action for each stage. After you authorize GitHub in the browser, the screen polls and loads your accounts and repositories without another action.
Non-secret answers are saved as editable defaults under $KATER_CONFIG_DIR/onboarding-drafts/, or ~/.kater/onboarding-drafts/. Each draft belongs to one API, organisation and user. Files are written atomically with owner-only permissions. Passwords, key passphrases and private-key paths stay in memory only. They remain available during retries and navigation, then clear after connection success or exit. The private key is read only when you submit the connection.
Ctrl+Q closes onboarding and prints what is saved and how to continue. A request already in progress finishes before exit. Server jobs continue afterward. Reopening onboarding shows their status. Errors stay beside the form without clearing its fields. After a network failure, the screen offers Reload status before you can repeat a mutation. A saved warehouse connection is read-only in onboarding. Applying a schema sync clears its earlier completion and the first-query completion, but keeps unrelated progress.
kater init --reset clears organisation progress and the current user's local defaults. It does not remove content, established connections, stored credentials, or GitHub write-back settings.
Configuration
CLI-owned settings are Pydantic objects: local presentation/root/scope, serving options, explicit deployment inputs, and outbound API/login settings. Operation payloads and warehouse metadata remain request models; shared runtime identity, MCP authentication/branding and compiler settings stay with their owning packages.
Where a command runs comes from two files, in dbt's shape (CL7 of brainstorm/kater-cli-plan.md). Nothing reads a config.toml.
kater_project.ymlmarks a project, the local copy, and names its profile.kater git cloneandkater git pullwrite it, and.git/info/excludekeeps it out of git. A command that reads content looks for it from the working folder up, or takes--kater-root/KATER_ROOT, and exits 2 without one (kater_core.scopes,project_required).profiles.ymllists each profile's targets. It comes from--profiles-dir, elseKATER_PROFILES_DIR, else the project folder, else the configuration directory (~/.katerorKATER_CONFIG_DIR). The profile is--profile, else the project's, elsekater. The target is--target/-t, elseKATER_TARGET, else the profile'starget. These three flags may come anywhere on the line (help_sections.hoisted).- Every target is
type: kater, a Kater API:api_url, and optionallyauth_url,client_id,redirect_uri,site_urlandtoken. Warehouse calls go through that API with its stored credential (ADR 0042), so no target holds a warehouse credential. Any value can be{{ env_var('NAME') }}or{{ env_var('NAME', 'default') }}. A bad value exits 2 and names the file and the key, never the value. kater debugchecks each part: the version, the profile and target, the project, the API's/health, the sign-in, aselect 1on each connection through the API, the git state and the compile cache.
# ~/.kater/profiles.yml
kater:
target: dev
outputs:
dev:
type: kater
api_url: http://127.0.0.1:8788
prod:
type: kater
api_url: https://api.kater.ai
ci:
type: kater
api_url: https://api.kater.ai
token: "{{ env_var('KATER_CI_TOKEN') }}"
KATER_CONFIG_DIR selects an alternate absolute directory for configuration and credential isolation (not the existing saved-scope location). Login saves each Kater API's sign-in settings in sign-ins.json. The other settings below come from a flag, else the environment, else the default.
| Setting | Environment | CLI flag |
|---|---|---|
| Local JSON output | KATER_JSON |
--json |
| Project folder | KATER_ROOT |
--kater-root |
| Profiles folder | KATER_PROFILES_DIR |
--profiles-dir |
| Profile | None | --profile |
| Target | KATER_TARGET |
--target, -t |
| Local scope | KATER_SCOPE |
--scope |
| Serve mode | KATER_SERVE_MODE |
serve --mode |
Local serve transport (stdio, or http on 127.0.0.1 behind KATER_MCP_TOKEN) |
KATER_SERVE_TRANSPORT |
serve --transport |
Local serve port (0 takes a free one) |
KATER_SERVE_PORT |
serve --port |
| Disable serve cache | KATER_NO_CACHE |
serve --no-cache |
| Serve cache directory | KATER_CACHE_DIR |
serve --cache-dir |
Serve telemetry: true sends each MCP call's spans to the OTLP/HTTP receiver |
OTEL_ENABLED |
None |
Serve telemetry receiver: an OTLP/HTTP base URL, such as http://localhost:4318. Required with OTEL_ENABLED |
OTEL_EXPORTER_OTLP_ENDPOINT |
None |
A target that names Kater's own API with no sign-in settings uses Kater's production values (API_URL, AUTH_URL, CLIENT_ID and SITE_URL in src/kater_cli/config.py). kater init writes the profile kater with the target prod at API_URL when there is none.
Settings validate when needed: local commands do not require API credentials; profile-token requests do not require OAuth settings; help/version do not read the profile. A saved scope in ~/.kater/scope.json counts only inside its own project. Job commands keep their explicit root and scope rules rather than inheriting development defaults. Jobs keep explicit --deployment and --env-file; dotenv is never discovered automatically, and explicit job dotenv loading still does not override existing environment values.
Structure
commands/ contains ordinary annotated Typer callbacks grouped by resource. dispatch.py preserves omitted values and builds the execution adapter's request context. connection.py derives warehouse flags from the existing settings contract, and lifecycle.py adds a typed JSON command for each operation that lifecycle_operations.py lists from the named operation registry. parse_arguments() uses this same Typer tree without opening a service, for host-attached callers.
The root imports no command. command_table.py names each root command, its module and its short help, and the root group in help_sections.py lists them from it and imports a module only to run its command, so kater --help, kater --version and kater <group> --help answer in under half a second. A command module imports what is heavy, such as the client or the configuration, inside the function that uses it. After you add a root command, change one's help or add an operation to the chart, query, dashboard or insight family, run python -m scripts.check_cli_manifest --write; pnpm check:cli-manifest fails until then.
Metadata
Release files for kater-cli 0.2.254
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kater_cli-0.2.254-py3-none-any.whl | Python 3 | none | any | Details |
Release files / kater_cli-0.2.254-py3-none-any.whl
| Download URL | kater_cli-0.2.254-py3-none-any.whl |
|---|---|
| Size | 6.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c30735c5d8adc3831455300d1e0883b49cbe67e3dc898f28c24e5169e07234d7
|
|
BLAKE2b-256 checksum How to use checksums |
277a9e35f085c65eb7aa73f03c271af1b59f8b4f1f86377dffceca3268b2c40d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logSecurity for kater-cli 0.2.254
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 1 file in this release has been uploaded with provenance metadata.
Attestation for kater_cli-0.2.254-py3-none-any.whl
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.