Skip to content

jaseci-labs/jac

Repository files navigation

Jac logo

The Jac Programming Language

One language, one compiler, the whole stack. No glue.

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.

Latest release CI status Code coverage GitHub stars Release downloads Discord members online MIT license

Docs · Playground · Tutorial · Discord

Install jac, create a web app, and serve it in three commands

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 language features, not frameworks you assemble around it. The design rests on two properties, synechic and topokinetic, defined below.

Try Jac in 30 seconds

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 | bash

Then clone and run this_is_jac, a showcase site built entirely in Jac:

git clone https://github.com/jaseci-labs/this_is_jac
cd this_is_jac
jac install   # first run: pulls python + npm deps
jac start     # builds the frontend + wasm, serves on http://localhost:8000

Open http://localhost:8000 and scroll. Sign the guestbook -- it's backed by walkers writing to a real graph that persists automatically, no database to set up. Spawn a walker that traverses that graph live, play a native-compiled shooter running in the browser as WebAssembly, and poke at a full social app embedded as a single component. One language, one codebase, all the way down.

Don't want to install anything? Open the Jac Playground in your browser.

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.

Why Jac exists

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 seam 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 seams. 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: str
export 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.

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 marooned in one process. Jac is the first language that is both. And 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: Why Jac Exists and The Two Ideas, or the side-by-side count in One App, Two Stacks.

For AI agents

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. 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/skills

For 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 mcp

For 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"] } } }

Or skip the setup entirely and paste this into your agent's chat; it will install Jac and configure itself:

Fetch https://raw.githubusercontent.com/jaseci-labs/jaseci/main/SKILL.md and follow its instructions.

LLM-friendly docs pointers live at docs.jaseci.org/llms.txt, and jac ai gives you a Jac-fluent coding agent in your terminal with no setup at all.

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 -- cheap to generate, expensive to trust. In Jac there is less glue to write and one compiler that checks all of it: 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. 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 binary, your whole toolchain

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:

The jac binary links in CPython, Bun, LLVM and a Zig linker, a package manager, a REST server, and a Kubernetes deployer, and builds every kind of artifact
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.

Anatomy of the jac binary: a native launcher stub plus a runtime payload carrying a private CPython, the precompiled Jac compiler and runtime, a statically linked LLVM, the Bun executable, vendored typeshed stubs, and static libc archives
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 -- includes 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
jac ninja editor A pinned Neovim fork statically linked into the launcher itself -- boots in milliseconds, with jac lsp pre-wired a separate editor + LSP setup

Full story: One Binary, Build Anything.

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 ai / jac mcp / jac guide Built-in coding agent, MCP server, curated docs

Build anything

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

Proof it's real: 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. Run wc -l on it and check.

And build it better

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 already knows whether to execute, serve, or build it. The scaffolding is the small part -- the point is what the language does for each kind that a traditional stack makes you assemble 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 -- where a script normally means 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) -- ship to machines with no Jac and no Python, territory that normally means learning 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 writes 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); 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.

AI, graphs, and UIs are language features

Call an LLM like a function

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
}

No prompt, no parsing, no API glue. 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 →

Your data is a graph, and your API writes itself

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_tasks

Model 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 turns it into a REST endpoint: request bodies map onto its fields, report becomes the JSON response, Swagger docs appear 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 →

Frontend and backend in one file

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; jac start --dev gives you 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.

Laptop to Kubernetes without changing your code

jac start main.jac           # local: REST API + auth + Swagger + persistence
jac start main.jac --scale   # cloud: Kubernetes with Redis, MongoDB, load balancing

Your 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 →

Learn Jac

What's in this repo

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)
docs/ The documentation site at docs.jaseci.org
scripts/ The installer and release tooling

The official VS Code extension lives at jaseci-labs/jac-vscode.

Research

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() and sem, 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)

A book-length treatment, developing the synechic and topokinetic language classes and the theory beneath Jac's design, is in preparation. The project grew out of research at the University of Michigan and is now developed in the open by a global community. Citing Jac in your own work? GitHub's "Cite this repository" button (powered by CITATION.cff) gives a ready-made reference. More on docs.jaseci.org: Research & Papers.

Built with Jac

Project Description
Tobu AI-powered memory keeper for the stories behind your photos and videos
TrueSelph Production-grade scalable agentic conversational AI platform
Myca AI-powered productivity tool for high-performing individuals
Pocketnest Birdy AI Commercial financial AI powered by your own financial journey

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.

Contributing

We welcome contributions of every size, from typo fixes to compiler passes.

If Jac looks useful to you, star the repo. It helps other developers discover the project.

License

Jac and the Jaseci stack are MIT licensed. Vendored third-party components retain their own permissive licenses.

About

The Jac Programming Language -- the only language you need to build anything (full stack app, device driver, video game, website, whatever). One self-contained binary; One language; Codegens to Python bytecode, JavaScript, and native machine code.

Resources

License

Code of conduct

Contributing

Stars

555 stars

Watchers

11 watching

Forks

Packages

 
 
 

Contributors