karni
Health Warn
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Karni is an open-source Django + React framework for building with AI coding agents. Your agent writes only your domain. The API, admin, permissions and React screens come from a package you upgrade, not code it rewrites in each project. One rule set covers Claude Code, Cursor and Copilot. The build fails when an agent hand-writes what Karni ships.
Karni is an open-source Django + React framework for building with AI coding agents. Your agent writes only your domain. The API, admin, permissions and React screens come from a package you upgrade, not code it rewrites in each project. One rule set covers Claude Code, Cursor and Copilot. The build fails when an agent hand-writes what Karni ships.
Why Karni exists
Every new web project starts the same way: auth, a user model, the admin, permissions, CRUD endpoints, tables, forms, Docker, Celery. Only after all of that does the work on the product itself begin.
AI coding agents made this faster, but not better. We give the agent the same prompts in every project and wait while it builds the same setup again. It writes everything fresh each time: the same code, slightly different, with the subtle parts wrong in different places. Every line costs tokens and time, and every copy has to be maintained.
What is Karni
The problem. Every Django + React project needs the same code before it does anything of its own: serializers, permission classes, admin files, login pages, tables and forms. A boilerplate copies it into your project once. An AI agent writes it again in every project. Either way you pay for it twice: once to produce it, and again to maintain every copy, because a fix made upstream never reaches code that was copied or regenerated.
How Karni solves it. That code lives in three versioned packages you install and upgrade: karni (Python), @karni/ui (React) and the karni command. karni upgrade applies the changes each release needs, so a fix reaches every project that depends on Karni.
What you get. You declare a model and who may access it. Karni gives you the REST API, the admin, permissions and role-based access control, the React screens, the tests and the seed data.
What you still write. Your domain, and only that: your models, the rules for who may do what, and the logic and pages specific to your product. Karni's rules files tell the agent the same, and the build fails when it hand-writes what Karni provides.
Show, don't tell
This is what a developer writes in the reference app, EventHub (__str__ left out):
class Venue(BaseModel):
name = models.CharField(max_length=200)
address = models.TextField()
city = models.CharField(max_length=100)
capacity = models.IntegerField()
class VenueViewSet(BaseViewSet):
model = Venue
access = Access(read=Public(), write=HasRole("organizer", "staff"))
search_fields = ("name", "city")
And this is the page karni make page venues --resource venues writes:
import { Page, ResourceTable } from "@karni/ui";
export default function VenuesPage() {
return (
<Page title="Venues">
<ResourceTable resource="venues" />
</Page>
);
}
What you get with no other code:
- REST endpoints at
/api/venues/, with filters, search, ordering, pagination and?expand= - the OpenAPI schema, Swagger UI and a typed TypeScript client
- an admin screen, with no
admin.py - a table with sorting, filters, pagination and CSV or XLSX export, plus a form and a detail view
- permissions: everyone reads, organizers and staff write
- a one-call test of the whole API (
assert_crud) and realistic seed data
All of EventHub, with payments, e-mail and four roles, is 619 lines of project code. Rebuilding the leads module of Social Stats on Karni took it from 2,346 lines to 996 (case study).
⭐ If Karni is useful to you, please star the repo. It helps other
people building Django + React apps with AI coding agents find the project.
Why not just use Django or a boilerplate?
Karni stays a versioned dependency that you upgrade. A boilerplate is copied once and diverges forever. Plain Django gives you the parts, but every project writes the same serializers, permission classes, admin files and tests again. A boilerplate writes them for you once, and then a security fix upstream never reaches your copy. With Karni the generic code stays in the package, and karni upgrade applies the code changes each release needs.
Quickstart
You need Python 3.12 or later, Node 20.19 or later (24 LTS recommended) and Docker, which runs PostgreSQL.
python3 -m venv .venv && . .venv/bin/activate
pip install karni karni-cli pytest pytest-django
karni new "Ticket Shop" && cd ticket_shop
cp .env.example .env
docker compose up -d --wait db
printf 'DATABASE_URL=postgres://karni:karni@localhost:5432/karni\nKARNI_CACHE=locmem\nMEDIA_ROOT=data/media\nSTATIC_ROOT=data/static\n' >> .env
karni make app events
karni make model Event title:str:200 starts_at:datetime organizer:fk:User -a --access owned:organizer
karni make migration --app events && karni migrate
karni make page login --kind login
karni seed
karni serve --local
In a second terminal, in the same directory:
cd ticket_shop/frontend
npm install
npm run dev
Open http://127.0.0.1:8000/ for the welcome page and /admin/ for the admin. Open http://localhost:5173/login for the React app. Sign in as [email protected] with the password karni-password. karni seed created that user. The quickstart guide explains each step.
PostgreSQL is Karni's default database. To try Karni without Docker, leave out the docker compose line and use DATABASE_URL=sqlite:///data/db.sqlite3: SQLite works, without the guarantees only PostgreSQL gives (range columns, EXCLUDE constraints, trigram search).
Without Python 3.12 on your machine, run the karni command from its container image, ghcr.io/cbsshekhawat18-lab/karni. For example, docker run --rm -u "$(id -u):$(id -g)" -v "$PWD:/work" ghcr.io/cbsshekhawat18-lab/karni new "Ticket Shop" scaffolds the project into the current directory.
Karni compared
| Plain Django + DRF | Cookiecutter Django | SaaS Pegasus | Karni | |
|---|---|---|---|---|
| What you start with | an empty project | a generated project you own | a generated codebase you own (paid, with an open-source edition) | a dependency you upgrade |
| Serializers, viewsets, admin, permissions per model | you write them | you write them | generated once, then yours | derived from the model and its access rule |
| An upstream fix reaches your code | only for Django itself | no | by regenerating and merging | through karni upgrade |
| Teams, subscriptions, multi-tenancy | no | no | yes, mature | no (payments only, as a module) |
| Maturity | the standard | large community, many years in production | large, actively supported | version 0.3, two reference apps |
| Deployment | your choice | Docker and cloud guides, widely used | deploy guides for several platforms | a generated Docker Compose stack, not yet verified end to end |
| AI agent guidance in the project | none | none in the generated project | rule files, CLAUDE.md / AGENTS.md, Claude Code skills and MCP | adapters for eight tools from one rule set, karni context, a build-failing karni check, an MCP server |
Choose Cookiecutter Django or SaaS Pegasus for a proven, complete starting point that you will own. Choose Karni to keep the generic code upstream, and accept a younger framework for it.
The comparison pages go into each alternative, with sources.
How it works
BaseModel. Every model inherits a UUID key, timestamps, soft delete and who-created-it fields. Default managers apply named scopes, so a deleted row never appears in a query you forgot to filter. Models
BaseViewSet and generated serializers. A viewset names a model and an access rule. Karni derives the serializer, filters, search, pagination, ?expand= and an N+1-free query plan, and compiles access into both the permission check and the queryset, so a row outside your scope is a 404. API
An admin that registers itself. Every model appears in a django-unfold admin with columns, filters and search from its fields. AdminMeta changes a detail, and your own ModelAdmin replaces it. Admin
Schema-driven components. @karni/ui reads the OpenAPI document, so ResourceTable, ResourceForm and ResourceDetail need only a resource name to render the right columns, inputs and validation. UI
The enforcement layer. karni check, an ESLint preset and architecture tests fail the build when project code rebuilds what Karni ships, such as a copy of the generated serializer or a raw <table>. Every opt-out needs a written reason. Enforcement
Cheat sheet
A model and its API, in two files:
# events/models.py
from django.db import models
from karni.models import BaseModel
class Venue(BaseModel):
name = models.CharField(max_length=200)
city = models.CharField(max_length=100)
# events/viewsets.py
from karni.api import Access, BaseViewSet, HasRole, Public
from events.models import Venue
class VenueViewSet(BaseViewSet):
model = Venue
access = Access(read=Public(), write=HasRole("organizer", "staff"))
A page, from karni make page venues --resource venues:
import { Page, ResourceTable } from "@karni/ui";
export default function VenuesPage() {
return (
<Page title="Venues">
<ResourceTable resource="venues" />
</Page>
);
}
The commands you use every day:
karni new "Shop" # scaffold a project
karni add payments # wire an installed module into settings and the agent files
karni types # TypeScript types and hooks from the OpenAPI document
karni context # the project inventory an agent reads first
karni seed # realistic, connected demo data
karni check # conventions and system checks; non-zero exit on a violation
The project's Makefile:
make up # karni serve -d
make down # docker compose down
make serve # karni serve
make migrate # karni make migration; karni migrate
make types # karni types
make check # karni check; karni rules sync --check
make rules # karni rules
make agents # karni rules sync
make context # karni context
make test # karni test
make shell # karni shell
make routes # karni routes
make schedules # karni schedule list
make superuser # karni createsuperuser
make logs # docker compose logs -f django worker beat
Commands
Each command links to its full entry in the reference.
All karni commands| Command | What it does |
|---|---|
karni new |
Scaffold a project from templates/project |
karni add |
Install an optional module and wire it into settings |
karni upgrade |
Upgrade across Karni versions: codemods, diff, manual-change report |
karni doctor |
Report the environment: project, interpreter, Node, adapters, history |
karni config |
Read and write Karni settings in the project's .karni/config.toml (committed) or, with --global, in ~/.config/karni/config.toml: get, set, list |
karni ui |
Fit Karni's components to the project's design system: detect |
karni context |
Print a compact machine-readable project inventory |
karni rules |
Karni's conventions for humans and AI agents (no Django needed): sync |
karni check |
Run architecture and system checks |
karni explain |
Explain an error code (E104, C101, PAY004, K106), or a pasted traceback or log line (karni explain -): class, cause, where, fix |
karni types |
Generate TS types and typed hooks from the backend OpenAPI |
karni mcp |
Serve context, rules, check, explain_text and queries as MCP tools (needs karni-cli[mcp]) |
karni queries |
Run one endpoint in-process as a user and report its queries |
karni serve |
Start the dev stack |
karni migrate |
Apply migrations |
karni test |
Run the test suite |
karni shell |
Open a Django shell |
karni routes |
List every URL with its methods, name, view, model and access |
karni schema |
Show every column, constraint and index, and the declaration behind each |
karni worker |
Run a Celery worker |
karni beat |
Run Celery beat |
karni schedule |
List and run the Celery beat schedules: list, run |
karni seed |
Fill every model with realistic demo data |
karni sync-roles |
Create or update the roles KARNI_ROLES declares |
karni createsuperuser |
Create an admin user |
karni manage |
Run any management command |
karni why |
Explain an access decision: why a row, field or action is refused or missing |
karni why-empty |
Explain an empty list: which step removes the rows, and the fix |
karni make |
Generate project code: apps, models, viewsets, tasks, schedules, listeners, pages: app, model, viewset, serializer, migration, test, factory, seeder, task, schedule, event, listener, command, service, middleware, page, component, module |
karni trace |
Follow a captured request: its tasks, retries, email, webhooks, audit |
karni replay |
Re-run a captured request against the current code, as any user |
Reference by area
stable: a reference application uses it. experimental: only Karni's own tests use it so far. planned: not built yet.
Project models inherit karni.models.BaseModel. Optional settings for Karni's layers go in a nested class Karni.
stableBaseModel: UUID key, created and updated timestamps, soft delete,created_byandupdated_bystableRealistic, connected seed data (karni seed,<app>/seeds.py)stableModel events and listeners, optionally queued to Celery (@on_updated)stableField-level change history (class Karni: audit = True)experimentalScheduled tasks (<app>/schedules.py,karni schedule)plannedA tenant scope on every model (thekarni-tenancymodule)
Base classes: AuditedModel, BaseModel, GuardedModel, SoftDeleteModel, TimestampedModel, UUIDModel.
Full reference: base classes and class Karni keys.
A viewset declares model and access. Everything else has a default you can override.
stableBaseViewSet: CRUD, filters, search, ordering, pagination,?expand=and the OpenAPI document, with no serializerstableaccessdeclarations (Public,Owned,HasRole,Where,Granted) compiled into both the request gate and the row filterstableQuery budgets: a list endpoint that runs more queries than declared fails its teststableCSV and XLSX export of any list (/export/?format=)stableImport from CSV or XLSX with a mandatory preview (/import/)experimentalResponse caching per viewset (Cache,Uncached)stableTypeScript types and typed hooks from the OpenAPI document (karni types)
Declarations: Access, Authenticated, Budget, Cache, Can, Granted, HasRole, Owned, Public, Uncached, Unpaginated, Unscoped, Where.
Full reference: karni.api.
Admin and what is configured for youkarni.admin registers every model on start-up. AdminMeta adjusts one model, and a ModelAdmin of your own replaces it.
stableEvery model registered with derived columns, filters and search, with noadmin.pyexperimentalRow scope from the roles' grants: a staff user sees and edits only the rows a grant allowsexperimentalField visibility, change history and the import and export screensexperimentalA permission matrix of every role against every model and action
Full reference: karni.admin.
UI components and hooks@karni/ui renders from the OpenAPI schema, so a page names a resource instead of listing fields.
stableResourceTable,ResourceFormandResourceDetaildriven by the OpenAPI schemastableSign-in, session restore and role checks (AuthProvider,LoginForm,usePermission)stableData hooks with shared caching (useResourceList,useResourceItem)stableImport screen with column mapping and preview (ResourceImport)stablePage building blocks:Page,Layout,Stat,Modal,Toaster,EmptyStateexperimentalChangeHistory,DataChartandFileUploadexperimentalkarni ui detect: the project's shadcn/ui, Tailwind, Material UI, Chakra UI or Mantine theme as Karni's tokens, and shadcn/ui components as Karni's primitives
58 components and 17 hooks, among them ResourceTable, ResourceForm, ResourceDetail, ResourceSelect, ResourceImport, AuthProvider, AuthGuard, LoginForm, Page, Layout. The hooks are useDelayedFlag, useOnlineStatus, useTheme, useKarniPrimitives, useUnsavedChangesGuard, useChangeHistory, useImportDescribe, useImportJob, useImportActions, useResourceList, useResourceItem, useResourceMutations, useKarniClient, useSchema, useAuth, usePermission, useToast.
Full reference: components and hooks.
Permissions: roles, scopes, field visibilityAll of this is built and tested, including row scope in the admin and import with preview. Parts that no reference application uses yet are marked experimental. Tenancy is not built.
stableOneaccessdeclaration per viewset: 404 outside the read scope, 403 for read-but-not-writestableRoles as data (KARNI_ROLES) with theallandownscopesexperimentalTherelated:<key>scope (class Karni: scope_paths) andcustom:scopesstableMembership through a path:owner_field = "workspace__members"stableScope paths that do not resolve failkarni check(E214) instead of answering 500experimentalField visibility per role (class Karni: field_roles)experimentalRow scope in the admin, from the same grants as the APIstableChange history: who changed which field, when, from what to whatexperimentalSensitive fields recorded in the history without their valuesexperimentalMaker-checker approvals and safe impersonation (theapprovalsandimpersonationmodules)plannedTenancy: a tenant scope applied to every model
Full reference: capabilities and settings.
Modules you add with karni addA module is a separate package for anything with its own service or a real memory cost. Install it, then karni add <name> wires it in.
experimentalkarni add approvals: A second person approves high-value changes before they are written, with a queue, an API and an audit trailexperimentalkarni add impersonation: Safe 'log in as user' for Karni support staff: an explicit permission, no privilege escalation, a banner, a time limit, both identities in the audit trailstablekarni add payments: Hosted checkout, refunds and signature-verified webhooks for Stripe and Razorpay, with a test provider for CIplannedkarni-tenancy
Full reference: modules.
Agent integration: context, rules, adapters, MCPThe same rule set produces every adapter file, so the tools never disagree.
stablekarni context,karni rulesandkarni checkin the project workflowstableAdapter files for every supported agent tool from one rule set (karni rules sync)stableSlash commands for the routine tasks (/new-model,/new-page, …)experimentalkarni explain <code>: why an error happens and the fix, offlineexperimentalkarni why/karni why-empty: why a row, field or action is refused or missing for a user, from the code that decides itexperimentalMCP server exposingcontext,rules,check,whyandwhy_emptyas tools
Slash commands: /new-model, /new-page, /add-module, /new-module.
Full reference: slash commands and agent rules.
Testing utilitieskarni.testing turns the usual hundred lines of API tests into a few calls.
stableassert_crudandassert_isolated: the whole API surface and owner isolation in two callsstableGenerated tests fromkarni make model … --with teststableOpenAPI snapshot test (assert_schema_snapshot)stableClients per role (client_as)experimentalquery_budgetanduser_with_roleshelpersstableArchitecture rules that fail the build (karni check, the ESLint preset)
Helpers: APITestCase, assert_admin_row_hidden, assert_crud, assert_isolated, assert_row_hidden, assert_schema_snapshot, client_as, query_budget, user_with_roles.
Full reference: karni.testing.
Built for AI agents
An agent in a Karni project extends the framework instead of rewriting it:
karni contextprints the project in a few lines: apps, models, viewsets, roles, components, hooks and pages.karni rulesprints the 43 conventions, each with a code, in 537 tokens (cl100k).karni rules --check <file>checks one file.- Adapter files.
karni newwrites the file each tool reads, from one rule set: AGENTS.md, CLAUDE.md, Cursor, Copilot, Windsurf, Cline, Aider and Junie, plus slash commands such as/new-model. - An MCP server.
karni mcpservescontext,rulesandcheckas tools. - Your prompts, kept (optional). Gigai Chronicle records every prompt you give an agent inside your repository, and
karni context --with-history <file>reads it back to brief the next agent. It is MIT licensed, local-only, and made by Karni's author.
When an agent writes a serializer or a raw <table> by hand, karni check fails the build and names the component to use. The first prompt, as a new project's welcome page shows it:
You are working in the Karni project `ticket_shop`. Run `karni context` and
`karni rules` first and follow them. Then add an Event model (title, starts_at)
with its viewset and test using `karni make`, run `make migrate && karni types`,
and run `karni check`. Never write serializers, routers, admin classes or
permission checks by hand: Karni derives them.
Karni works the same without any AI tool: nothing in it calls a language model, and every generator is a command you run. See building with an agent and without one.
Frequently asked questions
How is this different from a Django boilerplate?
A boilerplate is copied into your project once, and its serializers, permission classes and admin files then become yours to maintain. Karni keeps that code in versioned packages, derives the per-model parts from your model, and moves your project to each new release with karni upgrade.
Does it work with Cursor, Copilot and Claude Code?
Yes. A new Karni project contains the instruction files each of them reads, generated from one rule set, plus slash commands for routine tasks. karni mcp offers the same commands as MCP tools.
Can I use it without AI tools?
Yes. Nothing in Karni calls a language model, and every generator, such as karni make model, is a command you run yourself.
How much code do I write per model?
The model, an access rule and whatever is specific to your domain. In the reference app EventHub, the Venue resource is a five-line model and a four-line viewset.
Is it production-ready?
Not yet. Version 0.4.0 has two reference applications and CI on every push, but no known production deployment and a Docker path that has not been tested end to end.
What happens when Karni releases a breaking change?
A public name keeps working for at least one minor release, with a KarniDeprecationWarning that names the release that removes it. karni upgrade --to <version> applies the mechanical changes and lists, by file and line, what it could not change (stability promise).
Who should not use Karni
- You have an existing Django application. Karni scaffolds new projects and has no path to adopt an existing one.
- You need teams, subscription billing or multi-tenancy now. SaaS Pegasus ships them. Karni does not yet.
- Your stack is not Django REST Framework with React.
- You want to own and edit every line of the generic code. That is what a boilerplate is for.
Status and roadmap
Version 0.4.0 was released on 2026-10-22, with Django 5.2 LTS and Python 3.12 to 3.14. Each capability's status is in the reference.
- Stable: models, the API with
access, roles with theallandownscopes, the admin, the schema-driven components, change history, import and export, the testing helpers and the agent tooling. - Built, not yet used by a reference app: the
related:andcustom:scopes, field visibility per role, row scope in the admin, and the approvals and impersonation modules. - Not done: an end-to-end test of the Docker stack, the tenancy module.
Documentation, contributing, security, license
- Documentation: https://cbsshekhawat18-lab.github.io/karni/, with the quickstart, the tutorial and the reference.
- Contributing: CONTRIBUTING.md and the Code of Conduct. A second reference application with its friction log helps most.
- Security: report problems privately, as SECURITY.md describes.
- License: Apache License 2.0.
- Credits: built and maintained by Chandrabhan Shekhawat, Gigai Kripa Services (https://gigaikripaservices.com/).
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found