karni-cli
The karni command. Orchestrates a Karni project's own manage.py via
subprocess — the CLI itself never imports Django.
Commands
karni new <name>— scaffold a project from the bundled cookiecutter template (monorepo checkouts use the livetemplates/project; override withKARNI_TEMPLATES).karni add <module>— addkarni-<module>to[project].dependenciesand wirekarni_<module>into the# karni:appsblock in config/settings.py. Only that marker block is managed; any other layout gets a clear error and you edit settings manually. Once the module is installed it also records the module'sAGENTS.fragment.mdas.karni/modules/<module>.mdand refreshes the agent adapters.karni types— dump the OpenAPI schema (manage.py spectacular), generatetypes.ts(openapi-typescript, project-pinned binary preferred, elsenpx openapi-typescript@^7) and typed hooks (hooks.ts) over @karni/ui.karni context— compact machine-readable inventory (< 200 tokens for a typical project): APPS (from the# karni:appsblock) and PAGES (fromfrontend/src/pages/) read statically, MODELS/VIEWSETS frommanage.py karni_context, COMPONENTS/HOOKS from @karni/ui's build-generateddist/manifest.json(omitted when absent — runnpm i @karni/uiinfrontend/on the host to enable them;--manifest PATHoverrides). Nothing is hand-maintained.karni context --with-history [PATH]— the same inventory plus aHISTORY:brief of what was already asked and decided about PATH (without PATH: the project's recorded decisions) from any history provider that detects a store, e.g. Gigai Chronicle's.chronicle/. Capped at ~300 tokens (characters ÷ 4), cut at line boundaries with a last line naming the full-brief command. With no store the output is exactlykarni context's. Seedocs/concepts/history-providers.md.karni check [-q]— Django system checks pluskarni.checksentry-point hooks (the architecture-test extension surface). A clean run outside CI may end with one tip on stderr, at most once per project;-qsuppresses it.karni doctor [-q]— human-readable environment report: project, interpreter (.venv/ compose service), Node/npm, the @karni/ui manifest, adapter freshness, history providers. May end with the same one-time tip.karni config get|set|list [--global] KEY [VALUE]— settings (suggest_tools):.karni/config.tomlin the project (committed) or$XDG_CONFIG_HOME/karni/config.tomlwith--global; the project wins. Machine-local state (e.g. "tip shown") lives in the self-ignoring.karni/local/.karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]— Karni's conventions fromkarni.agent.rules(no Django needed), and static single-file checks (exit 1 on violations).karni rules sync [--check] [--force]— regenerate the thin agent adapters (AGENTS.md, CLAUDE.md, Cursor, Windsurf, Copilot, Cline, Aider, Junie) and slash commands fromkarni_cli/agent_adapters.toml;--checkis the CI staleness gate.karni mcp— context, rules and check as MCP tools (pip install 'karni-cli[mcp]').karni upgrade [--to VERSION] [--from VERSION] [--dry-run] [--allow-dirty] [--list]moves the project across Karni versions. It reads the karni installed in the project (--fromoverrides), takes every breaking change between that and--tofrom Karni's machine-readable changelog (packages/karni/karni/changelog/*.toml, bundled into karni-cli), and runs their codemods in release order. Python codemods use libcst; TypeScript codemods use a pinned jscodeshift throughnpxand are skipped, with the reason, without Node.js. The codemods run on a scratch copy, and the result is written back all at once, or not at all if one fails.--dry-runprints a unified diff and writes nothing. Writing needs a clean git tree;--allow-dirtyoverrides that, and is also required outside git. The report lists what was applied (each file and its rewrite count), what could not be fixed automatically (the sites found, with each migration-note link) and what was skipped. Run it before you raise the karni pin. Seedocs/migrations/.
See docs/agents.md for the agent surface in full.
Runners
Artisan-style shortcuts. Each runner runs one project command through the
project interpreter (see Execution environment below), streams its output
and exits with its exit code. --help on each names the command it wraps.
Extra arguments pass straight through; put -- before any that clash with
karni's own options (--docker, --service, --help).
| Command | Runs |
|---|---|
karni serve |
docker compose up (--build, -d) |
karni serve --local [--host H] [--port P] |
manage.py runserver 127.0.0.1:8000 via .venv |
karni migrate [ARGS] |
manage.py migrate [ARGS] |
karni test [ARGS] |
python -m pytest [ARGS] |
karni shell [ARGS] |
manage.py shell [ARGS] |
karni routes [--json] |
manage.py karni_routes: every URL with methods, name, view, model, access |
karni worker [-A APP] [-l LEVEL] [ARGS] |
python -m celery -A config worker -l info [ARGS] |
karni beat [-A APP] [-l LEVEL] [ARGS] |
python -m celery -A config beat -l info [ARGS] |
karni schedule list [--json] |
manage.py karni_schedules: every merged beat schedule |
karni schedule run NAME |
manage.py karni_schedules --run NAME: runs the task once, synchronously |
karni createsuperuser [ARGS] |
manage.py createsuperuser [ARGS] |
karni manage ARGS |
manage.py ARGS: the raw passthrough for everything else |
In docker mode, shell, test, worker, beat, createsuperuser and
manage get a TTY (docker compose exec without -T) when karni runs in a
terminal, so prompts and Ctrl-C work. Scripted and agent runs keep -T.
With the compose stack up, worker and beat already run as services, so
karni worker and karni beat are for .venv development. See
docs/events.md and docs/scheduling.md.
Generators
karni make <type> writes the project code a task needs, so neither a person
nor an AI agent hand-creates a file a generator makes. karni make --list
prints them all; every one is also a hidden Laravel-style alias
karni make:<type>. The full reference (every option, the field DSL) is
docs/cli.md, generated from this CLI.
| Command | Writes |
|---|---|
karni make app NAME |
NAME/{__init__,apps,models,viewsets}.py, migrations/, tests/; wires # karni:apps |
karni make model NAME [FIELD...] |
class NAME(BaseModel) in <app>/models.py; --with viewset,page / -a chains; --migrate |
karni make viewset MODEL |
<Model>ViewSet with its access (--access authenticated|public-read|owned:<field>|staff|role:<name>), --search |
karni make serializer MODEL --reason ... |
<app>/serializers.py + serializer_class on the viewset |
karni make migration [NAME] |
runs manage.py makemigrations [--app] [--name] [--empty] through the project interpreter |
karni make task NAME |
@shared_task in <app>/tasks.py (--retry N) |
karni make schedule NAME |
every(...)/cron(...) in <app>/schedules.py (--every 15m / --cron "0 3 * * *", --task) |
karni make event NAME |
a Signal in <app>/events.py |
karni make listener NAME --on ... |
<app>/listeners.py: Model.created|updated|deleted or a custom event; --queued |
karni make command NAME |
<app>/management/commands/NAME.py |
karni make service NAME |
<app>/services/NAME.py (where HTTP clients are allowed) |
karni make middleware NAME |
<app>/middleware.py, wired through # karni:middleware |
karni make page NAME |
frontend/src/pages/NAME.tsx (≤ 50 lines; --resource R --kind list|detail|form), route in frontend/src/routes.tsx |
karni make component NAME |
frontend/src/components/NAME.tsx claiming a role (--role) |
karni make module NAME |
modules/karni-NAME/ per docs/modules.md |
karni make app events
karni make model Event title:str:200 starts_at:datetime "status:choice:draft|live" \
organizer:fk:User 'venue:fk:Venue?' -a --access owned:organizer --search title
karni make migration && karni migrate
karni make listener notify_organizer --on Event.created --queued
karni make schedule nightly-report --cron "0 3 * * *"
Every generator: never overwrites without --force; --dry-run prints the
files and diff and writes nothing; prints each created/modified file plus
notes (the chosen access, the route, the next command); resolves the app
from --app or the project's only local app; edits existing files only
through marker comments or AST-located appends (an unfamiliar layout is an
error naming the manual step); never imports Django. Generated Python is
clean under ruff (lint and format) and karni rules --check, and generated
pages parse and stay within 50 lines — tests/test_make_gate.py generates
every type into a fresh scaffold and asserts it (plus tsc and the
frontend's ESLint config when KARNI_TEST_NODE_MODULES points at an
installed frontend/node_modules), then runs the generated backend for real
(makemigrations, migrate, check, requests through the Django test client).
Quote fields that end in ? in zsh ('venue:fk:Venue?') and choice values
joined by |.
Execution environment
Commands that run the project resolve, in order: --docker/--no-docker flag →
<project>/.venv → a running compose service (default django; change with
--service or KARNI_COMPOSE_SERVICE) → an error naming both remedies.
Metadata
Release files for karni-cli 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| karni_cli-0.3.1.tar.gz | 245.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| karni_cli-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 507.3 kB
Release files / karni_cli-0.3.1.tar.gz
| Download URL | karni_cli-0.3.1.tar.gz |
|---|---|
| Size | 245.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
16f38d4257fa7c78db3bed9a80b0ee7c8b4e2ba2b57461153d0891d808822972
|
|
BLAKE2b-256 checksum How to use checksums |
cb57aaf57e9a0cf50de9e6f661b8a7cc0a14138df9fe7bfacda04f40c5f54f07
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / karni_cli-0.3.1-py3-none-any.whl
| Download URL | karni_cli-0.3.1-py3-none-any.whl |
|---|---|
| Size | 261.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6c332a4f638f3b0ca4dac0c2b5d2241002d360a2e6719dfb9d2efe247240d0e3
|
|
BLAKE2b-256 checksum How to use checksums |
d5ce0d5fe115ed639738061b88924f66dcc8cda6370c961ecc1799aaa6acfe66
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Security for karni-cli 0.3.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.