Part of the Lex project — Agents · Manifesto · All packages
A Lex-native coding assistant — think Claude Code or Cursor, built entirely in the Lex ecosystem.
Trust Without Comprehension — live demo
Effect-typed parallel orchestration (§VI) + tamper-evident audit (§VIII) — verified live by the type checker:
# run it yourself
bash examples/manifesto_full_chain/demo.sh# set provider key
export ANTHROPIC_API_KEY=sk-...
# build mode (default), interactive REPL
lex run src/tui/main.lex
# one-shot CLI mode (exits after the task)
lex run src/tui/main.lex "implement list.zip"
# plan mode
lex run src/tui/main.lex -- --plan
# mistral provider
lex run src/tui/main.lex -- --mistral
# bootstrap demo: impl → spec → test → review
lex run src/bootstrap/run.lex
# A2A server (JSON-RPC 2.0)
lex run src/server/api.lex
# ACP server (BeeAI Agent Communication Protocol)
lex run src/server/acp.lex# installs to /usr/local/bin/lex-code and /usr/local/lib/lex-code/
make install
# custom prefix
make install PREFIX=~/.local
# uninstall
make uninstallAfter install, lex must still be on your PATH (it’s the interpreter).
lex-code "implement list.zip"
lex-code --plan --ollama "how should we structure the session module?"| Flag | Mode | Role |
|---|---|---|
| (default) | Build | Write and edit Lex source files |
--plan |
Plan | Produce implementation plans, no writes |
--explore |
Explore | Read + grep, understand the codebase |
--refactor |
Refactor | Restructure code, rename, inline |
--spec |
Spec | Generate lex-spec Spec values |
--test |
Test | Write unit and property tests |
--review |
Review | Code-review: correctness, style, effects |
--multi |
Multi | Run Build + Test in parallel via std.conc |
| Flag | Provider | Model | Key required |
|---|---|---|---|
| (default) | Anthropic | claude-sonnet-4-6 | ANTHROPIC_API_KEY |
--openai |
OpenAI | gpt-5.5 | OPENAI_API_KEY |
--google |
gemini-3.5-flash | GOOGLE_API_KEY |
|
--mistral |
Mistral | mistral-large-latest | MISTRAL_API_KEY |
--litellm |
LiteLLM proxy | $LITELLM_MODEL |
none (proxy handles keys) |
--ollama |
Ollama (local, native API) | $OLLAMA_MODEL |
none |
--vllm |
vLLM (local/remote) | $VLLM_MODEL |
none |
ollama pull codellama # or llama3, deepseek-coder, qwen2.5-coder, …
lex run src/tui/main.lex --ollama# start vLLM server
python -m vllm.entrypoints.openai.api_server \
--model mistralai/Mistral-7B-Instruct-v0.3
# run lex-code against it
VLLM_MODEL=mistralai/Mistral-7B-Instruct-v0.3 \
lex run src/tui/main.lex --vllm "implement list.zip"
# remote GPU box
VLLM_BASE_URL=http://gpu-box:8000/v1/chat/completions \
VLLM_MODEL=deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct \
lex run src/tui/main.lex --vllmVLLM_MODEL defaults to mistralai/Mistral-7B-Instruct-v0.3.
VLLM_BASE_URL defaults to http://localhost:8000/v1/chat/completions.
LiteLLM is the recommended path for running local models. It provides an OpenAI-compatible endpoint over any backend (Ollama, vLLM, MLX, …), which gives cleaner tool calling than the native Ollama wire format.
# start the LiteLLM proxy (config at project root)
litellm --config litellm_config.yaml --port 4000
# run lex-code against qwen3-coder:30b (recommended local model)
LITELLM_MODEL=qwen3-coder:30b \
lex run --allow-effects env,io,net,llm,proc,sql,fs_write,time \
src/tui/main.lex main
# one-shot via the --litellm flag
LITELLM_MODEL=qwen3-coder:30b \
lex run --allow-effects env,io,net,llm,proc,sql,fs_write,time \
src/tui/main.lex main -- --litellm "implement list.zip"
# override the proxy URL (default: http://localhost:4000)
LITELLM_BASE_URL=http://gpu-box:4000 \
LITELLM_MODEL=qwen3-coder:30b \
lex run --allow-effects env,io,net,llm,proc,sql,fs_write,time \
src/tui/main.lex main -- --litellmLITELLM_MODEL is the model name as it appears in your litellm_config.yaml model_name field.
LITELLM_BASE_URL defaults to http://localhost:4000.
Tested on lex-code fizzbuzz bootstrap — task: write fizzbuzz.lex with fn fizzbuzz(n :: Int) -> List[Str] + 4 unit tests, lex check clean, run_all returns 0.
| Model | VRAM | Steps | Result | Notes |
|---|---|---|---|---|
qwen3-coder:30b (Q4_K_M) |
45 GB | ~14 LLM rounds | ✅ passes | Best local choice. Correct tool use, proper Lex idioms after linter feedback. |
gemma4:26b (Q4) |
19 GB | — | ❌ fails | Thinking model: consumes 500–700 tokens on chain-of-thought before any output. Tool calls appear as embedded JSON in content instead of tool_calls. Generates Python instead of Lex under large context. |
gemma4:latest (9 B) |
10 GB | — | not tested | Lighter variant; same thinking-model caveats apply. |
Reliable patterns with qwen3-coder:30b:
# Warm the model before a run (first call loads weights, subsequent calls are faster)
curl -s http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"qwen3-coder:30b","messages":[{"role":"user","content":"hi"}],"max_tokens":10,"stream":false}' \
> /dev/null
LITELLM_MODEL=qwen3-coder:30b \
lex run --allow-effects env,io,net,llm,proc,sql,fs_write,time \
src/bootstrap/fizzbuzz_lex.lex main
# [fizzbuzz_lex] starting build via litellm
# [fizzbuzz_lex] done — steps: 71$ lex check fizzbuzz.lex && lex run fizzbuzz.lex run_all
ok
0Step count explained: steps counts all d.Step records emitted by the agent loop — StepDelta (per LLM token event), StepToolExec, StepToolResult, and StepDone. One LLM round + one tool call ≈ 5 step records. 71 steps ≈ 14 LLM rounds (max_steps: 20 counts rounds, not records).
Avoiding the 0-delta stall: If Ollama receives many large-context requests in rapid succession it can enter a state where it returns {"done": false, "response": ""}. The agent loop sees 0 deltas, emits a silent empty StepDone, and the run appears to complete in 1 step with no output. Fix: restart Ollama (pkill -f "ollama serve" && open -a Ollama) and avoid batching many large-context calls without pauses.
Models with a chain-of-thought "thinking" phase need two things to work through LiteLLM:
max_tokens ≥ 2000— thinking tokens count against the budget before any visible output is produced. Withmax_tokens: 256the model exhausts its budget mid-thought and returns empty content.merge_reasoning_content_in_choices: trueinlitellm_config.yaml— without this, LiteLLM drops thecontentfield whenthinkingis present in the Ollama response.
# litellm_config.yaml
- model_name: gemma4:26b
litellm_params:
model: ollama/gemma4:26b
api_base: http://localhost:11434
merge_reasoning_content_in_choices: trueEven with these fixes, thinking models tend to emit tool calls as embedded JSON in content (rather than in the tool_calls field) when given 10+ function schemas. The openai.lex adapter has a content_tool_call fallback parser, but the generated code quality degrades significantly under large context. Use qwen3-coder:30b for coding tasks.
lex run src/server/api.lexExposes the standard Google A2A protocol: tasks/send, tasks/get, tasks/cancel,
tasks/sendSubscribe (SSE). Agent card at /.well-known/agent.json.
lex run src/server/acp.lexExposes a REST API compatible with the BeeAI ACP standard:
| Method | Path | Description |
|---|---|---|
GET |
/ |
Agent info JSON |
POST |
/runs |
Synchronous run — returns completed JSON |
POST |
/runs/stream |
Streaming run — SSE events |
Example:
curl -X POST http://localhost:8080/runs \
-H 'Content-Type: application/json' \
-d '{"input":[{"role":"user","content":[{"type":"text","text":"write list.zip"}]}]}'Streaming example:
curl -X POST http://localhost:8080/runs/stream \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-d '{"input":[{"role":"user","content":[{"type":"text","text":"write list.zip"}]}]}'
# event: run.started
# data: {"run_id":"...","status":"running"}
#
# event: run.completed
# data: {"run_id":"...","agent_id":"lex-code","status":"completed","output":[...]}| Tool | Description |
|---|---|
read_file |
Read file contents |
write_file |
Write / create a file |
edit_file |
Targeted string replacement |
grep |
Search file contents by regex |
glob |
List files matching a glob |
bash |
Run a shell command |
todo_write |
Write structured TODO list |
| Tool | Description |
|---|---|
lex_check |
Type-check a Lex file |
lex_audit |
Effect audit |
lex_run |
Run a Lex expression |
lex_test |
Run tests |
| Tool | Description |
|---|---|
lex_spec_check |
Evaluate a Spec against bindings |
lex_spec_smt |
SMT-backed spec verification |
| Tool | Description |
|---|---|
sigid_lookup |
Resolve a SigId to a function |
attestation_query |
List attestations for a function |
effects_of |
Query effect row of a function |
lex_store_diff |
Diff two store snapshots |
lex_store_apply |
Apply a store patch |
lex_store_merge |
Merge two store snapshots |
The agent can read and drive lex-vcs directly via these tools.
| Tool | CLI command | Description |
|---|---|---|
ast_diff |
lex diff <a> <b> |
AST-level diff between two files |
op_show |
lex op show <id> |
Inspect a content-addressed operation |
op_log |
lex op log |
Show the operation log |
op_push |
lex op push |
Push ops to remote |
op_pull |
lex op pull |
Pull ops from remote |
branch_list |
lex branch list |
List branches |
branch_current |
lex branch current |
Show active branch |
branch_show |
lex branch show <name> |
Inspect a branch |
branch_create |
lex branch create <name> |
Create a branch |
branch_use |
lex branch use <name> |
Switch branch |
branch_peek |
lex branch peek <name> |
Read-only view of another branch |
branch_overlay |
lex branch overlay <name> |
Overlay a branch without switching |
merge_start |
lex merge start <branch> |
Begin a merge session |
merge_status |
lex merge status |
Show pending conflicts |
merge_resolve |
lex merge resolve <id> |
Resolve a conflict |
merge_defer |
lex merge defer <id> |
Defer a conflict for later |
merge_commit |
lex merge commit |
Commit a completed merge |
lex-code
├── src/
│ ├── agents/ # AgentDef values (build, plan, explore, refactor, spec, test, review)
│ ├── prompts/ # System prompts per mode
│ ├── tools/ # Tool implementations
│ │ ├── standard/ # read, write, edit, grep, glob, bash, todowrite
│ │ ├── lex_*.lex # check, audit, run, test, spec_check, spec_smt
│ │ ├── lex_store_* # sigid, attestations, effects, diff, apply, merge
│ │ └── vcs/ # 17 lex-vcs tools (ast_diff, op_*, branch_*, merge_*)
│ ├── permissions/ # lex-spec Spec values per agent mode
│ ├── server/
│ │ ├── session.lex # Session type, run_turn, AgentMode
│ │ ├── multi_agent.lex # std.conc parallel dispatch
│ │ ├── persist.lex # lex-trail log helpers
│ │ ├── api.lex # A2A server (JSON-RPC 2.0)
│ │ └── acp.lex # ACP server (BeeAI REST protocol)
│ ├── tui/main.lex # CLI REPL + one-shot mode
│ ├── vscode/ # VSCode extension (TypeScript)
│ ├── web/ # Web frontend (vanilla JS)
│ └── bootstrap/run.lex # Demo 4-phase pipeline
├── bin/lex-code # Shell wrapper (used by make install)
├── Makefile # install / uninstall targets
└── lex.toml
cd src/vscode
npm install
npm run build
# then install .vsix or press F5 in VSCode to debugOpen the panel: Cmd+Shift+L (Mac) / Ctrl+Shift+L (Linux/Windows).
Commands available via the Command Palette:
Lex Code: Open ChatLex Code: Build modeLex Code: Plan modeLex Code: Refactor modeLex Code: Spec modeLex Code: Test modeLex Code: Review mode
Configure server URL, default mode, and provider via Settings → Lex Code.
# start the A2A server
lex run src/server/api.lex
# open in browser
open src/web/index.html
# or serve with any static server:
npx serve src/webThe --multi TUI flag (and run_parallel in src/server/multi_agent.lex) spawns two
actors via std.conc.spawn and runs Build + Test concurrently:
let impl_actor := conc.spawn(worker_handler, impl_state)
let test_actor := conc.spawn(worker_handler, test_state)
let impl_steps := conc.ask(impl_actor, Execute(task))
let test_steps := conc.ask(test_actor, Execute(test_task))src/bootstrap/run.lex demonstrates a full 4-phase pipeline:
- impl — Build agent writes the function
- spec — Spec agent generates a lex-spec
Spec - test — Test agent writes unit tests
- review — Review agent checks the whole thing
Each agent mode has a lex-spec Spec value (in src/permissions/rules.lex) that
allowlists its tool set. At construction time, with_permission_gate (from lex-llm)
filters the tool list using the spec, so agents can only call the tools they’re
authorised to use.
- v0.1 — agents, tools, TUI REPL, A2A server, lex-trail persistence
- v0.2 — refactor/spec/test/review agents, store tools, lex-spec permissions, Mistral provider
- v0.3 — parallel multi-agent (
std.conc), VSCode extension, web frontend, bootstrap script - v0.4 — lex-vcs tools (17), CLI one-shot mode, Ollama + vLLM providers, install target
- v0.5 — ACP server (
src/server/acp.lex), ACP helpers in lex-agent
Built under the principles of Trust Without Comprehension.