CLI Reference#
The jac command is your primary interface for working with Jac projects. It handles the full development lifecycle: running programs (jac run), type-checking code (jac check), running tests (jac test), formatting and linting (jac fmt, jac check --lint), managing dependencies (jac install, jac remove, jac update), serving APIs (jac start), and even compiling to native binaries (jac nacompile, or jac build --as native). Think of it as combining the roles of python, pip, pytest, black, and flask into a single unified tool.
Every capability ships built into the core binary. The scale subsystem (formerly the jac-scale plugin) provides deployment commands and flags -- for example, jac start --scale for Kubernetes deployment. The full-stack client framework (formerly the jac-client / jac-desktop plugins) contributes others, such as jac build --client desktop for desktop app packaging. byLLM likewise ships built in, contributing jac model and the AI language features.
💡 Enhanced Output: All CLI commands render beautiful, colorful Rich-style output out of the box -- themes, panels, and spinners are built into jaclang by default, with no extra install needed.
I want to…#
A task-first index into the commands below. The full alphabetical list follows in Quick Reference.
| I want to… | Command(s) |
|---|---|
| Run a program | jac run (no filename → runs the project by its kind; --entry <walker> runs a specific entrypoint) |
| Start a web/API server | jac start |
| Run the live hot-reload dev loop | jac dev · jac start --dev |
| Deploy to Kubernetes | jac start --scale · jac scale status · jac scale destroy |
| Create a new project | jac create |
| Set up / build a client shell (web, desktop, mobile) | jac setup · jac build --client <target> |
| Compile a native binary or C-ABI shared library | jac nacompile · jac build --as native |
| Build one distributable artifact (.jab, wheel, npm, source) | jac build --as {jab,wheel,npm,source,…} |
| Add, remove, or update dependencies | jac install <pkg> · jac remove · jac update |
Install project dependencies (preview with --plan) |
jac install · jac install --plan |
| Run an installed CLI tool under Jac | jac x |
| Type-check, format, or lint | jac check · jac fmt · jac check --lint · jac precommit |
| Run tests | jac test |
| Debug or visualize a graph | jac run --debug · jac dot · jac browse |
| Have an AI agent write or edit code in my project | jac ai |
| Query code structure (definitions, uses, walkers) | jac code |
| Inspect or recover the persistence DB | jac db |
| Manage config or profiles | jac config |
| Manage byLLM local models | jac model |
| Use Jac from an AI assistant | jac guide · jac mcp |
| Convert between Python, Jac, and JS | jac tool py2jac · jac tool jac2py · jac tool jac2js |
| Clean caches / artifacts | jac clean · jac purge |
Quick Reference#
| Command | Description |
|---|---|
jac run |
Execute a Jac file or .jab, or (no filename) run the current project by its kind (--entry <walker>, --debug) |
jac start |
Start REST API server (use --scale for K8s deployment) |
jac dev |
Live hot-reload dev loop (project-entry resolution + HMR serve) |
jac build |
Type-check gate, then emit one artifact (--as jab\|sealed\|binary\|wheel\|npm\|source\|native; default .jab; --client builds a client shell) |
jac create |
Create new project (--pack to bundle a directory into a .jacpack template) |
jac check |
Type check code (--lint to lint, --lint --fix to auto-fix) |
jac test |
Run tests |
jac fmt |
Format code |
jac precommit |
Run format + check using jac.toml lint settings (installable as a git hook) |
jac clean |
Clean project build artifacts |
jac purge |
Purge global bytecode cache (works even if corrupted) |
jac dot |
Generate graph visualization |
jac browse |
Automate a headless browser over CDP (navigate, click, snapshot, screenshot) |
jac ai |
Launch an interactive Jac coding agent (works with local models, no API key) |
jac code |
Query code structure via the compiler (symbols, uses, walkers, slices) |
jac mcp |
Start the MCP server so AI assistants can use the live Jac compiler |
jac completions |
Generate (and optionally install) shell completions |
jac nacompile |
Compile the native (na) subset to a binary, shared library, or WebAssembly |
jac model |
Manage byLLM local-model weights (Gemma 4, Qwen 3.5, …) |
jac config |
Manage project configuration |
jac scale |
Manage local microservices (status/stop/restart/logs) and platform deployments (status/destroy) |
jac install |
Install project dependencies from jac.toml (--plan to preview the resolved plan), or jac install <pkg> to add packages to jac.toml and install them (--no-save to skip recording) |
jac x |
Run an installed CLI tool (Python console-script or npm tool) under the jac runtime |
jac remove |
Remove packages from project |
jac update |
Update dependencies to latest compatible versions |
jac tool |
Language tools & source transforms (jac2py, py2jac, jac2js, grammar, IR, AST) |
jac guide |
Show curated Jac reference guides |
jac lsp |
Language server |
jac setup |
Setup client build target (jac-client) |
jac db |
Inspect persistence DB, manage rescue aliases, recover quarantined data |
Version Info#
Displays the Jac version and platform, plus documentation and community links:
_
(_) __ _ ___ Jac Language
| |/ _` |/ __|
| | (_| | (__ Version: 0.31.0
_/ |\__,_|\___|
|__/ Platform: Linux x86_64
📚 Documentation: https://docs.jaseci.org
💬 Community: https://discord.gg/6j3QNdtcN6
🐛 Issues: https://github.com/Jaseci-Labs/jaseci/issues
(byLLM, scale, the full-stack client framework, and the MCP server all ship inside the binary, so there is no separate version to report for them.)
Core Commands#
jac run#
Execute a Jac file, a prebuilt .jab artifact, or (with no filename) run the current project.
Note: jac <file> is shorthand for jac run <file> - both work identically.
jac run [-h] [-s] [--show] [-m] [--no-main] [-c] [--no-cache] [-e DIAGNOSTICS] [--profile PROFILE] [--entry ENTRY] [-n NODE] [-r ROOT] [--debug] [filename] [args ...]
| Option | Description | Default |
|---|---|---|
filename |
Jac file (or .jab artifact) to run. Omit to dispatch on the project's jac.toml |
(project) |
-s, --show |
Print the resolved project run-plan (kind, action, equivalent command) without executing | False |
-m, --main |
Treat module as __main__ |
True |
-c, --cache |
Enable compilation cache | True |
-e, --diagnostics |
Diagnostic verbosity: error, all, or none |
error |
--profile |
Configuration profile to load (e.g. prod, staging) | "" |
--entry |
Run a specific entrypoint (function/walker) instead of the module's with entry block |
None |
-n, --node |
Starting node ID (with --entry) |
None |
-r, --root |
Root executor ID (with --entry) |
None |
--debug |
Launch the interactive debugger on the file | False |
args |
Arguments passed to the script (available via sys.argv[1:]) |
Like Python, everything after the filename is passed to the script. Jac flags must come before the filename.
Project-aware run (no filename). Inside a project, a bare jac run resolves the project kind from [project] kind in jac.toml (or infers it from the entry-point's codespace) and does the natural action for that kind: execute runnable kinds (cli, cli-native), serve server kinds (service, web-app, ...), or build artifact kinds (native-binary, native-lib, py-package, js-package). Use jac run --show to preview the plan and the equivalent primitive command (run / start / nacompile / build) without running it. See project kinds and config [project].
Diagnostics modes:
| Mode | Errors | Warnings | Exit code on errors |
|---|---|---|---|
error (default) |
Shown with full details | Silent | 1 |
all |
Shown with full details | Shown | 1 |
none |
Silent | Silent | 0 |
The diagnostics level can also be set in jac.toml under [run].diagnostics. The CLI flag takes precedence over the config file.
Examples:
# Run a file (fails on compile errors by default)
jac run main.jac
# Run the current project per its jac.toml kind (no filename)
jac run
# Preview what the project would run/build, without doing it
jac run --show
# Run without cache (flags before filename)
jac run --no-cache main.jac
# Pass arguments to the script
jac run script.jac arg1 arg2
# Show all diagnostics (errors + warnings)
jac run -e all main.jac
# Suppress all diagnostics
jac run -e none main.jac
# Pass flag-like arguments to the script
jac run script.jac --verbose --output result.txt
Running a specific entrypoint (--entry). By default jac run executes a module's with entry block. Pass --entry <name> to invoke a specific function or walker instead, optionally seeding a starting node (-n/--node) and root (-r/--root). Flags come before the filename; script arguments follow it.
# Invoke a specific walker
jac run --entry my_walker main.jac
# With arguments passed to the entrypoint
jac run --entry process_data main.jac arg1 arg2
# With root and starting node
jac run --entry my_walker -r root_id -n node_id main.jac
Running a prebuilt .jab artifact. jac run app.jab executes a sealed artifact with zero live compilation -- the sealed image (client dist, serve manifest, native binaries) is baked in and hash-verified at load. cli-kind artifacts execute; use jac start to production-serve servable kinds.
Interactive debugger (--debug). Pass --debug to launch the interactive debugger on a file. See VS Code Debugger Setup below for editor integration.
Passing arguments to scripts:
Arguments after the filename are available in the script via sys.argv:
# greet.jac
import sys;
with entry {
name = sys.argv[1] if len(sys.argv) > 1 else "World";
print(f"Hello, {name}!");
}
sys.argv[0] is the script filename (like Python). For scripts that accept
flags, use Python's argparse module:
import argparse;
with entry {
parser = argparse.ArgumentParser();
parser.add_argument("--name", default="World");
args = parser.parse_args();
print(f"Hello, {args.name}!");
}
jac start#
Start a Jac application as an HTTP API server. Use --scale to deploy to Kubernetes (handled by the built-in scale subsystem; the first --scale run resolves its deploy deps via jac install). Use --dev for Hot Module Replacement (HMR) during development; live-reload is powered by the watchdog library bundled in the jac binary, so no extra install is needed.
jac start [-h] [-p PORT] [-m] [--no-main] [-f] [--no-faux] [-d] [--no-dev] [-a API_PORT] [-n] [--no-no_client] [--profile PROFILE] [--client {web,desktop,pwa,mobile}] [--host HOST] [--platform {auto,android,ios}] [--scale] [--no-scale] [-b] [--no-build] [filename]
| Option | Description | Default |
|---|---|---|
filename |
Jac file to serve | main.jac |
-p, --port |
Port number | 8000 |
-m, --main |
Treat as __main__ |
True |
-f, --faux |
Print docs only (no server) | False |
-d, --dev |
Enable HMR (Hot Module Replacement) mode | False |
--api_port |
Separate API port for HMR mode (0=same as port) | 0 |
--no_client |
Skip client bundling/serving (API only) | False |
--profile |
Configuration profile to load (e.g. prod, staging) | "" |
--client |
Client build target (web, desktop, pwa, mobile) |
None |
--host |
Mobile dev (--client mobile --dev) optional live-reload host/IP override |
"" |
--platform |
Mobile start/dev platform selector for --client mobile (auto, android, ios) |
auto |
--scale |
Deploy to Kubernetes (built-in scale subsystem) | False |
-b, --build |
Build Docker image before deploy (with --scale) |
False |
Examples:
# Start with default main.jac on default port
jac start
# Start on custom port
jac start -p 3000
# Start with Hot Module Replacement (development)
jac start --dev
# HMR mode without client bundling (API only)
jac start --dev --no_client
# Mobile dev (Android default)
jac start main.jac --client mobile --dev
# Mobile dev on iOS simulator
jac start main.jac --client mobile --dev --platform ios
# Mobile dev with explicit host override
jac start main.jac --client mobile --dev --host 192.168.1.25
# Deploy to Kubernetes (built-in scale subsystem)
jac start --scale
# Build and deploy to Kubernetes
jac start --scale --build
Note:
- If your project uses a different entry file (e.g.,
app.jac,server.jac), you can specify it explicitly:jac start app.jac
jac dev#
The dedicated live hot-reload development loop. jac dev resolves the project entry point and serves it with Hot Module Replacement (HMR), rebuilding on every save. Unlike jac run / jac start, it always works from live source and never reads a sealed .jab artifact. (jac start --dev still exists for HMR serving; jac dev is the purpose-built loop.)
| Option | Description | Default |
|---|---|---|
-p, --port |
Port to serve on | 8000 |
--api_port |
Separate API port for HMR (0 = same as port) |
0 |
Examples:
jac create#
Initialize a new Jac project with configuration. Creates a project folder with the given name containing the project files, including an AGENTS.md that points AI coding agents at jac guide.
jac create is kind-aware: --kind <kind> scaffolds a project for a specific project kind, stamping [project] kind into jac.toml so the new project's bare jac run dispatches correctly (see jac run). All built-in kinds ship with jaclang -- including web-app, web-static, mobile, and desktop, which previously required the separate jac-client / jac-desktop plugins and now need no extra install.
| Option | Description | Default |
|---|---|---|
name |
Project name (creates folder with this name) | Current directory name |
-f, --force |
Overwrite existing project | False |
-k, --kind |
Project kind: cli, cli-native, native-binary, native-lib, service, service-mesh, py-package, js-package, web-app, web-static, desktop, mobile | cli |
-u, --use |
Custom template: file path or URL to a .jacpack, or a named variant (e.g. jac-shadcn) |
default |
-l, --list_jacpacks |
List available project kinds and named variants | False |
--pack DIR |
Bundle a template directory into a distributable .jacpack file (absorbs jac jacpack pack) |
None |
--pack_output F |
Output path for the bundled .jacpack (with --pack) |
<name>.jacpack |
--kind and --use are mutually exclusive.
Examples:
# Create a basic cli project (creates myapp/ folder)
jac create myapp
cd myapp
# Scaffold a headless API service
jac create myapp --kind service
# Scaffold a natively-compiled binary
jac create myapp --kind native-binary
# Scaffold a full-stack app (built into jaclang core)
jac create myapp --kind web-app
# Scaffold a shadcn-themed full-stack app
jac create myapp --use jac-shadcn
# Create from a local .jacpack file / directory / URL
jac create myapp --use ./my-template.jacpack
jac create myapp --use ./my-template/
jac create myapp --use https://example.com/template.jacpack
# List available project kinds and named variants
jac create --list_jacpacks
# Force overwrite existing
jac create myapp --force
# Create in current directory
jac create
# Bundle a template directory into a .jacpack (absorbs `jac jacpack pack`)
jac create --pack ./my-template
jac create --pack ./my-template --pack_output custom-name.jacpack
See Also: Use jac create --pack to bundle a directory into a distributable .jacpack template, then jac create --use <file>.jacpack to scaffold from it.
jac check#
Type check Jac code for errors. Pass --lint to also run the linter (this absorbs the former jac lint), and --lint --fix to auto-fix lint violations.
| Option | Description | Default |
|---|---|---|
paths |
Files/directories to check | Required |
-e, --print_errs |
Print detailed error messages | True |
-i, --ignore |
Space-separated list of files/folders to ignore | None |
-p, --parse_only |
Only check syntax (skip type checking) | False |
--nowarn |
Suppress warning output | False |
--lint |
Also run the linter and report style/lint violations | False |
--fix |
With --lint, auto-fix lint violations (code corrections) |
False |
Examples:
# Check a file
jac check main.jac
# Check a directory
jac check src/
# Check directory excluding specific folders/files
jac check myproject/ --ignore fixtures tests
# Check excluding multiple patterns
jac check . --ignore node_modules dist __pycache__
# Type-check and lint the current directory
jac check . --lint
# Lint and auto-fix violations
jac check . --lint --fix
# Lint excluding folders
jac check . --lint --ignore fixtures
Errors and warnings are displayed with structured diagnostic codes (e.g., E1030, W2001). You can suppress individual diagnostics inline with # jac:ignore[CODE]:
Lint Rules:
jac check --lint(formerlyjac lint) reports style violations; add--fixto apply auto-fixes. Configure rules via[check.lint]injac.toml. See Lint Rules for the full list with diagnostic codes.
See the full Errors & Warnings reference for all diagnostic codes.
jac test#
Run tests in Jac files.
Note:
jac testruns through pytest bundled in thejacbinary -- there is no separatepytestinstall needed.
| Option | Description | Default |
|---|---|---|
filepath |
Test file to run | None |
-t, --test_name |
Specific test name | None |
-f, --filter |
Filter tests by pattern | None |
-x, --xit |
Exit on first failure | False |
-m, --maxfail |
Max failures before stop | None |
-d, --directory |
Test directory | None |
-v, --verbose |
Verbose output | False |
Examples:
# Run all tests in a file
jac test main.jac
# Run a specific test - spaces in name (quoted)
jac test main.jac -t "my test name"
# Run a specific test - underscores in name
jac test main.jac -t my_test_name
# Run tests in directory
jac test -d tests/
# Run all tests in current directory
jac test
# Stop on first failure
jac test main.jac -x
# Verbose output
jac test main.jac -v
Error handling:
| Mistake | Error shown |
|---|---|
jac test --test_name foo (no file or directory) |
--test_name requires a filepath |
jac test missing.jac (file doesn't exist) |
File not found: 'missing.jac' |
jac test main.jac -t foo bar (unquoted multi-word) |
hint to use quotes |
jac fmt#
Format Jac code according to style guidelines. For auto-linting (code corrections like combining consecutive has statements, converting @staticmethod to static), use jac check --lint --fix instead.
| Option | Description | Default |
|---|---|---|
paths |
Files/directories to format | Required |
-s, --to_screen |
Print to stdout instead of writing | False |
-l, --lintfix |
Also apply auto-lint fixes in the same pass | False |
-c, --check |
Check if files are formatted without modifying them (exit 1 if unformatted) | False |
Examples:
# Preview formatting
jac fmt main.jac -s
# Apply formatting
jac fmt main.jac
# Format entire directory
jac fmt .
# Check formatting without modifying (useful in CI)
jac fmt . --check
Note: For auto-linting (code corrections), use
jac check --lint --fixinstead. Seejac checkabove.Safety: If the formatter detects that comments were displaced (e.g., moved to the end of the file), it emits error
E5051and refuses to save the file. Runjac fmt <file> -sto inspect the output without writing.
jac lint#
Linting has folded into jac check. Run jac check --lint to report violations and jac check --lint --fix to auto-fix them. See jac check above for options and examples.
jac precommit#
Hidden from jac --help (still functional).
Run a pre-commit pipeline (jac fmt --lintfix followed by jac check) using the lint settings from jac.toml. Exits non-zero if any file was reformatted or jac check reported errors, so it can gate a commit. Because formatting honors [check.lint], enabling the opt-in strip-comments / strip-docstrings rules there makes jac precommit apply them too.
| Option | Description | Default |
|---|---|---|
paths |
Files/directories to process | Project root |
-s, --staged |
Only process git-staged .jac files |
False |
-v, --verify |
Verify only: do not rewrite files (exit 1 if unformatted) | False |
-i, --install |
Install a git pre-commit hook that runs this command | False |
Examples:
# Format (lintfix) and check the whole project
jac precommit
# Run on staged .jac files only
jac precommit --staged
# Verify without writing (what the installed git hook runs)
jac precommit --staged --verify
# Install a .git/hooks/pre-commit hook
jac precommit --install
Git hook:
jac precommit --installwrites an executable.git/hooks/pre-committhat runsjac precommit --staged --verify. The hook blocks a commit when staged.jacfiles are unformatted or failjac check; runjac precommit(without--verify) to apply the fixes, then re-stage. If a hook already exists, the installer leaves it untouched and reports the conflict.
jac enter#
Running a specific entrypoint has folded into jac run. Use jac run --entry <walker> <file> (with optional -n/--node and -r/--root). See jac run above.
Visualization & Debug#
jac dot#
Hidden from jac --help (still functional).
Generate DOT graph visualization.
jac dot [-h] [-s SESSION] [-i INITIAL] [-d DEPTH] [-t] [-b] [-e EDGE_LIMIT] [-n NODE_LIMIT] [-o SAVETO] [-p] [-f FORMAT] filename [connection ...]
| Option | Description | Default |
|---|---|---|
filename |
Jac file | Required |
-s, --session |
Session identifier | None |
-i, --initial |
Initial node ID | None |
-d, --depth |
Max traversal depth | -1 (unlimited) |
-t, --traverse |
Enable traversal mode | False |
-c, --connection |
Connection filters | None |
-b, --bfs |
Use BFS traversal | False |
-e, --edge_limit |
Max edges | 512 |
-n, --node_limit |
Max nodes | 512 |
-o, --saveto |
Output file path | None |
-p, --to_screen |
Print to stdout | False |
-f, --format |
Output format | dot |
Examples:
# Generate DOT output
jac dot main.jac -s my_session --to_screen
# Save to file
jac dot main.jac -s my_session --saveto graph.dot
# Limit depth
jac dot main.jac -s my_session -d 3
jac debug#
Interactive debugging has folded into jac run. Use jac run --debug <file> to launch the debugger on a file. See jac run above.
VS Code Debugger Setup#
To use the VS Code debugger with Jac:
- Install the Jac extension from the VS Code Extensions marketplace
- Enable Debug: Allow Breakpoints Everywhere in VS Code Settings (search "breakpoints")
- Create a
launch.jsonvia Run and Debug panel (Ctrl+Shift+D) → "Create a launch.json file" → select "Jac Debug"
The generated .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "jac",
"request": "launch",
"name": "Jac Debug",
"program": "${file}"
}
]
}
Debugger controls: F5 (continue), F10 (step over), F11 (step into), Shift+F11 (step out).
Graph Visualization (jacvis)#
The Jac extension includes live graph visualization:
- Open VS Code Command Palette (Ctrl+Shift+P / Cmd+Shift+P)
- Type
jacvisand select jacvis: Visualize Jaclang Graph - A side panel opens showing your graph structure
Set breakpoints and step through code -- nodes and edges appear in real time as your program builds the graph. Open jacvis before starting the debugger for best results.
For a complete walkthrough, see the Debugging in VS Code Tutorial.
Browser Automation#
jac browse#
Hidden from jac --help (still functional).
Drive a headless Chrome/Chromium over the Chrome DevTools Protocol (CDP): navigate, interact with elements, inspect the page, and capture screenshots. The driver is zero-dependency -- it speaks CDP over a hand-rolled WebSocket, so no Playwright or Selenium install is required. Interactions use real CDP input events (trusted clicks and keystrokes), not JavaScript injection.
| Option | Description | Default |
|---|---|---|
action |
The action to perform (see table below) | Required |
args |
Action-specific arguments (selector, url, text, path, ...) | [] |
-s, --session |
Session name; each session is an isolated browser instance | default |
--viewport |
Browser window size as WIDTHxHEIGHT (applied at open) |
1280x720 |
Actions:
| Action | Arguments | Description |
|---|---|---|
open |
[url] |
Launch a headless browser, optionally navigating to a URL |
navigate / goto |
<url> |
Navigate to a URL (adds https:// if no scheme; waits for load) |
click |
<selector\|@ref> |
Real mouse click at the element center |
type |
<selector> <text> |
Focus an element and type text as per-character key events |
fill |
<selector> <text> |
Clear a field and insert text in one step |
press |
<key> |
Press a named key or character (Enter, Tab, Ctrl+A, ...) |
get |
url\|title\|text [selector] |
Read a page property (get text needs a selector) |
eval |
<expression> |
Run JavaScript and return the result as JSON |
wait |
<ms\|selector> |
Sleep for a duration, or wait until a selector is actionable |
scroll |
<up\|down\|left\|right\|top\|bottom\|selector> [px] |
Scroll the page, or scroll an element into view |
console |
[--clear] |
Print buffered console/log/exception output since page load |
snapshot |
Print the accessibility tree with @e1/@e2 refs on interactive nodes |
|
screenshot |
[path] |
Capture the page as PNG (defaults to the cache directory) |
state |
save\|load <path> |
Save or restore cookies + localStorage as JSON |
sessions |
List known sessions with their PID, port, and liveness | |
close |
Terminate the browser and clear session state |
Outputs are printed raw so they pipe cleanly; JSON-valued results (eval, get) are serialized. Errors go to stderr and return exit code 1.
Sessions and persistence:
A launched browser stays alive between CLI calls -- each invocation reconnects to the running Chrome recorded under ~/.cache/jacbrowser/. Use -s to run multiple isolated browsers side by side. Element refs from snapshot (the @e1 handles) persist across calls, so you can snapshot once and act on refs in later commands.
Refs vs. selectors:
click, type, and fill accept either a CSS selector (#email, button.primary) or an @ref produced by snapshot. Both auto-wait until the element is actionable: it is scrolled into view and must be visible, position-stable, inside the viewport, and the top element at the click point. If any of those cannot be satisfied (e.g. the point lands offscreen or another element covers the target), the command fails with an error instead of silently doing nothing.
Environment variables:
| Variable | Description |
|---|---|
JACBROWSER_SESSION |
Default session name (overridden by -s) |
JACBROWSER_CHROME |
Path to the Chrome/Chromium binary |
JACBROWSER_CACHE |
Cache directory for session, ref, and screenshot files |
Examples:
# Launch a browser and open a page
jac browse open example.com
# Read page properties
jac browse get title
jac browse get text 'h1'
# Inspect the accessibility tree -> assigns @e1, @e2, ... to interactive nodes
jac browse snapshot
# @e1 link "Home"
# @e5 button "Send Message"
# Interact by ref (from snapshot) or by CSS selector
jac browse click @e5
jac browse fill '#email' you@example.com
jac browse press Enter
# Run JavaScript
jac browse eval "document.querySelectorAll('a').length"
# Wait for an app to mount, then read its console output
jac browse wait '#app'
jac browse console
# [log] booted in 312ms
# [warning] Each child in a list should have a unique "key" prop.
# Scroll for screenshot framing
jac browse scroll down
jac browse scroll '#pricing'
# Capture a screenshot
jac browse screenshot ./page.png
# Save and restore an authenticated session
jac browse state save auth.json
jac browse state load auth.json
# Work in an isolated session
jac browse -s work open example.com
jac browse sessions
# * work pid=12345 port=9222 [alive]
# Close the browser
jac browse close
A typical end-to-end flow chains these together:
jac browse open example.com
jac browse snapshot # find the @ref of the field and button
jac browse fill @e3 "hello"
jac browse click @e5
jac browse screenshot result.png
jac browse close
AI-Assisted Development#
Three commands make Jac projects legible to (and drivable by) AI agents -- including Jac's own built-in coding agent. See also Agent Skills & MCP for the workflow overview.
jac ai#
Launch an interactive Jac coding agent in your project. Runs against your configured byLLM model -- including fully local models, so it works without an API key.
| Option | Description | Default |
|---|---|---|
prompt |
Optional one-shot request; omit for an interactive session | interactive |
-m, --model |
Model to use, e.g. local:gemma-4-e4b or openai/gpt-4o |
from jac.toml |
-n, --n_ctx |
Context-window size for local models (tokens) | model default |
-s, --safe |
Confirm every file write and code execution | off |
-q, --quiet |
Compact output: hide live reasoning, timings, and step detail | off |
-u, --ui |
Open the agent in a web UI with a live phase-graph visualizer | off |
Examples:
# Interactive session using the project's configured model
jac ai
# One-shot request
jac ai "add a walker that lists all Todo nodes"
# Fully local, no API key
jac ai -m local:gemma-4-e4b
# Web UI with live phase-graph visualization
jac ai --ui
jac code#
Query code structure via the compiler -- grep's structural successor. Returns JSON by default (for tools and agents); pass --text for human-readable output.
| Action | Description |
|---|---|
symbol <name> |
Definitions and use-sites of a symbol |
uses <name> |
All reads/writes of a symbol |
map [kind] |
Structural overview of nodes, walkers, edges, objs (optionally filtered by kind) |
walkers <node-type> |
Walkers whose traversals visit a given node type |
slice <name> [-d N] |
Typed neighbourhood of a symbol to depth N (built for prompt assembly) |
diag [file] |
Structured compiler errors and warnings |
Examples:
jac code map # what's in this project?
jac code symbol Todo --text # where is Todo defined and used?
jac code walkers Todo # which walkers touch Todo nodes?
jac code slice add_todo -d 2 # everything an agent needs to edit add_todo
jac mcp#
Start the Model Context Protocol server so any MCP client (Claude Code, Claude Desktop, Cursor, ...) can lint, transpile, run, and explain Jac code through the live compiler.
jac mcp [-t stdio|sse|streamable-http] [-p PORT] [--host HOST] [--mode lite|standard|full] [--inspect]
| Option | Description | Default |
|---|---|---|
-t, --transport |
Transport protocol | stdio |
-p, --port |
Port for SSE/HTTP transports | 3001 |
--host |
Bind address for SSE/HTTP transports | 127.0.0.1 |
--mode |
Tool/prompt exposure level for the connecting model | full |
--inspect |
Print inventory of resources, tools, and prompts, then exit | off |
See the MCP Server Reference for the full tool catalog and per-client setup snippets.
Local Model Cache#
The jac model command manages the on-disk cache of bundled local LLM weights used by byLLM's local:<alias> route. Weights live under ~/.cache/jac/models/<alias>/ (override with JAC_MODELS_DIR). See Built-in Local Models in the byLLM reference for the full backend.
jac model#
Manage byLLM local-model weights (Gemma 4, Qwen 3.5, …).
| Action | Description |
|---|---|
list |
Show bundled aliases and download status (default). |
pull <alias> |
Download GGUF weights for an alias from HuggingFace. |
rm <alias> |
Delete cached weights for an alias. Aliases: remove, delete. |
| Argument | Description | Default |
|---|---|---|
action |
One of list, pull, rm. |
list |
alias |
Local-model alias (e.g. gemma-4-e4b). Required for pull / rm; omit for list. |
"" |
Examples:
# Show bundled aliases and which are cached locally
jac model
# Download Gemma 4 E4B weights (~5 GB) ahead of first use
jac model pull gemma-4-e4b
# Free disk by removing cached weights
jac model rm gemma-4-e4b
Sample output of jac model:
Local model cache: /home/you/.cache/jac/models
ALIAS SIZE STATUS DESCRIPTION
---------------------- --------- ------------ ----------------------------------------
gemma-4-e2b ~2500 MB not cached Google Gemma 4 E2B (smaller, faster)
gemma-4-e4b 4.6 GB downloaded Google Gemma 4 E4B (instruction-tuned, Q4_K_M)
qwen3.5-4b ~2800 MB not cached Alibaba Qwen 3.5 4B (instruction-tuned, Q4_K_M)
Note: In CI and other non-TTY contexts, the runtime will not prompt to download. Either
jac model pull <alias>ahead of time, or setBYLLM_AUTO_DOWNLOAD=1(or[byllm.local].auto_download = trueinjac.toml) to allow silent first-run downloads.
Database Operations#
The jac db command group inspects the live persistence backend, manages DB-resident rescue aliases, and recovers quarantined anchors. It works against any PersistentMemory backend -- SqliteMemory (default), the built-in scale MongoBackend, or any custom backend that implements the interface -- through the same set of subcommands.
For the architectural background (fingerprints, drift detection, quarantine philosophy, alias decorator), see Persistence & Schema Migration.
Backend dispatch#
jac db always operates on the backend the user's app is configured to use:
- Pass
--app PATHto point at the entry.jacfile. - Or run the command from the app's directory; if there's exactly one
.jacin the current directory, it's picked automatically.
The command imports the user's app to set up the runtime context, then talks to whatever PersistentMemory backend the configuration installs -- SQLite locally, Mongo in production, etc. There is no separate mode for each backend.
# Explicit
jac db inspect --app path/to/app.jac
# Implicit when there's one .jac in cwd
cd my_app/
jac db inspect
jac db inspect#
Print a one-line summary of the live persistence backend plus per-archetype count tables for both anchors and quarantine.
Output:
Jac DB: /tmp/myapp/.jac/data/anchor_store.db
[INFO] format_version=1 anchors=5 quarantined=0 aliases=0
Anchors
┏━━━━━━━━━━━━━┳━━━━━━━┓
┃ arch_type ┃ count ┃
┡━━━━━━━━━━━━━╇━━━━━━━┩
│ Person │ 2 │
│ GenericEdge │ 2 │
│ Root │ 1 │
└─────────────┴───────┘
The summary line covers: storage format version, total live anchor count, total quarantined count, and total alias count. Quarantine + Anchors tables only print when non-empty.
jac db quarantine list#
List the most recent quarantined anchors with their class, fingerprint, error, and timestamp.
Sorted newest first. UUID columns are truncated to a recognizable prefix; pass any unique prefix to quarantine show or recover.
jac db quarantine show \<id-prefix>#
Dump one quarantined row in full (parsed JSON), including the original data payload -- useful for understanding why a row failed to load.
A unique prefix is sufficient. If the prefix is ambiguous, the command tells you and asks for a longer prefix.
jac db alias add / list / remove#
DB-resident rescue aliases. Persisted in an aliases table (SQLite) or <collection>_aliases companion collection (Mongo, e.g. _anchors_aliases) and merged into the in-process Serializer._aliases map at backend connect time. Survives across process restarts; affects every consumer of that database.
# List current aliases.
jac db alias list
# Register a rescue alias for a class rename / module move.
jac db alias add "old.module.LegacyName" "new.module.NewName"
# Remove one.
jac db alias remove "old.module.LegacyName"
Both arguments to alias add are fully-qualified module.ClassName strings -- the module part is what would have appeared in the stored row's arch_module field. For files run via jac run app.jac, the module is __main__.
When to use this vs. the decorator. The
@archetype_aliasdecorator is the normal path: it's code-resident, travels through git, applies wherever the code runs.jac db alias addis the rescue path: emergency recovery in production without a code deploy. Decorator first, CLI as the safety net.
jac db recover \<id-prefix>#
Re-attempt deserialization on one quarantined row. On success, the row is moved back to the live anchors collection and re-stamped with the live class's identity + fingerprint so subsequent reads bypass alias resolution and drift detection.
Recovery only succeeds when the user's archetype classes (and any @archetype_alias decorators) are registered, so the user app must be discoverable -- via --app PATH or the cwd auto-discovery described above. Without it, every quarantined row will be reported as class X.Y still unresolvable.
jac db recover-all#
Batch variant. Re-attempts every quarantined row and reports counts, plus a per-row reason for whatever still can't be recovered.
Typical output:
Or, when some rows are still stuck (often because the class involved isn't covered by any alias yet):
✔ Recovered 3 of 5 quarantined rows.
[WARN] 2 rows still quarantined.
Still quarantined
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ id ┃ reason ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ d44e2c7a… │ class oldmod.GoneAway still unresolvable │
│ 902b14ee… │ deserialize raised: ValueError: bad enum value │
└───────────┴─────────────────────────────────────────────────┘
jac db fsck#
Scan the backend for referential-integrity violations: dangling references (a node citing an edge document that no longer exists, or an edge citing a missing endpoint node) and orphans (an unreferenced edge, or an edgeless non-root node). Read-only by default, so it is safe to run as a monitoring probe.
Output:
Jac DB fsck: /tmp/myapp/.jac/data/app.db
[INFO] dangling refs : 19 (8 document(s) cite a missing referent)
[INFO] orphan edges : 3
[INFO] orphan nodes : 11
[INFO] Run `jac db fsck repair` to heal danglers and collect orphans.
Pass repair to act on the findings. Dangling citations are pruned and each missing referent is filed into the quarantine store under the DANGLING_REF reason code (visible via jac db quarantine list); orphans are collected. On SQLite the whole repair runs inside one BEGIN IMMEDIATE transaction, so a fsck repair is itself crash-atomic.
Output:
✔ repaired: pruned 19 citation(s), quarantined 19 dangler(s) under DANGLING_REF, collected 14 orphan(s).
A clean database reports nothing to do:
Most danglers are healed automatically the first time a traversal touches them (see Persistence → Dangling references).
jac db fsckis the offline backstop: it heals references no live request has hit yet, and surfaces orphan garbage for collection.
jac db schema rules#
List every registered __jac_schema__ drift rule along with the active JAC_SCHEMA_REPAIR mode. The app is imported first (same --app / cwd discovery as the other subcommands), which is what runs the __jac_schema__ hooks and registers the rules.
Output:
Registered schema drift rules
[INFO] JAC_SCHEMA_REPAIR mode: repair
Rules
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
┃ archetype ┃ rule ┃ detail ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩
│ __main__.User │ was │ myapp.models.OldUser │
│ __main__.User │ alias │ username -> name │
│ __main__.User │ drop │ legacy_bio │
│ __main__.User │ upgrade │ split_tags │
└─────────────────┴─────────┴───────────────────────┘
Useful as a pre-deploy sanity check: it confirms which renames, drops, and upgrade callbacks will apply when old documents load, and which repair mode the process will run under.
Typical rescue workflow#
# 1. Discover what's quarantined.
jac db inspect --app app.jac
jac db quarantine list --app app.jac
# 2. Drill into one row to understand why.
jac db quarantine show <prefix> --app app.jac
# 3. If it's a class rename: register an alias.
jac db alias add "__main__.OldName" "__main__.NewName"
# 4. Re-attempt every stuck row.
jac db recover-all --app app.jac
# 5. Confirm.
jac db inspect --app app.jac
After step 5 the quarantine count should be zero (or list only rows that genuinely need a different fix -- type changes too aggressive for the coercion table, etc.).
Configuration Management#
jac config#
View and modify project configuration settings in jac.toml.
| Action | Description |
|---|---|
show |
Display explicitly set configuration values (default) |
list |
Display all settings including defaults |
get |
Get a specific setting value |
set |
Set a configuration value |
unset |
Remove a configuration value (revert to default) |
path |
Show path to config file |
groups |
List available configuration groups |
| Option | Description | Default |
|---|---|---|
key |
Configuration key (positional, e.g., project.name) |
None |
value |
Value to set (positional) | None |
-g, --group |
Filter by configuration group | None |
-o, --output |
Output format (table, json, toml) |
table |
Configuration Groups:
project- Project metadata (name, version, description)run- Runtime settings (cache, session)build- Build settings (typecheck, output directory)test- Test settings (verbose, filters)serve- Server settings (port, host)format- Formatting optionscheck- Type checking optionsdot- Graph visualization settingscache- Cache configurationenvironment- Environment variables
Examples:
# Show explicitly set configuration
jac config show
# Show all settings including defaults
jac config list
# Show settings for a specific group
jac config show -g project
# Get a specific value
jac config get project.name
# Set a value
jac config set project.version "2.0.0"
# Remove a value (revert to default)
jac config unset run.cache
# Show config file path
jac config path
# List available groups
jac config groups
# Output as JSON
jac config show -o json
# Output as TOML
jac config list -o toml
Deployment (scale)#
jac start --scale#
Deploy to Kubernetes using the built-in scale subsystem. See the jac start command above for full options.
jac scale#
jac scale <action> is the unified noun for scale operations. It has two modes depending on the argument:
- Local microservices --
jac scale <action> [name]manages locally-running services:status,stop,restart,logs. - Platform deployment -- given a
.jacapp file,jac scale <action> <file.jac> [--target T] [--component C]operates on a platform deployment:status(health of each component) anddestroy(tear the deployment down). This absorbs the former top-leveljac status/jac destroyverbs.
To deploy in the first place, run jac start --scale (see jac start above).
| Option | Description | Default |
|---|---|---|
action |
status, stop, restart, logs (local) or status, destroy (platform, with a .jac file) |
Required |
name / file |
Local service name, or the path to the .jac app file for platform actions |
None |
--target |
Deployment target platform (platform actions) | kubernetes |
--component |
Restrict the action to a single component (platform actions) | None |
Platform status output (jac scale status app.jac):
Jac Scale - Deployment Status
App: my-app Namespace: default
┌───────────────────┬────────────────────────┬───────┐
│ Component │ Status │ Pods │
├───────────────────┼────────────────────────┼───────┤
│ Jaseci App │ ● Running │ 1/1 │
│ Redis │ ● Running │ 1/1 │
│ MongoDB │ ● Running │ 1/1 │
│ Prometheus │ ● Running │ 1/1 │
│ Grafana │ ● Running │ 1/1 │
└───────────────────┴────────────────────────┴───────┘
Service URLs
────────────────────────────────────────────
Application: http://localhost:30001
Grafana: http://localhost:30003
Status indicators:
| Symbol | Meaning |
|---|---|
● Running |
All pods healthy and ready |
◑ Degraded |
Some pods ready, but not all |
⟳ Pending |
Pods are starting up |
↺ Restarting |
Pods are crash-looping |
✗ Failed |
Component has failed |
○ Not Deployed |
Component is not present in the cluster |
Examples:
# Local microservices
jac scale status
jac scale logs my-service
jac scale restart my-service
jac scale stop my-service
# Platform deployment status of a .jac app
jac scale status app.jac
jac scale status app.jac --target kubernetes
# Tear down a platform deployment
jac scale destroy app.jac
Package Management#
jac install#
jac install has two modes depending on whether package names are passed. Pass --plan (optionally with --json) to preview the resolved dependency plan without installing anything -- this absorbs the former jac deps.
No-argument mode - sync the project environment to jac.toml. Installs all Python (pip), git, and npm dependencies in one command. Creates or validates the project virtual environment at .jac/venv/. Requires a jac.toml in the current (or a parent) directory.
Package mode - jac install <pkg> [pkg ...] adds one or more packages to jac.toml and installs them into the project's virtual environment at .jac/venv/ -- this absorbs the former jac add. When no version is specified, the package is installed unconstrained and the installed version is queried to record a ~=X.Y compatible-release spec in jac.toml. Pass --no-save to install without reading or modifying jac.toml (the Jac-native equivalent of pip install <pkg>), or --global to install into the binary's own jac-owned site instead -- a location that is on sys.path from any project, for a tool you install once and use everywhere (--global never records to jac.toml and works outside a project). Either target is fully self-contained: the bundled pip and the binary's own site, never the host Python or its site-packages.
Ecosystem flags select what kind of dependency is recorded: --dev records under [dev-dependencies], --git <url> installs from a git repository and records under [dependencies.git], --npm adds a client-side npm package (with no names, installs all npm deps from jac.toml), and --shadcn installs shadcn UI components from the bundled offline registry.
Recorded vs ad-hoc installs
jac install <pkg>jac install <pkg> --no-savejac install <pkg> --globalTarget Project .jac/venv/Project .jac/venv/Binary's global site Updates jac.tomlYes No No Requires a project Yes Yes No Importable from other projects No No Yes The default records the dependency in
jac.tomlfor reproducible installs. Use--no-savefor an ad-hoc package scoped to this project, and--globalfor a tool you want available everywhere.
jac install [-h] [packages ...] [-e PATH] [-d] [-x group [group ...]] [--no-save]
[-g GIT] [--npm] [--shadcn] [-v] [--force-reinstall] [--no-cache-dir]
[--pre] [--dry-run] [--no-deps] [--quiet] [--prefer-binary]
[--global] [--plan] [--json]
| Option | Description | Default |
|---|---|---|
packages |
Package(s) to add to jac.toml and install into the project's .jac/venv (recording is skipped with --no-save, --global, or --dry-run). |
[] |
-e, --editable PATH |
Install the Jac package at PATH in editable mode (analogous to pip install -e). The target package's own jac.toml (read from PATH) supplies its dependencies; the package and those deps are linked/installed into the current project's .jac/venv (or the global site with --global). Cannot be combined with packages. Repeatable. |
None |
-d, --dev |
Include dev dependencies (no-arg mode), or record named package(s) under [dev-dependencies] |
False |
-x, --extras |
Install one or more [optional-dependencies] groups (no-arg mode only) |
[] |
--no-save |
Install named package(s) without recording them in jac.toml |
False |
-g, --git URL |
Git repository URL to install and record under [dependencies.git] |
None |
--npm |
Install npm (client-side) package(s); with no names, install all npm deps from jac.toml |
False |
--shadcn |
Install shadcn UI component(s) from the bundled registry | False |
-v, --verbose |
Show detailed output | False |
--force-reinstall |
Reinstall all packages even if they are already up-to-date | False |
--no-cache-dir |
Disable the pip download cache | False |
--pre |
Include pre-release and development versions | False |
--dry-run |
Show what would be installed without actually installing anything | False |
--no-deps |
Don't install package dependencies | False |
--quiet |
Suppress pip output | False |
--prefer-binary |
Prefer pre-built wheels over source distributions | False |
--global |
Install into the binary's own jac-owned site (importable from any project), not the project's .jac/venv. Works outside a project. |
False |
--plan |
Resolve and print the dependency plan without installing anything (absorbs the former jac deps) |
False |
--json |
With --plan, emit the plan as machine-readable JSON |
False |
Examples:
# Add a package to jac.toml and install it (records ~=2.32 based on installed version)
jac install requests
# Add multiple packages, with version constraints
jac install "numpy>=1.24" pandas scipy
# Add as a dev dependency
jac install pytest --dev
# Install without recording in jac.toml (ad-hoc, like pip install)
jac install numpy --no-save
# Install and record a git dependency
jac install --git https://github.com/user/package.git
# Add npm (client-side) packages
jac install --npm react
# Add shadcn UI components (offline, bundled registry)
jac install --shadcn button card
# Install all dependencies from jac.toml (no-arg mode)
jac install
# Install including dev dependencies (no-arg mode)
jac install --dev
# Install optional dependency groups defined in jac.toml (no-arg mode)
jac install --extras data monitoring
# Editable install of the current package (no-arg mode)
jac install -e .
# Editable install of a package living elsewhere into the current project's venv
jac install -e /path/to/lib
# Editable install with all optional dependency groups
jac install -e . --extras all
# Install a tool into the global site, importable from any project
jac install -e ./jac-byllm --global
# Install with verbose output
jac install -v
# Reinstall all packages from scratch (ignores cached state)
jac install --force-reinstall
# Preview what would be installed without doing it
jac install --dry-run
# Install without using pip's download cache
jac install --no-cache-dir
# Preview the resolved dependency plan without installing (formerly `jac deps`)
jac install --plan
jac install --plan --json
For private npm packages from custom registries (e.g., GitHub Packages), configure scoped registries and auth tokens in jac.toml under [client.npm]. See NPM Registry Configuration.
Optional groups are declared under [optional-dependencies] in jac.toml. See the Configuration Reference.
Self-contained installs:
jac install(andjac remove,jac update) run through thejacbinary's own bundled pip against the project's.jac/venv. No system Python,pip, or external package manager (such asuv) is required or consulted -- behaviour is identical regardless of what is installed on the host.Note: The pip passthrough flags (
--force-reinstall,--no-cache-dir,--pre,--no-deps,--quiet,--prefer-binary) are forwarded directly to pip. Usejac updateto upgrade packages to their latest versions.Running installed tools: packages that ship a command-line tool (a Python console-script, or an npm tool in
node_modules/.bin) are runnable withjac x <tool>-- no need to put anything on your shellPATH.
jac x#
jac x <tool> runs an installed command-line tool under the jac runtime -- the Jac-native, cross-ecosystem equivalent of pipx run / npx. It resolves a Python console-script (from an installed package's entry points) or an npm tool (from node_modules/.bin) and runs it. Python tools execute in-process under the bundled interpreter; npm tools run through the jac-managed bun runtime -- so neither a system Python nor a system Node is required.
The CLI tools you install with jac install are therefore runnable without putting anything on your shell PATH, and resolution is project-aware: inside a project, a tool installed in that project shadows a global one of the same name. jac x <name> also runs custom scripts defined in the [scripts] section of jac.toml -- this absorbs the former jac script. A bare jac x (or jac x --list) lists everything runnable.
Resolution order (first match wins). By default
jac xsearches tiers locality-first:
- the project's Python venv (
.jac/venv),- the project's npm tools (
.jac/client/node_modules/.bin),- the jac-owned global Python site (where
jac install --globalinstalls).
--globalrestricts the search to the global Python site;--noderestricts it to the project's npm tools. Each tool's tier is shown byjac x --list.
| Option | Description | Default |
|---|---|---|
name |
Tool/command name to run. Omit (or pass --list) to list the available tools. |
"" |
args |
Everything after name is forwarded verbatim to the tool. Flags for jac x itself must come before name. |
[] |
-g, --global |
Resolve from the jac-owned global Python site only, ignoring the project venv and npm tools. | False |
-n, --node |
Resolve from the project's npm tools (node_modules/.bin) only. |
False |
-l, --list_tools |
List the runnable tools across all tiers (each tagged with its tier), then exit. A bare jac x does the same. |
False |
Examples:
# Run a Python tool installed in the project (e.g. huggingface_hub's `hf`)
jac x hf download gpt2
# Run an installed formatter on the current directory
jac x black .
# Run a project npm tool (node_modules/.bin) through bun -- no system Node needed
jac x eslint .
jac x vite build
# Force a specific tier when a name exists in more than one
jac x --global hf whoami # the global-site Python copy
jac x --node vite build # the project's npm copy
# List everything runnable here, tagged by tier ([project] / [node] / [global])
jac x --list
No system Python or Node required. Python tools run in-process under the
jacbinary's bundled interpreter; npm tools run via the jac-managedbun(resolved from the systemPATH, the project's.jac/bin/bun, or auto-downloaded), which executes thenode_modules/.binshims directly. Arguments after the tool name -- including flags like--help-- pass straight through, and the tool's exit code becomesjac x's exit code.
jac remove#
Remove packages from your project's dependencies.
| Option | Description | Default |
|---|---|---|
packages |
Package names to remove | None |
-d, --dev |
Remove from dev dependencies | False |
With the built-in client framework:
| Option | Description | Default |
|---|---|---|
--npm |
Remove client-side (npm) package | False |
Examples:
# Remove a package
jac remove requests
# Remove multiple packages
jac remove numpy pandas
# Remove dev dependency
jac remove pytest --dev
# Remove npm package (client framework built into jaclang core)
jac remove react --npm
jac update#
Update dependencies to their latest compatible versions. For each updated package, the installed version is queried and a ~=X.Y compatible-release spec is written back to jac.toml.
| Option | Description | Default |
|---|---|---|
packages |
Specific packages to update (all if empty) | None |
-d, --dev |
Include dev dependencies | False |
-v, --verbose |
Show detailed output | False |
Examples:
# Update all dependencies to latest compatible versions
jac update
# Update a specific package
jac update requests
# Update all including dev dependencies
jac update --dev
jac clean#
Clean project build artifacts from the .jac/ directory.
| Option | Description | Default |
|---|---|---|
-a, --all |
Clean all .jac artifacts (data, cache, packages, client) |
False |
-d, --data |
Clean data directory (.jac/data) |
False |
-c, --cache |
Clean cache directory (.jac/cache) |
False |
-p, --packages |
Clean virtual environment (.jac/venv) |
False |
-f, --force |
Force clean without confirmation prompt | False |
By default (no flags), jac clean removes only the data directory (.jac/data).
Examples:
# Clean data directory (default)
jac clean
# Clean all build artifacts
jac clean --all
# Clean only cache
jac clean --cache
# Clean data and cache directories
jac clean --data --cache
# Force clean without confirmation
jac clean --all --force
💡 Troubleshooting Tip: If you encounter unexpected syntax errors, "NodeAnchor is not a valid reference" errors, or other strange behavior after modifying your code, try clearing the cache with
jac clean --cache(rm -rf .jac) orjac purge. Stale bytecode can cause issues when source files change.
jac purge#
Purge the global bytecode cache. Works even when the cache is corrupted.
When to use:
- After upgrading Jaseci packages
- When encountering cache-related errors (
jaclang.pycore,NodeAnchor, etc.) - When setup stalls during first-time compilation
| Command | Scope |
|---|---|
jac clean --cache |
Local project (.jac/cache/) |
jac purge |
Global system cache |
jac build#
Run the whole-program type-check gate (fail-closed; reuses jac check), then emit one artifact. By default jac build produces a .jab -- a single self-describing sealed app bundle. Use --as to select a different projection. jac build is now the single front door that the former jac bundle (wheel/npm), jac eject (source), and project-level jac nacompile (native/binary) folded into.
jac build [-h] [--as {jab,sealed,binary,wheel,npm,source,native}] [-o OUTPUT] [-n] [-c]
[--client {web,pwa,static,mobile,desktop,cef,react-native}] [-p PLATFORM] [filename]
| Option | Description | Default |
|---|---|---|
filename |
Entry .jac file (omit to use the project entry) |
(project) |
--as |
Artifact projection: jab, sealed, binary, wheel, npm, source, native |
jab |
-o, --output |
Output directory | dist |
-n, --no_typecheck |
Skip the type-check gate | False |
-c, --check_only |
Run the gate only; emit nothing | False |
--client |
Build a client shell (web, pwa, static, mobile, desktop, cef, react-native) |
None |
-p, --platform |
Platform selector for --client builds |
Current platform |
Projections (--as):
--as |
Emits | Replaces |
|---|---|---|
jab (default) |
A sealed .jab app bundle (deterministic tar.gz of the sealed image) |
-- |
sealed |
The sealed image as an unpacked directory (exactly what a .jab archives) |
-- |
binary |
A self-contained app executable: a copy of the jac launcher with your sealed .jab appended as an overlay |
-- |
wheel |
A pip install-ready Python wheel in dist/ |
jac bundle |
npm |
An npm tarball | jac bundle --target npm |
source |
An editable FastAPI + JavaScript source tree (zero .jac files) |
jac eject |
native |
A standalone native binary | project-level jac nacompile |
The type-check gate. jac build refuses to emit an artifact if the program fails the whole-program type check. Pass --no_typecheck to skip the gate, or --check_only to run the gate and emit nothing (useful in CI).
The .jab artifact. A .jab is a single self-describing sealed app bundle: client dist, serve manifest, and native binaries are baked in and hash-verified at load, so jac run app.jab / jac start app.jab execute or serve it with zero live compilation. It is kind-aware: cli kinds execute, servable kinds production-serve, and attachable packages refuse to run standalone.
Shipping an executable: binary vs native. These two projections solve different problems and are easy to confuse:
--as binarypackages any app (walkers, Python imports, a full web client) into one executable by appending the sealed.jabonto a copy of the runningjaclauncher. The file carries the full runtime and boots through the same path asjac run app.jab, with zero live compilation. Because it embeds the runtime, the artifact is large but complete: hand it to a machine with no Jac, Python, or Node installed. The entry point resolves the same wayjac rundoes (amain.jacor the[project]entry-point injac.toml); an entry-less package is rejected at build time.--as nativeAOT-compiles the restrictednasubset through LLVM into a small, dependency-free binary (no walkers, no async, no Python imports). Reach for it when your program fits the native pathway and you want the smallest possible artifact.
Building a wheel (publish to PyPI):
# Type-check, then build a wheel into dist/
jac build --as wheel
# Build to a custom directory
jac build --as wheel -o /tmp/wheels
After a wheel build the tool prints Upload with: twine upload dist/*. There is no --publish flag; upload with twine:
Building an npm tarball:
To produce both a wheel and an npm tarball, run both commands (there is no single "all" projection):
Building a native binary or editable source tree:
# Standalone native binary (project-level; see `jac nacompile` for file-level .na.jac)
jac build --as native
# Editable FastAPI + JavaScript source tree (formerly `jac eject`)
jac build --as source -o /tmp/myapp-out
Building a client shell:
# Build a desktop client shell
jac build --client desktop
# Build a mobile client shell for a platform
jac build --client mobile -p android
Note: The
[project.include]/**/*.jircollection settings injac.tomlgovern whatjac build --as wheelcollects (this was formerlyjac bundle). See the Configuration Reference for the full set of publishing fields (name,version,license,readme,authors,[project.include], and more). For the full end-to-end publishing workflow, see the Publishing Packages guide.
Template Management#
jac jacpack#
Template packing has folded into jac create. Bundle a template directory into a distributable .jacpack with jac create --pack <dir> (--pack_output F for a custom path), and list available templates/kinds with jac create --list_jacpacks. The .jacpack concept below is unchanged.
# Bundle a template directory into a .jacpack (formerly `jac jacpack pack`)
jac create --pack <dir> [--pack_output out.jacpack]
# List available project kinds and named variants (formerly `jac jacpack list`)
jac create --list_jacpacks
Template Directory Structure:
A template directory should contain:
jac.toml- Project config with a[jacpack]section for metadata- Template files (
.jac,.md, etc.) with{{name}}placeholders
To make any Jac project packable as a template, simply add a [jacpack] section to your jac.toml. All other sections become the config for created projects.
Example jac.toml for a template:
# Standard project config (becomes the created project's jac.toml)
[project]
name = "{{name}}"
version = "0.1.0"
entry-point = "main.jac"
[dependencies]
# Jacpac metadata - used when packing, stripped from created projects
[jacpack]
name = "mytemplate"
description = "My custom project template"
jaclang = "0.9.0" # minimum compatible jac binary (host) runtime, not a PyPI dependency
[[jacpack.plugins]]
name = "jac-client"
version = "0.1.0"
[jacpack.options]
directories = [".jac"]
root_gitignore_entries = [".jac/"]
Examples:
# List available templates / project kinds
jac create --list_jacpacks
# Bundle a template directory
jac create --pack ./my-template
# Bundle with custom output path
jac create --pack ./my-template --pack_output custom-name.jacpack
Using Templates with jac create:
Once a template is registered, use it with the --use flag:
jac eject#
Ejecting has folded into jac build. Use jac build --as source to compile a Jac project into a runnable FastAPI + JavaScript source tree with zero .jac files -- each walker becomes a Python FastAPI route and the .cl.jac UI compiles to JavaScript on Vite. Use it when you want an editable FastAPI/JS codebase you can extend and deploy without writing Jac.
# Eject the current project (formerly `jac eject`)
jac build --as source
# Eject to a chosen output directory
jac build --as source -o /tmp/myapp-out
What gets emitted
- Server-side
.sv.jac(and the server scope of plain.jac) modules become Python, keeping their realjaclang.jac0core.jaclibimports; client-side.cl.jacmodules become JavaScript. A generatedbackend/main.pyFastAPI app exposes onePOST /walker/<Name>per walker,POST /function/<name>per function, plus/user/registerand/user/login(:pubwalkers/functions are open; the rest require a bearer token). - A project with no client
appcomponent ejects backend-only (thefrontend/scaffold is skipped)..impl.jac/.test.jacfiles are skipped.
Persistence. By default the object graph persists to a local SQLite file via the jaclang runtime. To persist through SQLAlchemy instead (so the same backend can target Postgres/MySQL), set driver = "sqlalchemy" under [eject.db] in jac.toml; the connection URL is overridable at runtime with JAC_DB_URL.
Runtime provisioning is being migrated
jaclang is no longer published to PyPI -- it ships as the jac binary. The generated requirements.txt still lists a jaclang entry, which no longer resolves via a plain pip install. Until source ejection is updated to package the binary's runtime, run the ejected backend in an environment that already provides the jaclang runtime (for example, a checkout where the jac binary is on PATH).
jac jac2js#
Generating JavaScript from Jac has moved under jac tool. Use jac tool jac2js <file> (used for client frontend compilation). See jac tool below.
Utility Commands#
jac guide#
Show the curated Jac reference guides bundled with the compiler -- the authoritative spec for writing correct, idiomatic Jac. AI coding agents and humans can read them straight from the CLI; nothing to install.
| Option | Description | Default |
|---|---|---|
topic |
Guide name to display (omit to list every guide) | None |
-s, --search |
List only guides matching a keyword | None |
-e, --export |
Export all guides as a Claude Code skills directory at this path | None |
-j, --json |
Emit machine-readable JSON (for tools and agents) | False |
Examples:
# List every available guide
jac guide
# Print a specific guide
jac guide jac-types
# Find guides by keyword
jac guide --search walker
# Machine-readable list for tooling and agents
jac guide --json
# Export the guides as auto-loading Agent Skills
jac guide --export ~/.claude/skills
See Agent Skills and MCP for using the guides with AI assistants.
jac grammar#
Extracting the grammar has moved under jac tool. Use jac tool grammar (add --lark for Lark format, -o OUT to write to a file). See jac tool below.
jac script#
Running custom scripts has folded into jac x. Use jac x <name> to run a script defined in the [scripts] section of jac.toml (a bare jac x, or jac x --list, lists the available tools and scripts). See Configuration: Scripts for defining scripts.
jac py2jac#
Converting Python to Jac has moved under jac tool. Use jac tool py2jac <file>. See jac tool below.
jac jac2py#
Converting Jac to Python has moved under jac tool. Use jac tool jac2py <file>. See jac tool below.
jac tool#
jac tool <name> fronts the language tools (IR, AST) and the source transforms. The transforms jac2py, py2jac, jac2js, and grammar are now invoked through jac tool (they were formerly top-level jac jac2py / jac py2jac / jac jac2js / jac grammar).
| Tool | Description |
|---|---|
jac2py <file> |
Convert Jac code to Python |
py2jac <file> |
Convert Python code to Jac |
jac2js <file> |
Convert Jac code to JavaScript (used for client frontend compilation) |
grammar [--lark] [-o OUT] |
Extract and print the Jac grammar (EBNF, or --lark for Lark format) |
ir [ast\|sym\|py] <file> |
Inspect compiler IR: AST, symbol table, or generated Python |
Examples:
# Source transforms
jac tool jac2py main.jac
jac tool py2jac script.py
jac tool jac2js app.jac
# Grammar
jac tool grammar # EBNF to stdout
jac tool grammar --lark # Lark format
jac tool grammar -o grammar.ebnf # write to file
# View IR options
jac tool ir
# View AST
jac tool ir ast main.jac
# View symbol table
jac tool ir sym main.jac
# View generated Python
jac tool ir py main.jac
Deprecated:
jac jsis a deprecated alias forjac tool jac2jsand will be removed in a future release. It still works but emits a deprecation warning on stderr; update scripts to usejac tool jac2js.
jac lsp#
Start the Jac language server (LSP over stdio) for editor/IDE integration.
Editors normally launch this for you; configure your editor's LSP client to run jac lsp for .jac files.
jac nacompile#
Hidden from jac --help (still functional).
Compile a .na.jac file to a standalone native ELF executable. No external compiler, assembler, or linker is required. The entire pipeline runs in pure Python using llvmlite and a built-in ELF linker.
Project-level vs. file-level. For a whole-project native build, use
jac build --as native(or--as binary), which runs the type-check gate first.jac nacompileremains the file-level tool for compiling an individual.na.jacfile, building--sharedC-ABI libraries, and cross-compiling with--target wasm32.
| Option | Description | Default |
|---|---|---|
filename |
Path to the .na.jac file (must have with entry {} block) |
required |
-o, --output |
Output binary path | filename without .na.jac |
The file must contain a with entry { } block (which defines the jac_entry() function). Files with Python/server dependencies (native_imports) cannot be compiled to standalone binaries.
What happens under the hood:
- Compiles the
.na.jacthrough the Jac pipeline to get LLVM IR - Injects
main()and_startas pure LLVM IR (zero inline assembly) - Emits native object code via llvmlite's
emit_object() - Links into an ELF executable via the built-in pure-Python ELF linker
The resulting binary dynamically links against libc.so.6. Memory management uses a self-contained reference counting scheme -- no external garbage collector (libgc) is required.
Examples:
# Compile to ./chess
jac nacompile chess.na.jac
# Compile with custom output name
jac nacompile chess.na.jac -o mychess
# Run the binary
./mychess
jac completions#
Hidden from jac --help (still functional).
Generate and install shell completion scripts for the jac CLI.
| Option | Description | Default |
|---|---|---|
-s, --shell |
Shell type (bash, zsh, fish) |
bash |
-i, --install |
Auto-install completion to shell config | False |
When --install is used, the completion script is written to ~/.jac/completions.<shell> (e.g. ~/.jac/completions.bash) and a source line is added to your shell config file (~/.bashrc, ~/.zshrc, or ~/.config/fish/config.fish).
Installed files:
| Shell | Completion script | Config modified |
|---|---|---|
| bash | ~/.jac/completions.bash |
~/.bashrc |
| zsh | ~/.jac/completions.zsh |
~/.zshrc |
| fish | ~/.jac/completions.fish |
~/.config/fish/config.fish |
Examples:
# Print bash completion script to stdout
jac completions
# Auto-install for bash (writes to ~/.jac/completions.bash)
jac completions --install
# Generate zsh completions
jac completions --shell zsh
# Auto-install for fish
jac completions --shell fish --install
Note: After installing, run
source ~/.bashrc(or restart your shell) to activate completions. Completions cover subcommands, options, and file paths.
Client Framework Commands#
The built-in full-stack client framework contributes these commands and flags. They ship with jaclang core -- no separate install needed.
jac build --client#
Build a client shell for a specific target. This is the --client mode of jac build; see that section for the artifact projections (.jab, wheel, npm, source, native). A bare jac build (no --client) runs the type-check gate and emits a .jab, not a client shell.
| Option | Description | Default |
|---|---|---|
filename |
Path to .jac file | main.jac |
--client |
Client shell target (web, desktop, pwa, mobile, static, cef, react-native) |
None |
-p, --platform |
Mobile: android, ios, all. Desktop: windows names the sidecar jac-sidecar.exe |
Current platform |
Examples:
# Build the web client shell
jac build --client web
# Build desktop app
jac build --client desktop
# Build on Windows for the windows binary
jac build --client desktop --platform windows
# Build mobile app for Android
jac build --client mobile --platform android
# Build mobile app for iOS
jac build --client mobile --platform ios
jac setup#
One-time initialization for a build target.
For target=mobile, --platform supports android, ios, or all.
Examples:
# Setup Capacitor for mobile builds
jac setup mobile
# Setup iOS scaffold only (macOS only)
jac setup mobile --platform ios
# Setup both Android and iOS scaffolds (macOS)
jac setup mobile --platform all
Extended Flags#
| Base Command | Added Flag | Description |
|---|---|---|
jac create |
--kind web-app |
Create full-stack project template |
jac create |
--skip |
Skip npm package installation |
jac start |
--client <target> |
Client build target for dev server |
jac install |
--npm |
Add npm (client-side) dependency |
jac remove |
--npm |
Remove npm (client-side) dependency |
Desktop builds#
The desktop and cef client targets ship with jaclang core -- no
separate install. There is no separate jac desktop command and no setup step.
Build and run the OS-native webview target with jac build --client desktop /
jac start --client desktop, or the Chromium Embedded Framework target with
jac build --client cef / jac start --client cef. Set
engine = "cef" under [desktop] for CEF projects. See the
jac-desktop Reference for configuration and CEF
runtime flags.
Common Workflows#
Development#
# Create project
jac create myapp
cd myapp
# Run
jac run main.jac
# Test
jac test -v
# Lint and fix
jac check . --lint --fix
Publishing a Package#
Expected project layout:
mylib/
├── jac.toml ← must contain [project] section
├── README.md
└── mylib/ ← source dir (matches [project] name)
├── __init__.jac
└── utils.jac
# Type-check gate, then build a wheel from jac.toml
jac build --as wheel
# Test locally in a clean environment before uploading
python -m venv test_env && source test_env/bin/activate
pip install dist/mylib-1.0.0-py3-none-any.whl
# Upload to TestPyPI first to verify metadata
twine upload --repository testpypi dist/*
# Then publish to PyPI
twine upload dist/*
Production#
Note
main.jac is the default entry point for jac start. If your entry point differs (e.g., app.jac), pass it explicitly: jac start app.jac --scale.
# Start locally
jac start -p 8000
# Deploy to Kubernetes
jac start --scale
# Check deployment status
jac scale status main.jac
# Remove deployment
jac scale destroy main.jac