Skip to content

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.

Terminal window
kirak --help
kirak --version # or -V: prints e.g. "kirak 0.1.1"

Scaffold a new project directory.

Terminal window
kirak new my-api
cd 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:

Terminal window
kirak new --here # named after the directory
kirak 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:

Terminal window
pip install -e . # the project's dependencies: Kirak with the driver, uvicorn, python-dotenv
cp .env.example .env
# Edit .env with your database credentials and JWT secrets
kirak db init
uvicorn main:app --reload

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):

Terminal window
kirak info # text
kirak info --json # the facts envelope, see "JSON output" below
kirak info --dir ../my-api # another project, or any directory inside it

data 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.


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):

Terminal window
kirak validate # everything
kirak validate models # one kind: models, manifest, agents or mcp
kirak validate mcp --file mcp/support.json # a draft MCP server file
kirak validate models --file draft.json # a draft instead of the project's models
kirak validate manifest --file - # a draft kirak.json from stdin
kirak validate --override model:comments=c.json --override manifest=k.json
kirak validate --strict # models without an access block are errors

It 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.


The environment variables the project needs and whether each is set – names only, never values:

Terminal window
kirak env # table: variable, set?, required?, what needs it
kirak env --json
kirak env --env-names-file names.txt # check against another runtime's variable names

The 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.

Terminal window
kirak modules # every module: installed?, providers N/M, enabled here?, pip extra, summary
kirak 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 sms
kirak providers payments stripe # one provider: settings, secrets, capabilities, website, kirak.json example
kirak 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)).


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.


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
Terminal window
kirak schema # write .kirak/*.schema.json in the current directory
kirak schema --dir ../my-api # write them in another project
kirak schema --print manifest # print one schema (models, model, manifest, agent, mcp or tools) to stdout

Every 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".


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.


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.

Generate and apply the initial migration from all models.

Terminal window
kirak db init
kirak db init --name setup # custom name suffix (default: "initial")

What it does:

  1. Loads all user models from models/ directory (or models.json)
  2. Automatically includes built-in auth models
  3. Generates migrations/{UTC timestamp}_initial.sql (e.g. 20250801100000_initial.sql) with MySQL and PostgreSQL DDL
  4. Writes migrations/models_snapshot.json
  5. Applies the migration immediately

Fails if migration files already exist – use makemigrations for subsequent changes.

Output:

Created: migrations/20250801100000_initial.sql
Snapshot: migrations/models_snapshot.json
Applying migration...
Done -- 1 applied, 0 already applied.

Diff current models against the snapshot and generate a new migration file.

Terminal window
kirak db makemigrations # auto-generated name
kirak db makemigrations add-status-field # named migration

What it does:

  1. Reads current models
  2. Compares against migrations/models_snapshot.json
  3. Computes the diff (new tables, dropped tables, added columns, dropped columns, type changes)
  4. 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 like 0002, and any dashes in name are converted to underscores)
  5. Updates the snapshot

To see the SQL without writing the migration or the snapshot:

Terminal window
kirak db makemigrations --dry-run # MySQL and PostgreSQL SQL, plus notes
kirak 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:MYSQL
ALTER TABLE posts ADD COLUMN status VARCHAR(50) DEFAULT 'draft' NOT NULL;
CREATE INDEX idx_posts_status ON posts (status);
-- END:MYSQL
-- BEGIN:POSTGRESQL
ALTER TABLE posts ADD COLUMN status VARCHAR(50) DEFAULT 'draft' NOT NULL;
CREATE INDEX idx_posts_status ON posts (status);
-- END:POSTGRESQL

Every 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).


Apply all pending migration files in version order.

Terminal window
kirak db migrate

Kirak maintains a kirak_migrations table that records which files have been applied. Already-applied files are skipped.

Output:

2 applied, 1 already applied.

Show the status of all migration files.

Terminal window
kirak db status
kirak db status --json # the facts envelope, see "JSON output" below

Output:

VERSION NAME STATUS APPLIED AT
------------------------------------------------------------------------
20250801100000 initial applied 2025-08-01T10:00:00Z
20250810143000 add_status_field applied 2025-08-10T14:30:00Z
20250815091500 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).


Drop ALL tables in the database.

Terminal window
kirak db reset --force # --force is required

Terminal window
# 1. Edit models/posts.json -- add the new field to "schema"
# 2. Generate the migration
kirak 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. Apply
kirak db migrate
# 5. Restart the server
uvicorn main:app --reload

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:

Terminal window
DB_PASSWORD=... kirak db migrate

kirak env lists the variables the project needs and whether each is set, without printing values.