AGENT RUNTIME · GO · MIT
One binary.
Seven modules.
Odek is a ReAct agent: it plans, calls tools in parallel, and asks before risky commands. The release binary is <15 MB, the Web UI is embedded in it, and its entire go.sum lists seven modules.
Linux & macOS · amd64 & arm64 · CLI, REPL, Web UI, Telegram, cron
7 modules.The full dependency graph: three odek libraries (LLM, MCP, vectors) and four golang.org/x packages.
12 risk classes.Every shell command is tokenized and classified. Unrecognized commands are denied, not guessed.
6,000+ tests.Plus 17 fuzz targets. CI runs staticcheck and govulncheck on every push.
WEB UI · EMBEDDED IN THE BINARY
No Node.
No build step.
Tool output, rendered.
Every tool return is listed with its recorded outcome. Diffs, code, and terminal output open in the inspector: search, raw view, copy, save, split diff.
Plan status is not proof.
The Overview shows plan steps the agent marked complete, labelled “verification requires evidence,” with links to the tool results behind each step.
The command, verbatim, before it runs.
A risky command stops the run until you answer. The card shows the exact command, its risk class, and what that class means. Unanswered requests expire.
Sub-agents, one row each.
Delegated tasks run in parallel. Each one reports phase, step, tokens, and last tool. Running agents can be stopped one at a time; each has its own conversation trace.
Start with a task.
Type the task, reference files or past sessions with @, attach files, and pick the model and limits under Run settings.
Command palette.
⌘K searches sessions, commands, models, and inspector views from one prompt.
Actual odek Web UI, captured from the bundled fixture with synthetic sessions — not a recorded agent run. Select an image for full size.
odek serveFIVE DESIGN DECISIONS
Each claim
links to its source.
Every dependency is code you inherit. Every permission is reach you grant.
Each section below points at the file or doc that backs it.
Install ↗-
WHY FEWER DEPENDENCIES?
Seven modules.
That is all of go.sum.No web framework, no CLI framework, no indirect dependencies. The HTTP server, WebSocket framing, cron parser, and terminal line editor are the standard library plus odek’s own code. The Web UI is embedded with
go:embed. Install is one file.Three of the seven modules (go-llm-sdk, go-mcp, go-vector) come from the same organization as odek. Fewer modules to review is not the same as no review.
Count the dependencies yourself ↗ -
WHY A LEAN RUNTIME?
Parallel tool calls.
No process per read.Independent tool calls in one turn run concurrently (4 by default,
max_tool_parallel). File reads, search, patch, diff, JSON queries, checksums, and math run in-process instead of shelling out. Near the context limit, old tool output is trimmed and dropped turns are compacted into a digest. At the 90-iteration cap the run ends with a partial-progress summary.Wall-clock time is dominated by the model. The runtime only controls its own overhead.
Look under the hood ↗ -
WHY SECURITY GUARDRAILS?
Unrecognized commands
are denied.By default, reads, local writes, and plain fetches run; installs, uploads, code execution, and system writes prompt; destructive, blocked, and unrecognized commands are denied. Tools run in a Docker container by default. Web pages, files, and MCP results reach the model inside a per-call nonce tag that marks them untrusted. After three same-class approvals in 60 seconds, the trust shortcut disappears and you type
approve.The classifier and injection scanner are rule sets; a novel evasion can get past them. The sandbox is what contains it.
Inspect the guardrails ↗ -
WHY OPEN SOURCE?
Every documented defense
has a regression test.MIT-licensed Go.
security_report_validation_test.gopins each mitigation listed in SECURITY.md, and the classifier is fuzzed for invariants such as “a harmless prefix never lowers a verdict.” Releases shipchecksums.txt; the installer andodek upgraderefuse a binary that does not match it.Tested is not certified. Auditable means you can read the implementation, not that someone else already has.
Read what you run ↗ -
WHY OWN YOUR AGENT WORKFLOW?
Hard budgets.
Exit code 4.Cap a run’s wall-clock time, tool calls, input and output tokens, and cost (
--max-runtime,--max-tool-calls,--max-cost-usd, …). A breach stops the run, saves the session, and exits 4. Six built-in providers plus any OpenAI-compatible endpoint; external tools over MCP. Sessions, memory, and skills stay in~/.odek.The runtime is local. Prompts and tool results go to the model provider you configure. Cost caps apply only when model prices are configured.
Build on your terms ↗
FROM DOWNLOAD TO FIRST TASK
Four steps
to a first task.
macOS and Linux · amd64 and arm64 · No Python, Node, or venv.
What you need
| Requirement | Notes |
|---|---|
| macOS or Linux | Prebuilt binaries, amd64 and arm64. Windows: Go from source. |
| A provider API key | Choose z.ai, DeepSeek, OpenAI, or OpenRouter in step 02. For z.ai, use (GLM Coding Plan or pay-as-you-go). Same binary for DeepSeek, OpenAI, Anthropic, Gemini, Kimi, or any OpenAI-compatible endpoint — PROVIDERS.md. |
| Go ≥ 1.27 | Only if you build from source. Not needed for the prebuilt binary. |
| Docker | Optional. The sandbox is on by default — opt out in step 03. |
▸ 01 · install
One line. Checksum-verified prebuilt binary, then ~/.local/bin (or /usr/local/bin). If odek version is not found, add that directory to PATH.
curl -fsSL https://odek.21no.de/install.sh | sh
copied — paste in a terminal. The installer refuses to install anything it cannot verify against the release checksums.
Later, odek upgrade self-updates from GitHub Releases the same way (SHA-256 verified). The script is readable here — pipe-to-sh should always be a choice, not a habit.
Prefer manual steps? Download and verify yourself
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
ASSET="odek-${OS}-${ARCH}"
TMP=$(mktemp -d)
curl -fsSL -o "${TMP}/${ASSET}" \
"https://github.com/BackendStack21/odek/releases/latest/download/${ASSET}"
curl -fsSL -o "${TMP}/checksums.txt" \
"https://github.com/BackendStack21/odek/releases/latest/download/checksums.txt"
if command -v sha256sum >/dev/null; then
(cd "${TMP}" && grep " ${ASSET}$" checksums.txt | sha256sum -c -)
else
(cd "${TMP}" && grep " ${ASSET}$" checksums.txt | shasum -a 256 -c -)
fi
mkdir -p "${HOME}/.local/bin"
install -m 755 "${TMP}/${ASSET}" "${HOME}/.local/bin/odek"
rm -rf "${TMP}"
export PATH="${HOME}/.local/bin:${PATH}"
odek version
Have Go? Install from the latest tag — never go install …@latest
Go ignores v2 tags for this repository’s historical v1 module path and would install an older v1 release.
TAG=$(git ls-remote --tags --sort=-v:refname \
https://github.com/BackendStack21/odek.git \
| awk '!/\^\{\}$/ {sub("refs/tags/", "", $2); print $2; exit}')
TMP=$(mktemp -d)
git clone --depth 1 --branch "${TAG}" \
https://github.com/BackendStack21/odek.git "${TMP}/odek"
(cd "${TMP}/odek" && go install -ldflags "-X main.version=${TAG}" ./cmd/odek)
rm -rf "${TMP}"
export PATH="$(go env GOPATH)/bin:$PATH"
odek version
▸ 02 · configure
Initialize once, then choose your provider below. odek init --global creates ~/.odek/config.json with restricted permissions and refuses to overwrite an existing configuration without --force.
odek init --globalMerge the selected example into ~/.odek/config.json, preserving your other settings. Keep API keys in ~/.odek/secrets.env.
DeepSeek
{
"provider": "deepseek",
"model": "deepseek-flash",
"providers": {
"deepseek": {
"api_key": "${DEEPSEEK_API_KEY}"
}
}
}Uses Odek’s built-in DeepSeek provider and endpoint. Choose a model available to your API account.
DEEPSEEK_API_KEY=your-api-key-herez.ai
{
"provider": "zai",
"model": "glm-5.3-flash",
"providers": {
"zai": {
"api_key": "${ZAI_API_KEY}",
"base_url": "https://api.z.ai/api/coding/paas/v4"
}
},
"llm": {
"request_timeout_seconds": 300,
"stream_idle_timeout_seconds": 300
}
}The endpoint shown is for the GLM Coding Plan. For pay-as-you-go, use https://api.z.ai/api/paas/v4. Check your plan’s model IDs in the z.ai dashboard.
ZAI_API_KEY=your-api-key-hereOpenAI
{
"provider": "openai",
"model": "gpt-5.6-luna",
"providers": {
"openai": {
"api_key": "${OPENAI_API_KEY}"
}
}
}Uses Odek’s built-in OpenAI provider and endpoint. The model is an example; change it to a supported model available to your API account.
OPENAI_API_KEY=your-api-key-hereOpenRouter
{
"provider": "openrouter",
"model": "openai/gpt-4o",
"providers": {
"openrouter": {
"api_key": "${OPENROUTER_API_KEY}",
"format": "openai",
"base_url": "https://openrouter.ai/api/v1"
}
}
}OpenRouter is a custom provider using the OpenAI format. Keep the format field and use a model ID with its publisher prefix. Choose a model that supports tool calling. OpenRouter API guide ↗
OPENROUTER_API_KEY=your-api-key-hereOpen ~/.odek/secrets.env in your editor and add or update the selected key entry. Replace the placeholder with your actual key, preserve any other entries, then restrict file permissions:
chmod 600 ~/.odek/secrets.env▸ 03 · sandbox
Tool execution runs inside an isolated Docker container by default for odek run, odek continue, odek repl, and odek serve. No Docker? Opt out before the first run:
export ODEK_NO_SANDBOX=1 # add to ~/.zshrc / ~/.bashrc
# or per-run:
odek run --no-sandbox "..."
Unsandboxed runs warn loudly. ODEK_REQUIRE_SANDBOX=1 makes them fatal instead. Full model: SANDBOXING.md.
▸ 04 · first run
You should see your configured model in the run header and a short ReAct trace: think → act → answer.
odek run "List the Go files in this directory and count their total lines"
illustration your model · think → act → answer
odek repl
Web UI — streams tokens, tools, and approvals. It binds 127.0.0.1:8080 and prints a token URL. Open that URL; a bare http://127.0.0.1:8080 loads the chrome but cannot connect.
odek serve
# → http://127.0.0.1:8080/?token=…
▸ optional · bodek
bodek is a Bubble Tea TUI over odek serve — live reasoning, tool steps, approvals, and sub-agent chips. The engine stays odek; bodek only renders the stream. For operators who want a terminal UI and can accept that extra dependency.
bodek
# spawns odek serve, or attach: bodek --url 'http://127.0.0.1:8080/?token=…'
▸ 05 · if it breaks
| Symptom | Fix |
|---|---|
odek: command not found |
~/.local/bin (or $(go env GOPATH)/bin) is not on PATH. |
failed to create sandbox container |
No Docker. Use --no-sandbox or export ODEK_NO_SANDBOX=1. |
| Auth errors / empty key | Check that your selected provider’s key is in ~/.odek/secrets.env (mode 0600) and matches the variable referenced by providers in your global config. ./odek.json cannot carry keys. |
429 on sub-agent runs |
z.ai throttles around 5 concurrent streams. Set top-level max_concurrency to 2 in ~/.odek/config.json, or ODEK_MAX_CONCURRENCY. |
| Slow first byte / timeout | GLM 5.3 reasoning is always on. Defaults are 300s; raise llm.request_timeout_seconds and llm.stream_idle_timeout_seconds if it is still silent. |
▸ next
The page is the short path. Depth lives in the docs.
- bodek optional TUI — Bubble Tea client for odek serve
- full guide GETTING_STARTED — source install, bodek, GLM reference
- cheatsheet every command and flag, one page
- config five-layer chain, every field
- cli run, serve, telegram, schedule, upgrade
- providers deepseek, openai, anthropic, gemini, zai, kimi
- sandbox Docker isolation and the opt-out
- security approvals, untrusted content, injection defenses
- web ui odek serve — token URL, WebSocket, inspector