odek

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.

FIVE 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 ↗
  1. 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 ↗
  2. 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 ↗
  3. 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 ↗
  4. WHY OPEN SOURCE?

    Every documented defense
    has a regression test.

    MIT-licensed Go. security_report_validation_test.go pins each mitigation listed in SECURITY.md, and the classifier is fuzzed for invariants such as “a harmless prefix never lowers a verdict.” Releases ship checksums.txt; the installer and odek upgrade refuse 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 ↗
  5. 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 ↗

BRING YOUR MODEL

DeepSeekOpenAIAnthropicGeminiz.aiKimi+ OpenAI-compatible endpoints

FROM DOWNLOAD TO FIRST TASK

Four steps
to a first task.

macOS and Linux · amd64 and arm64 · No Python, Node, or venv.

  1. 01 install
  2. 02 configure
  3. 03 sandbox
  4. 04 first run
  5. 05 troubleshooting

What you need

RequirementNotes
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.

▸ bash · one line
curl -fsSL https://odek.21no.de/install.sh | sh

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
▸ bash · manual
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.

▸ bash · source
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.

bash · initialize
odek init --global

Merge the selected example into ~/.odek/config.json, preserving your other settings. Keep API keys in ~/.odek/secrets.env.

DeepSeek

json · ~/.odek/config.json
{
  "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.

env · ~/.odek/secrets.env
DEEPSEEK_API_KEY=your-api-key-here

z.ai

json · ~/.odek/config.json
{
  "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.

env · ~/.odek/secrets.env
ZAI_API_KEY=your-api-key-here

OpenAI

json · ~/.odek/config.json
{
  "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.

env · ~/.odek/secrets.env
OPENAI_API_KEY=your-api-key-here

OpenRouter

json · ~/.odek/config.json
{
  "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 ↗

env · ~/.odek/secrets.env
OPENROUTER_API_KEY=your-api-key-here

Open ~/.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:

bash · file permissions
chmod 600 ~/.odek/secrets.env

Provider settings belong in your global configuration. A project ./odek.json cannot set providers, endpoints, or keys. The examples reference key variables explicitly, including OPENROUTER_API_KEY for the custom provider. More options: PROVIDERS.md.

▸ 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:

▸ bash · opt-out
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.

▸ bash · run
odek run "List the Go files in this directory and count their total lines"

illustration your model · think → act → answer

▸ bash · repl
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.

▸ bash · serve
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.

▸ bash · bodek
bodek
# spawns odek serve, or attach: bodek --url 'http://127.0.0.1:8080/?token=…'

Install and themes: bodek.21no.de. Prebuilt binaries on GitHub Releases (Linux, macOS, Windows).

▸ 05 · if it breaks

SymptomFix
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.