One self-contained binary. One Python-like language. AI, graphs, persistence, APIs, UIs, and cloud deployment as language features, compiled to Python bytecode, JavaScript, and native machine code.
Docs · Playground · Tutorial · Discord
Jac is a programming language designed for humans and AI to build together. It compiles one clean, Python-like syntax to Python bytecode, JavaScript, and native machine code, with the entire PyPI, npm, and C ecosystems available without wrappers or interop layers. The things every real application needs (an LLM call, a data model that persists, a REST API, a frontend, a deployment story) are compiler generated and abstracted by the language, not frameworks you assemble around it. The design rests on two properties, synechic and topokinetic (as described in "the ninja book"), and defined further below ("Why Jac").
What you get:
- One binary, your whole toolchain -- one download replaces the python interpreter, the JS runtime, the Rust/Zig/C compilers, and the package managers: nothing else to install
- One language for the whole stack, compiler-checked end to end -- frontend, backend, and data model are one program under one type checker: humans and AI write correct code faster, and there is one codebase to maintain, not five
- ~5x less code than a modern full-stack setup -- the difference is glue the compiler now generates: API endpoints, route tables, ORM models, validation, serializers, and migrations you never write, review, or debug
- AI is a typed function call, not a framework -- the compiler builds the prompt from your function signature and enforces the return type as the output schema
- Persistence built in -- Objects just persist: no database, no ORM, no migrations
- Laptop to Kubernetes without changing a line --
jac start --scalebuilds the images and provisions the cluster: you write no Dockerfile and no YAML. The compiler runtime spools out multipod deployments with spliced out microservices.
It's time to show and stop telling. See all of those features running in one single codebase next.
Install the self-contained jac binary. No Python, pip, Node, or C toolchain required:
curl -fsSL https://raw.githubusercontent.com/jaseci-labs/jaseci/main/scripts/install.sh | bashThen clone and run jac_site -- the official jaclang.org website, built end to end in Jac (naturally):
git clone https://github.com/jaseci-labs/jac_site
cd jac_site
jac install # first run: pulls npm deps
jac start # builds the frontend + wasm, serves on http://localhost:8000One language spans all three codespaces in this single codebase: the pages and components compile to JavaScript, the endpoints compile to Python and serve over RPC, and the arcade game in game/arena.jac compiles through LLVM to in-browser WebAssembly -- fully borrow-checked, with zero reference counting in the artifact. The docs reader serves the language corpus straight from a real graph, the Ninja Leaderboard persists scores through walkers with no database, and the whole thing is one typechecked, contiguous, synechic codebase.
Prebuilt binaries ship for macOS and Linux; on Windows, use WSL (a native PowerShell installer is coming soon). See the installation guide for versions, upgrading, and IDE setup.
Open the repository of any well-built product and count what a maintainer must read: TypeScript, Python, SQL, and shell where the logic lives; JSX and CSS for presentation; JSON, TOML, YAML, Dockerfile, HCL, and dotenv for configuration. Twelve notations, five package ecosystems, two lockfiles. Nobody chose that. It is what precipitates when every architectural boundary is also a change of language, type system, package manager, and serialization format.
The deeper cost isn't the reading; it's that no compiler can see across any of those boundaries. Rename one field and TypeScript checks the frontend, Python checks the backend, and nothing checks the wire format, the ORM mapping, the OpenAPI document, or the prompt template between them. The whole-program type checker of the modern stack is grep. That is where bugs pool, and it's why teams staff a specialist per boundary: the org chart is a picture of the glue.
The four-copy record (what one field costs in a conventional stack)
One record, maintained in four notations, in one repository:
CREATE TABLE users ( -- migrations/0004_users.sql
id UUID PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
display_name TEXT NOT NULL );class User(Base): # app/models.py (ORM)
id: Mapped[UUID] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(unique=True)
display_name: Mapped[str]
class UserOut(BaseModel): # app/schemas.py (API)
id: UUID
email: str
display_name: strexport interface User { // web/src/types/user.ts
id: string;
email: string;
displayName: string;
}Four copies, three type systems, and one landmine: the fourth copy renames display_name to displayName in a serializer config nobody has reviewed since it was pasted in. Adding one field is a four-file, three-language change plus a migration, a regenerated client, and a cache-key bump -- and not one line of that diff implements behavior. In Jac the record is one node declaration; the compiler owns its representation in the store, on the wire, and in the browser.
None of this is required by computation. The pattern traces to two silent assumptions in the 1945 report that defined the stored-program computer: that computation is stationary (the site of processing is fixed, and data travels to it), and that the machine is the program's world (a program's semantics end at the edge of its process, so frontend and backend, managed and native, script and service are separate programs, joined by hand). Both were engineering defaults for a machine with one memory. Seventy years of habit made them look like laws. Jac is one bet against each.
Against the second assumption, Jac is synechic (from the Greek synecheia, continuity): one continuous, checked medium across ecosystems, tiers, and toolchains. One language spans frontend, backend, and native code, and inherits each one's ecosystem (PyPI, npm, the C world) through a plain import, so one compiler sees both sides of every call. Rename a field and every stale use (server, client, or native) is a compile error, not a production incident. Building the first production synechic language is the whole point of Jac.
Hand-written glue (serializers, route tables, ORM models, API clients) is most of a conventional codebase, and it is where bugs pool, because it is the code no compiler sees. A continuous medium attacks both facts: the compiler generates that layer instead of a human writing it, so it cannot drift, and what is no longer written is the ~5x reduction claimed above. One App, Two Stacks records the side-by-side count.
The same continuity extends to the deepest discontinuity in computing, the divide between managed and systems languages. Today, when the hot path outgrows the garbage collector, the answer is a second language, an FFI boundary, and a rewrite. Jac replaces that divide with gradual borrow checking: unannotated code keeps fully managed semantics, and own and &/&mut opt individual declarations into moves, borrows, and deterministic destruction. A checked boundary (the membrane) mediates every value that crosses between the regimes, and full adoption reaches native artifacts with no reference counting and no collector. The divide is a gradient walked by degrees, never crossed. Gradual borrow checking →
The gradient in code (opt in one declaration at a time)
obj Buffer { has n: int = 0; }
with entry {
a: own Buffer = Buffer(); # this declaration opts in; the rest of the file is untouched
v: &Buffer = &a; # shared borrow of the owner
a.n = 5; # error[E1303]: cannot mutate 'a' while a shared borrow of it is live
b = a; # moves the value out of 'a'
print(a); # error[E1301]: use of 'a' after it was moved
}The checker tracks only what you tag, so node, edge, and walker stay fully managed and the borrow rules never have to reason about the graph. When a module opts in fully, the native pathway compiles it with no RC and no collector in the artifact: systems-language machine code from the same language that serves your web app.
Against the first assumption, Jac is topokinetic (from the Greek topos, place, and kinesis, motion): the moving locus of computation is a language construct. In Jac's Object-Spatial Programming, data lives as a persistent topology of nodes and edges, and walkers carry computation through it, dispatched by arrival. Whatever is reachable from root persists: persistence is a predicate, not an event, and the database dissolves into the language.
The two properties compound, and the dissolved database is the proof: continuity without motion still calls a store outside the language's semantics, and motion without continuity is a graph paradigm confined to one process. Jac is the first language that is both. The boundaries that are physics stay visible on purpose: a cross-tier call is async because the network is real, write conflicts surface as typed errors, and sharing data across users takes an explicit grant. Jac deletes the paperwork, not the physics.
The full argument can be found in "the ninja book": A Synechic and Topokinetic Programming Language develops both language classes and the theory, design and implementation underlying Jac. (DOI: 10.5281/zenodo.21498692).
Cite the book (BibTeX)
Mars, J. (2026). A Synechic and Topokinetic Programming Language. Zenodo. https://doi.org/10.5281/zenodo.21498692
@book{mars2026synechic,
author = {Mars, Jason},
title = {A Synechic and Topokinetic Programming Language},
year = {2026},
publisher = {Zenodo},
doi = {10.5281/zenodo.21498692},
url = {https://doi.org/10.5281/zenodo.21498692}
}Jac is designed for humans and AI to build together, and that includes your coding agent. The lowest-effort setup is no setup: point your agent at the jac CLI and tell it to figure it out. A first prompt like this is genuinely enough:
Build me a <your app idea> in Jac. The `jac` binary is installed and self documenting with `jac guide`.
The binary is self-documenting -- jac guide prints curated reference guides on every corner of the language, and one command extracts them as Agent Skills your agent can load directly:
jac guide --export ~/.claude/skillsFor a deeper integration, the jac binary also ships an MCP server with Jac validation, formatting, docs, and examples built in. Wire it into Claude Code with one command:
claude mcp add jac -- jac mcpFor Cursor, Windsurf, or any other MCP client, add this to your MCP config (use jac mcp --mode lite for smaller models):
{ "mcpServers": { "jac": { "command": "jac", "args": ["mcp"] } } }There's a structural reason agents do better in Jac than in a conventional stack. Glue code is most of what coding models emit (it dominates their training corpora), and glue is exactly the code no tool can verify (or at least you have to add more Glue to verify :-P). It's cheap to generate but expensive to trust. In Jac, entire categories of glue are eliminated, and one compiler checks everything: a whole full-stack app fits in one file that fits in a context window, and a cross-tier mistake an agent makes is a compile error instead of a production surprise.
As discussed in the ninja book, the key insight is that when authorship is abundant, the scarce resource is jurisdiction: the reach of the verifiers that can examine a change and say no, and Jac is built to leave no program point outside it. Even sem annotations do triple duty: prompt material for by llm(), documentation for humans, context for your agent.
One download replaces the interpreter, the JS runtime, the compilers and linker, the package managers, the server, and the deployer. At its center is a polypiler: a compiler whose unit of compilation is the whole polyglot application and whose targets are ecosystems rather than instruction sets:
What's inside the binary (and what you can uninstall)
Here is the actual anatomy. The jac you download is a small native launcher stub with the entire runtime payload appended to the same file. The first run unpacks the payload into a per-version cache. Every run after that is instant.
| Component | How it's in the binary | What you can uninstall |
|---|---|---|
| Launcher stub | The jac file itself: native machine code linked against libc only. Everything below rides in the appended payload |
-- |
| CPython 3.14 | A private python-build-standalone build (PGO+LTO, stripped), dlopened by the launcher at startup: your system Python is never consulted |
Python, pyenv, conda |
| Jac compiler + runtime | Precompiled to JIR in the payload's private site: the REST server (jac start), client framework, K8s deployer (--scale), and byLLM (by llm()). Their optional third-party deps (litellm, pymongo, ...) resolve per-project via jac install |
Flask, FastAPI, Express · Docker, kubectl, Helm · LangChain |
| Bun | The real Bun executable, carried inside the payload and invoked by absolute path, never on your PATH |
Node.js, npm, npx, yarn |
| LLVM 22 | Statically linked into a single jacllvm shared library behind the llvmlite ABI |
gcc, clang |
| Linker + C floor | Jac's own linker emits ELF / Mach-O / PE / wasm directly. Static libc + crt archives, a musl runtime (Linux), and wasm32 libc bitcode are vendored in the payload | ld, lld, make, cmake, emscripten |
| Package manager | pip runs inside the private interpreter, npm resolution goes through the carried Bun: one jac.toml, an automatic .jac/venv, and jac x to run any installed CLI tool |
pip, pipx, uv, poetry, venv/virtualenv |
| Type checker | Built into the compiler (jac check), with the typeshed stdlib stubs vendored at a pinned commit |
mypy, pyright, tsc |
| Dev tooling | Formatter, test runner, language server, and MCP server are modules of the same site (jac fmt / jac test / jac lsp / jac mcp) |
black, ruff, pytest, jest |
Full story: One Binary, Build Anything.
The anatomy records a design position. The components written in Jac (the compiler and runtime at roughly 190,000 lines, the type checker, the formatter and test tooling, and the linkers) sit inside the compiler's own jurisdiction. The carried engines (CPython, Bun, LLVM, and the C runtime archives) are included for feature completeness: each provides a level of compatibility and performance that a reimplementation would not, and each is reached across an ABI, built by a foreign toolchain, and outside the jurisdiction of the language's own verifier. We call the division the self-hosting frontier. The design goal is to replace each carried engine with a Jac implementation, so that the entire artifact above the operating system is written in the language it ships, and gradual borrow checking removes the reason these components were written in C and C++ in the first place. The frontier has moved in one direction only: the compiler crossed first, and the linkers followed, displacing ld and lld. We make no claim about schedule. The full strategy is developed in the ninja book.
The commands you'll use every day:
| Command | What it does |
|---|---|
jac run main.jac |
Run a program (like python3, but for anything) |
jac dev |
Live dev loop with hot reload |
jac start |
Serve your program: REST API, auth, Swagger docs, frontend |
jac build |
Type-check the whole project and emit a sealed app bundle |
jac build --as native |
Compile to a standalone, zero-dependency executable |
jac install / jac x |
Manage PyPI + npm deps / run any installed CLI tool |
jac check / jac fmt / jac test |
Type-check, format, test |
jac mcp / jac guide |
MCP server for coding agents, curated docs |
One language and one skill set produce every kind of software. Each row is one command away:
| What you're building | The command | Guide |
|---|---|---|
| Script / CLI tool | jac run app.jac |
CLI & native |
| Zero-dependency native executable | jac build --as native |
CLI & native |
Single-file app bundle (.jab) |
jac build |
CLI reference |
| Self-contained app executable | jac build --as binary |
CLI reference |
| REST API (+ Swagger, auth, persistence) | jac start api.jac |
Backend APIs |
| Microservices | sv import + jac start |
Backend APIs |
| Full-stack web app | jac start |
Full-stack web |
| Desktop app (native webview) | jac build --client desktop |
Desktop & mobile |
| Mobile app (Android / iOS) | jac build --client mobile |
Desktop & mobile |
| AI agents & LLM apps | by llm() |
AI agents |
| Python package (PyPI wheel) | jac build --as wheel |
Libraries |
| npm package | jac build --as npm |
Libraries |
C-ABI shared library (.so/.dylib/.dll) |
jac nacompile lib.na.jac --shared |
Libraries |
| WebAssembly in the browser | jac build in a web-static project |
Native pathway |
| Kubernetes deployment | jac start --scale |
Deploy & scale |
Three working examples carry the claim: a playable chess engine compiled to a standalone binary, a raylib game running as WebAssembly in the browser, and littleX, a full Twitter-style social app. littleX's entire backend (4 node types, 4 edge types, and 20 walkers that serve as business logic, REST endpoints, persistence, and authorization at once) is 2 files and 475 lines. The whole app, frontend included, is 37 Jac files with exactly one 65-line config file and zero glue artifacts: no route tables, no ORM models, no migrations, no serializers, no auth middleware. A wc -l over the tree confirms the counts.
Each of those deliverables is a project kind: jac create myapp --kind <kind> scaffolds it, stamps the kind into jac.toml, and a bare jac run dispatches on that kind to execute, serve, or build. The scaffolding is the small part. The point is what the language provides for each kind that a traditional stack assembles by hand:
--kind |
What you ship | What Jac adds beyond a traditional language |
|---|---|---|
cli |
Terminal script / tool | Graph-native data modeling in a one-off script, a root graph that persists between runs (no database, no files), and by llm() AI with zero glue: the same script in a traditional stack is Python + SQLite + an LLM SDK |
cli-native |
Compiled program, run in place | The same source compiled through statically linked LLVM: C-level speed with no gcc, clang, or rustc installed |
native-binary |
Zero-dependency executable | Jac's own linker emits the ELF/Mach-O/PE file (no ld in the loop): the executable runs on machines with no Jac and no Python, territory that otherwise requires C, Rust, or Go |
native-lib |
C-ABI shared library (.so/.dylib/.dll) |
Expose Jac to any language with a C FFI (C, Rust, Go, Python ctypes) by marking functions :pub: refcounted handles included, and --target cross-builds for Linux/macOS/Windows with no extra toolchain |
service |
Headless REST API | walker:pub is the endpoint: request bodies map to its fields, report is the JSON response, Swagger at /docs, and per-user isolated persistence: no FastAPI + SQLAlchemy + Pydantic + auth middleware to wire up |
service-mesh |
Microservice cluster | sv import is the architecture: the compiler turns imports into HTTP stubs, the consumer auto-starts its providers, and env vars re-point services across hosts: no OpenAPI codegen, no client SDKs |
py-package |
pip-installable wheel | jac build --as wheel with nothing beyond jac.toml; the wheel runs under the jac binary with no jaclang runtime dependency |
js-package |
npm tarball | Compiles to ES modules with auto-generated package.json and .d.ts declarations, consumable from any JS/TS project, built with no Node.js installed |
web-app |
Full-stack web app | Backend, frontend, and data model in one file: cl code compiles to React, and the compiler generates every RPC and shares types across the boundary, instead of two projects and five frameworks |
web-static |
Client-only page | na {} blocks compile to WebAssembly with Jac's own wasm linker (no emscripten), and jac build emits a portable index.html that opens straight from disk |
desktop |
Native desktop binary | The same app wrapped in the OS webview as one compiled binary: no Electron, no Rust, no PyInstaller |
mobile |
Android / iOS app | The same cl bundle wrapped by Capacitor, or true-native React Native via mobUI: JS tooling runs on the bundled Bun, no Node.js |
The full matrix, with a working recipe and guided track for each: What You Can Build.
enum Priority { LOW, MEDIUM, HIGH, URGENT }
def assess(ticket: str) -> Priority by llm();
with entry {
print(assess("Checkout is down and customers are leaving!"));
# Priority.URGENT
}There is no prompt, no parsing, and no API glue to write. The compiler constructs the prompt from your function's name, argument names, and types (plus optional sem annotations), and the return type is an enforced output schema. These are meaning types, the constructs of Meaning-Typed Programming. Declare your model once in jac.toml, run jac install byllm, and use any LiteLLM-compatible provider, or go fully local with jac install 'byllm[local]'. Learn more →
node Task {
has title: str;
has done: bool = False;
}
walker:pub add_task {
has title: str;
can create with Root entry {
task = Task(title=self.title);
root ++> task;
report {"id": jid(task), "title": task.title};
}
}
walker:pub list_tasks {
can fetch with Root entry {
report [{"id": jid(t), "title": t.title, "done": t.done}
for t in [-->][?:Task]];
}
}jac start api.jac --no-client # POST /walker/add_task · /walker/list_tasksModel your domain as nodes and edges, and send walkers (mobile computation, dispatched by arrival) to traverse it: this is Object-Spatial Programming. Mark a walker :pub and jac start serves it as a REST endpoint: request bodies map onto its fields, report becomes the JSON response, Swagger docs are served at /docs, and every user gets their own isolated, persistent graph. Whatever is reachable from root persists. No ORM, no schema migrations, no session plumbing. Object-Spatial Programming →
node Todo {
has title: str, done: bool = False;
}
def:pub add_todo(title: str) -> Todo {
todo = Todo(title=title);
root ++> todo;
return todo;
}
def:pub get_todos -> list[Todo] {
return [root-->][?:Todo];
}
cl def:pub app -> JsxElement {
has todos: list[Todo] = [], text: str = "";
async can with entry { todos = await get_todos(); }
async def add {
if text.strip() {
todos = todos + [await add_todo(text.strip())];
text = "";
}
}
return <div>
<input value={text}
onChange={lambda e: ChangeEvent { text = e.target.value; }}
placeholder="Add a todo..." />
<button onClick={add}>Add</button>
{[<p key={jid(t)}>{t.title}</p> for t in todos]}
</div>;
}Code in cl (the client codespace) compiles to a React/JSX bundle for the browser. Everything else compiles to Python for the server. That await add_todo(...) in the click handler is a real RPC: the compiler generates the HTTP call, serialization, and shared types across the boundary. jac start serves it, and jac start --dev adds hot reload. Full-stack tutorial →
For all three ideas in one file (an AI categorizer, a native-compiled scoring function, a persistent graph, and a React UI), see jac/examples/mini_todo.
jac start main.jac # local: REST API + auth + Swagger + persistence
jac start main.jac --scale # cloud: Kubernetes with Redis, MongoDB, load balancingYour program text does not change with the shape of its deployment: this is scale invariance, and the scale subsystem that delivers it ships inside the binary. --scale builds the images, provisions Redis and MongoDB, and deploys to Kubernetes with health checks. You write no Dockerfile and no YAML, and what stays in your code is only the physics: latency, failure, and cost surface as typed semantics. Deploy & scale →
This is the Jaseci monorepo, home to everything that makes Jac work:
| Directory | What it is |
|---|---|
jac/ |
jaclang -- the compiler, runtime, and everything inside the jac binary: the language, the full-stack client framework, the scale deployment subsystem, the MCP server, and the LLVM native pathway |
jac-byllm/ |
byllm -- AI/LLM integration via Meaning-Typed Programming (jac install byllm) |
jac/jaclang/cli/docs/ |
The full documentation set -- bundled into the jac binary (jac guide), served as MCP resources, and rendered at jaclang.org/docs |
scripts/ |
The installer and release tooling |
The official VS Code extension lives at jaseci-labs/jac-vscode.
Jac's core ideas are peer-reviewed research, not just design taste:
- Object-Spatial Programming -- the formal model behind nodes, edges, and walkers: mobile computation over a persistent typed topology (arXiv:2503.15812)
- MTP: A Meaning-Typed Language Abstraction for AI-Integrated Programming --
by llm()andsem, evaluated against hand-built prompt pipelines: comparable-or-better accuracy with substantially less code and lower token cost (OOPSLA 2025, arXiv:2405.08965) - The Jaseci Programming Paradigm and Runtime Stack -- the production lineage: walkers served as scale-out endpoints in commercial products (IEEE Computer Architecture Letters, 2023)
The book-length treatment is published: A Synechic and Topokinetic Programming Language develops the synechic and topokinetic language classes and the theory beneath Jac's design (DOI: 10.5281/zenodo.21498692). The project grew out of research at the University of Michigan and is now developed in the open by a global community. To cite Jac in your own work, GitHub's "Cite this repository" button (powered by CITATION.cff) gives a ready-made reference. More on the docs site: Research & Papers.
| Project | Description |
|---|---|
| JacHammer | AI-powered app builder that generates, previews, and ships full-stack Jac apps, on web and mobile |
| Sigil | The skill compiler: plain-Markdown skills compiled into typed agent harnesses that models run inside |
| mars.ninja | The personal site of Jac's creator, built end to end in Jac |
If you're building something with Jac, tell us on Discord and we'll add it here.
Jaseci is a member of the NVIDIA Inception Program for cutting-edge AI startups.
We welcome contributions of every size, from typo fixes to compiler passes.
- Ask questions & share ideas on our Discord server
- Report bugs via GitHub issues
- Send PRs: start with the contributing guide and CONTRIBUTING.md;
bash scripts/fresh_env.shsets up a dev environment
If Jac looks useful to you, star the repo. It helps other developers discover the project.
Jac and the Jaseci stack are MIT licensed. Vendored third-party components retain their own permissive licenses.