CLI Reference
Kirak ships with a kirak CLI for scaffolding projects, reporting facts about a project and the installed Kirak (info, modules, providers, catalog, env, schema), validating config files, and managing database migrations. How coding agents use it: AI Coding Agents.
kirak --helpkirak --version # or -V: prints e.g. "kirak 0.1.1"kirak new
Section titled “kirak new”Scaffold a new project directory.
kirak new my-apicd my-api
# PostgreSQL instead of MySQL (the default):kirak new my-api --database postgres
# Scaffold somewhere other than the current directory:kirak new my-api --dir ../projects--database (mysql or postgres) sets the database block of kirak.json (type, port 3306 or 5432, user root or postgres) and the driver dependency in pyproject.toml: kirak[mysql] or kirak[postgres].
Creates:
my-api/+-- main.py # Application entry point -- create_kirak_app()+-- kirak.json # Project manifest (modules, CORS)+-- .env.example # The secrets kirak.json needs (from `kirak env`)+-- .gitignore+-- pyproject.toml+-- AGENTS.md # Instructions for AI coding agents+-- .kirak/ # JSON Schemas of the installed Kirak (`kirak schema`)+-- .vscode/| +-- settings.json # Maps kirak.json, models/ and agents/ to the schemas+-- models/| +-- posts.json # Sample posts model (one model per file)+-- hooks/| +-- __init__.py| +-- post_hooks.py # Hook stubs to fill in+-- migrations/ # Migration files created by `kirak db init`kirak.json and models/posts.json start with a "$schema" key pointing to .kirak/, so editors complete and check them. AGENTS.md tells a coding agent to run the project’s own kirak, to get facts from the commands below with --json, and to run kirak validate after every edit.
To make the current directory the project – for example a repository a coding agent already has open:
kirak new --here # named after the directorykirak new my-api --here # or named explicitly--here refuses a directory that already has a kirak.json, and keeps any other file that already exists (an AGENTS.md, a .gitignore), listing each one it kept.
After scaffolding:
pip install -e . # the project's dependencies: Kirak with the driver, uvicorn, python-dotenvcp .env.example .env# Edit .env with your database credentials and JWT secretskirak db inituvicorn main:app --reloadkirak info
Section titled “kirak info”What a person or a coding agent needs to orient itself in a project, read from the project’s files only (no database access, no project code imported):
kirak info # textkirak info --json # the facts envelope, see "JSON output" belowkirak info --dir ../my-api # another project, or any directory inside itdata holds kirak_version, project_root, manifest, local_override (whether kirak.local.json exists), modules (from kirak.json merged with kirak.local.json), models (layout: directory or file, path, names), agents (names from agents/*.json), mcp_servers (per file in mcp/: name, path, file, access and the tools the file lists), schemas (exported, stale) and migrations (directory, files, snapshot).
Problems: invalid_json (error) for a config file that cannot be parsed, no_models (warning), schemas_stale (warning) for a .kirak/ schema from another Kirak version, database_driver_not_installed (warning) when the driver for database.type is not installed.
kirak validate
Section titled “kirak validate”Checks the project’s models, kirak.json (merged with kirak.local.json), agent files and MCP server files (mcp/*.json), and reports every problem at once, each with a stable code (Problem Codes):
kirak validate # everythingkirak validate models # one kind: models, manifest, agents or mcpkirak validate mcp --file mcp/support.json # a draft MCP server filekirak validate models --file draft.json # a draft instead of the project's modelskirak validate manifest --file - # a draft kirak.json from stdinkirak validate --override model:comments=c.json --override manifest=k.jsonkirak validate --strict # models without an access block are errorsIt runs the checks startup runs – a project that validates does not fail startup on its config files – plus some startup makes only later or not at all: unknown or missing provider settings, secrets written in kirak.json, relationships to models that do not exist, decimal scale larger than precision, extras that are not installed (the database driver for database.type included), and environment variables not set (warnings). Drafts are checked together with the rest of the project and nothing is written. --override keys: models (the whole models config), model:<name> (one file in models/), manifest, manifest_local, agent:<name>, mcp:<name> (one file in mcp/).
For MCP server files it reports what startup reports (schema, a JSON key written twice, two files with one name, tool refs that name no operation of the app, a module that is not enabled, an operation that cannot be a tool) plus two warnings: mcp_without_mcp_module (files in mcp/ but "mcp" is not in modules) and too_many_mcp_tools (a server with more than 30 tools). Python tools registered with @kirak.mcp("<name>").tool live in code, which validate does not import: their checks run at startup.
--extras and --env-names-file work as for kirak env. With --json, data is {"valid", "checked", "errors", "warnings"}; errors give exit code 1, warnings alone exit code 0.
kirak env
Section titled “kirak env”The environment variables the project needs and whether each is set – names only, never values:
kirak env # table: variable, set?, required?, what needs itkirak env --jsonkirak env --env-names-file names.txt # check against another runtime's variable namesThe list follows the project’s kirak.json and agent files: the core variables (DB_PASSWORD, KIRAK_REDIS_URL), the auth module’s secrets, those of each other enabled module, one set per configured provider instance (KIRAK_PAYMENT_<INSTANCE>_SECRET_KEY and so on), the secret of each enabled social login provider, and the API key of each AI model provider the agents or ai.default_model use. Each entry has name, purpose, required, secret, needed_by, alternatives (other names accepted instead), default and set.
“Set” means present in the process environment or the project’s .env, unless --env-names-file is given: then the names in that file (one per line; a NAME=value line is read as NAME and the value is ignored). Every required variable that is not set is an env_missing error (exit code 1).
kirak catalog --json inside a project includes the same list under project.env.
kirak modules, kirak providers, kirak catalog
Section titled “kirak modules, kirak providers, kirak catalog”What the installed Kirak offers, from one source: the specs every module and provider declares, the packaged schemas and the entry points of installed provider packages. They work outside a project too; inside one (or with --dir) they also say what the project enables and configures.
kirak modules # every module: installed?, providers N/M, enabled here?, pip extra, summarykirak modules payments # one module: settings schema, internal models, hook events, providers (--json: also operations)kirak providers notifications # every provider of a module (all kinds)kirak providers notifications --kind smskirak providers payments stripe # one provider: settings, secrets, capabilities, website, kirak.json examplekirak catalog --json # all of the above, core facts, social and AI model providers| Option | Meaning |
|---|---|
--json |
The facts envelope (see “JSON output” below) |
--dir |
A project (or a directory inside one) to report enabled modules and configured instances for |
--extras a,b |
The pip extras of the runtime the project will run on (for example a Docker image). “Installed” is then decided from these extras – a group extra such as all-payments covers its members – instead of the packages this Python can import |
A provider’s secrets give the environment variable pattern, e.g. KIRAK_PAYMENT_<INSTANCE>_SECRET_KEY: <INSTANCE> is the instance name in kirak.json, upper-cased. Providers added by installed packages appear with "source": "entry_point".
Every provider has a website: its vendor’s site (for example a logo in Kirak Studio), null for providers with no vendor (local storage, the database queue, smtp, the generic webhook). The AI model providers and the social login providers in kirak catalog --json carry one too (null for protocols and Kirak’s own sign-in: saml, oidc, openid, cas, email, username; and for mineid, a service that has shut down). A third-party provider sets it with a WEBSITE class attribute.
Each module operation in --json output (kirak.<module>.<name>(params)) has name, description, effect (read, write or destructive), tool_safe (false when it is not called with JSON arguments: provider webhooks, file uploads, browser redirect flows), providers (the provider types that support it, null for all), params, a JSON Schema object of the params dict, and result, a JSON Schema of the result’s data where the module builds it the same way for every provider (null otherwise). A parameter that only some provider types read lists them in x-kirak-providers:
{"name": "refund_payment", "effect": "destructive", "tool_safe": true, "providers": null, "params": {"type": "object", "required": ["payment_id"], "properties": { "payment_id": {"type": "string", "description": "The provider's payment id."}, "amount": {"type": "integer", "description": "Partial refund in the smallest unit. Omit for a full refund."}, "reason": {"type": "string", "description": "...", "x-kirak-providers": ["airwallex", "paddle", "square", "xendit"]}}}}Problems: unknown_module, unknown_provider_kind and unknown_provider (exit code 2).
The same data is available in Python from kirak.catalog (installed_catalog(), project_catalog(root), modules(), module(name), providers(module), provider(module, type)).
JSON output
Section titled “JSON output”Commands that report facts (kirak info, kirak db status, and more to come) accept --json. stdout then carries exactly one JSON document and nothing else; logs and messages go to stderr:
{ "kirak_version": "0.1.1", "command": "info", "ok": true, "data": {}, "problems": [ {"severity": "warning", "code": "schemas_stale", "message": "...", "file": ".kirak/agent.schema.json", "path": ""} ]}| Field | Meaning |
|---|---|
ok |
false when any problem has severity error |
data |
The command’s result; null when the command could not run |
problems |
Every problem found, not just the first. code is stable; file is relative to the project root; path is a dotted path inside that file |
Exit codes: 0 no errors (warnings allowed), 1 the command ran and found errors (or failed, code command_failed), 2 not a Kirak project (code not_a_project) or a usage error.
Secret values never appear in the output: any value of a secret-looking environment variable (process environment or the project’s .env), and any password inside a URL value, is replaced with ***.
The envelope, the data shapes and the problem codes are a public contract: new fields and codes may be added; existing ones change only after a deprecation period.
kirak schema
Section titled “kirak schema”Writes the JSON Schemas of Kirak’s config files, from the installed Kirak version, to .kirak/ in the project:
| File | Describes |
|---|---|
.kirak/models.schema.json |
models.json (all models) |
.kirak/model.schema.json |
one model: a value in models.json, or one file in models/ |
.kirak/manifest.schema.json |
kirak.json and kirak.local.json |
.kirak/agent.schema.json |
one file in agents/ |
.kirak/mcp.schema.json |
one file in mcp/ (an MCP server) |
.kirak/tools.schema.json |
a tools map (ref -> options); referenced by the files that offer tools, not a file of its own |
kirak schema # write .kirak/*.schema.json in the current directorykirak schema --dir ../my-api # write them in another projectkirak schema --print manifest # print one schema (models, model, manifest, agent, mcp or tools) to stdoutEvery key has a description, so editors show help and completion, and coding agents can read the rules of the installed version instead of a copied document. Kirak validates the files at startup with the same schemas. Each exported file carries "x-kirak-version"; after upgrading Kirak, startup logs a warning until you run kirak schema again.
Point a file at its schema with a top-level "$schema" key. Kirak ignores that key when loading:
{ "$schema": "./.kirak/manifest.schema.json", "title": "My API"}For a file in models/, agents/ or mcp/, use "../.kirak/model.schema.json", "../.kirak/agent.schema.json" or "../.kirak/mcp.schema.json".
kirak dev mcp
Section titled “kirak dev mcp”Starts the dev MCP server on stdin/stdout, for coding agents. A coding tool runs this command
itself; it opens no port. Needs pip install "kirak[dev-mcp]" (without it the command exits
with that hint). Tools, configuration per coding tool and the one-time reconnect for a new
project: AI Coding Agents.
python -m kirak runs the same CLI as kirak, for when the kirak script is not on PATH,
e.g. .venv/bin/python -m kirak dev mcp.
kirak db
Section titled “kirak db”Database migration commands. The connection settings come from the database block of kirak.json, the password from DB_PASSWORD (see Configuration). Every db command runs in the project root: the nearest directory, from the current one upwards, that contains kirak.json, so they work from any subdirectory of the project.
kirak db init
Section titled “kirak db init”Generate and apply the initial migration from all models.
kirak db initkirak db init --name setup # custom name suffix (default: "initial")What it does:
- Loads all user models from
models/directory (ormodels.json) - Automatically includes built-in auth models
- Generates
migrations/{UTC timestamp}_initial.sql(e.g.20250801100000_initial.sql) with MySQL and PostgreSQL DDL - Writes
migrations/models_snapshot.json - Applies the migration immediately
Fails if migration files already exist – use makemigrations for subsequent changes.
Output:
Created: migrations/20250801100000_initial.sqlSnapshot: migrations/models_snapshot.json
Applying migration...Done -- 1 applied, 0 already applied.kirak db makemigrations
Section titled “kirak db makemigrations”Diff current models against the snapshot and generate a new migration file.
kirak db makemigrations # auto-generated namekirak db makemigrations add-status-field # named migrationWhat it does:
- Reads current models
- Compares against
migrations/models_snapshot.json - Computes the diff (new tables, dropped tables, added columns, dropped columns, type changes)
- Writes a new migration file named
{UTC timestamp}_{name}.sql(e.g.20250820103000_add_status_field.sql– note the version is a full timestamp, not a sequential number like0002, and any dashes innameare converted to underscores) - Updates the snapshot
To see the SQL without writing the migration or the snapshot:
kirak db makemigrations --dry-run # MySQL and PostgreSQL SQL, plus noteskirak db makemigrations --dry-run --json # data: {"changes", "mysql", "postgresql", "notes"}The dry run reads only the model files and the snapshot, not the database. Without a snapshot it reports no_snapshot (exit code 1). --json needs --dry-run.
An added column marked "unique": true gets a CREATE UNIQUE INDEX uq_<table>_<column> statement after its ADD COLUMN. Changing unique on an existing column is not detected – add or drop the index by hand.
If no changes are detected:
No changes detected -- models match the snapshot.Migration file format:
-- Kirak Migration: 20250820103000_add_status_field-- Generated: 2025-08-20T10:30:00Z
-- BEGIN:MYSQLALTER TABLE posts ADD COLUMN status VARCHAR(50) DEFAULT 'draft' NOT NULL;CREATE INDEX idx_posts_status ON posts (status);-- END:MYSQL
-- BEGIN:POSTGRESQLALTER TABLE posts ADD COLUMN status VARCHAR(50) DEFAULT 'draft' NOT NULL;CREATE INDEX idx_posts_status ON posts (status);-- END:POSTGRESQLEvery migration file is named {UTC timestamp}_{name}.sql, the first one from kirak db init included (--name changes its suffix from initial).
Only the section matching database.type in kirak.json is executed. Edit the file before applying if you need custom DDL (additional indexes, data migrations, stored procedures).
kirak db migrate
Section titled “kirak db migrate”Apply all pending migration files in version order.
kirak db migrateKirak maintains a kirak_migrations table that records which files have been applied. Already-applied files are skipped.
Output:
2 applied, 1 already applied.kirak db status
Section titled “kirak db status”Show the status of all migration files.
kirak db statuskirak db status --json # the facts envelope, see "JSON output" belowOutput:
VERSION NAME STATUS APPLIED AT------------------------------------------------------------------------20250801100000 initial applied 2025-08-01T10:00:00Z20250810143000 add_status_field applied 2025-08-10T14:30:00Z20250815091500 add_product_model pending --Status values:
| Status | Meaning |
|---|---|
applied |
Migration has been successfully executed |
pending |
Migration file exists but has not been applied |
applied (MODIFIED) |
Applied migration’s file has changed since (checksum mismatch) |
With --json, data is {"migrations": [{"version", "name", "status", "applied_at"}], "applied": n, "pending": n}. Each pending migration is a migration_pending warning (exit code 0) and each modified one a migration_modified error (exit code 1).
kirak db reset
Section titled “kirak db reset”Drop ALL tables in the database.
kirak db reset --force # --force is requiredWorkflow: Adding a Field
Section titled “Workflow: Adding a Field”# 1. Edit models/posts.json -- add the new field to "schema"# 2. Generate the migrationkirak db makemigrations add-status-to-posts
# 3. Review the generated file (filename is a UTC timestamp, not a sequential number)cat migrations/20250815091500_add_status_to_posts.sql
# 4. Applykirak db migrate
# 5. Restart the serveruvicorn main:app --reloadEnvironment Variables for CLI
Section titled “Environment Variables for CLI”kirak db commands take the database type, host, port, user and name from the database block of kirak.json, and only the password from DB_PASSWORD. They load the project’s .env themselves, from the project root, so nothing has to be exported first. A variable already set in the environment wins over the same variable in .env, e.g. in CI:
DB_PASSWORD=... kirak db migratekirak env lists the variables the project needs and whether each is set, without printing values.