odek

GO SMALL. BUILD BIG.

Move fast.
Stay in control.

An autonomous agent with a small footprint and a clear set of boundaries. Odek plans, runs tools, and follows through—in one <15 MB Go binary you can inspect from the inside out.

MIT licensed · Open to inspection · Zero frameworks

Travel light.Compiled Go. Zero frameworks. Focused dependencies.

Work in parallel.Independent tools run together. Your task moves forward.

Keep the keys.You choose the model, approve the risks, and set the limits.

FIVE WHYS / THE ODEK PHILOSOPHY

Small by choice.
Capable by design.

Every dependency is code you inherit. Every permission is reach you grant. Every extra layer is something to understand.

Odek keeps those decisions close to you.

Make it yours ↗
  1. WHY FEWER DEPENDENCIES?

    Ship ideas.
    Travel light.

    Your agent should earn its place on your machine. Odek uses Go’s standard library and a focused set of packages. One compiled binary, with the Web UI built in. Fewer moving parts to install, update, and investigate when something breaks.

    A smaller dependency graph means fewer external components to review and maintain. Each one still deserves scrutiny.

    Count the dependencies yourself ↗
  2. WHY A LEAN RUNTIME?

    Give the work
    a head start.

    Start a binary. Get to work. Independent tool calls run concurrently, while built-in file and text tools do their work without spawning a process for every operation. Less setup. Less orchestration overhead. More room for the task.

    Task speed still depends on your model and workload. The runtime’s job is to keep its own overhead down.

    Look under the hood ↗
  3. WHY SECURITY GUARDRAILS?

    Ambitious tasks.
    Explicit boundaries.

    Give your agent room to work with Docker sandboxing on by default, approval gates for risky actions, and hard execution budgets. Untrusted content stays behind a trust boundary. Injection scanning, secret redaction, and MCP limits add layers of defense.

    You define its reach through configuration, connected tools, and approvals. Guardrails reduce risk; they do not make every action safe.

    Inspect the guardrails ↗
  4. WHY OPEN SOURCE?

    Trust has
    source code.

    Follow a tool call from decision to execution. Trace an approval. Read the redaction logic and the tests behind the defenses. Odek’s MIT-licensed Go source puts the implementation within reach: read it, audit it, change it, build it.

    Auditable means you can examine the implementation. It is not a claim of independent security certification.

    Read what you run ↗
  5. WHY OWN YOUR AGENT WORKFLOW?

    Your machine.
    Your call.

    Choose the model. Bring your tools through MCP. Move between the terminal, Web UI, and Telegram. Sessions, memory, and skills carry the work forward. Set time, tool-call, and token limits; add cost caps when model prices are configured.

    The runtime lives on your machine. Model requests go to your configured provider.

    Build on your terms ↗

BRING YOUR MODEL

DeepSeekOpenAIAnthropicGeminiz.aiKimi+ OpenAI-compatible endpoints

FROM DOWNLOAD TO FIRST TASK

A small install.
A running start.

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