Skip to content

description: The same Karni project built from the terminal without an agent: the karni commands that replace boilerplate and the domain code you write yourself.

Building without an AI agent

Karni is a framework you drive from a terminal, like Django or Laravel. Every repeated piece of a web app is a command, so a project is a sequence of karni calls plus the domain code only you can write. This is the same project as Building with an AI agent, by hand.

The commands

Need Command
A project karni new "Ticket Shop"
A Django app karni make app events
A model (+ viewset, pages, test) karni make model Event title:str:200 … -a --access owned:organizer
An API resource for an existing model karni make viewset Event --access public-read --search title
A migration karni make migration --app events then karni migrate
A frontend page karni make page events --resource events, --kind detail, --kind form, --kind login
A component karni make component StatusBadge
A background task karni make task send_digest --retry 3
A schedule karni make schedule nightly_report --every 1d --task events.tasks.send_digest
An event and a listener karni make event order_shipped, karni make listener notify --on Event.created --queued
A management command karni make command send_reminders
A service (the only place for HTTP clients) karni make service stripe_client
Middleware karni make middleware RequestTiming
A test, factory or seeder karni make test Event, karni make factory Event, karni make seeder Event
An optional module karni add payments
A reusable module of your own karni make module live-chat

Runners: karni serve (--local for a host run), karni migrate, karni test, karni shell, karni routes, karni worker, karni beat, karni schedule list|run, karni seed, karni createsuperuser, karni manage <any django command>. All of them run through the project's .venv or its docker compose stack, whichever exists.

Every command has --help and --dry-run (generators print the diff and write nothing). The full reference is The karni command.

A project, by hand

pip install karni karni-cli
karni new "Ticket Shop" && cd ticket_shop
cp .env.example .env            # DATABASE_URL=sqlite:///data/db.sqlite3 for a no-Docker start
karni make app events
karni make model Venue name:str:200 city:str:100 capacity:int --with viewset,test --access public-read
karni make model Event title:str:200 description:text starts_at:datetime ends_at:datetime \
    "status:choice:draft|published" organizer:fk:User venue:fk:Venue -a --access owned:organizer
karni make migration --app events && karni migrate
karni seed
karni test
karni serve --local             # http://127.0.0.1:8000, /admin, /api/docs
(cd frontend && npm install && npm run dev)   # http://localhost:5173

What you wrote: nothing yet. What you have: two models, two routed API resources with filtering, search and pagination, admin pages, list/detail/form screens, seed data and a test file per resource.

Where your code goes

Kind of code Where Example
Fields and invariants events/models.py Booking.clean() for a capacity rule
Who may read and write the access on the viewset Access(read=Public(), write=Owned("organizer"))
Custom API operations @action methods on the viewset a pay action calling a service
Reactions to data changes events/listeners.py @on_updated(Booking, queued=True)
Periodic work events/schedules.py every("1d", send_digest)
External services events/services/ the only place for HTTP clients
Screens frontend/src/pages/ compose ResourceTable, ResourceForm, ResourceDetail
Demo data events/seeds.py field overrides and seed()
Tests events/tests/ assert_crud, assert_isolated, plus your flows

The architecture rules (karni rules) say where things go; karni rules --check <file> says when something is in the wrong place, and karni check runs all of it before a commit.

Reading an error

Every error Karni raises starts with a code and ends with a link:

E104: EventViewSet: Owned('organiser') does not lead from Event to the user model
(Event has no field 'organiser'). Name a relation path ending at the user, e.g.
Owned("organizer") or Owned("event__organizer"). See …/errors/#e104

karni explain E104 prints the same entry in the terminal, with why Karni objects and the general fix. Error codes lists them all.

Upgrading

Karni is a dependency. pip install -U karni karni-cli then karni upgrade --dry-run shows every change between your version and the new one as a diff; karni upgrade applies the mechanical ones and lists the rest with a link to its migration note. See the stability promise.