Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ go test -race ./... -count=1
ODEK_E2E=true go test -v -count=1 ./cmd/odek/ -run "TestE2E_"

# MCP E2E tests (builds fakeserver from source at test time)
ODEK_E2E=true go test -v -count=1 ./cmd/odek/ -run "TestMCPE2E_"
ODEK_E2E=true go test -v -count=1 ./cmd/odek/ -run "TestMCPClientE2E_"

# Sandbox integration tests (requires Docker)
go test -v -count=1 ./cmd/odek/ -run "TestSandbox"
Expand Down
4 changes: 1 addition & 3 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ Most config knobs have a `ODEK_*` counterpart:
| `ODEK_APPROVE_PROJECT_SANDBOX` | — | bool | approve project-level `./odek.json` sandbox config and implicit `Dockerfile.odek` builds without prompting |
| `ODEK_SANDBOX_BUILD_NETWORK` | — | bool | allow networked `Dockerfile.odek` builds (default: builds run with `--network=none`) |
| `ODEK_MAX_CONCURRENCY` | `max_concurrency` | int |
| `ODEK_MAX_TOOL_PARALLEL` | `max_tool_parallel` | int |
| `ODEK_TRUSTED_PROXIES` | `trusted_proxies` | string (comma-separated IPs/CIDRs) |
| `ODEK_MEMORY_EXTENDED_ENABLED` | `--memory-extended-enabled` | bool |
| `ODEK_MEMORY_EXTENDED_MAX_SIZE_MB` | `--memory-extended-max-size-mb` | int |
Expand Down Expand Up @@ -290,7 +289,7 @@ When a model emits multiple tool calls in one response (`tool_calls` array with

| Field | Default | Env var | Description |
|-------|---------|---------|-------------|
| `max_tool_parallel` | `4` | `ODEK_MAX_TOOL_PARALLEL` | Max concurrent tool calls per iteration. 0 = default 4. Set to 1 for sequential execution. |
| `max_tool_parallel` | `4` | | Max concurrent tool calls per iteration. 0 = default 4. Set to 1 for sequential execution. |

I/O-bound tools (read_file, search_files, shell) benefit most — latency drops from `sum(latencies)` to `max(latency)`.

Expand Down Expand Up @@ -1283,7 +1282,6 @@ DEEPSEEK_API_KEY=sk-...
Why each key is pinned:

- **`provider` + `model`** — the connection identity. The key comes from the provider env (`DEEPSEEK_API_KEY` for the default) or `providers.<id>.api_key`. A custom URL belongs under `providers.<id>.base_url`, not a top-level `base_url`.
- **`stream: true`** — reasoning and answers render live in the terminal and Web UI. Purely preference; remove for minimal output.
- **`interaction_mode: "engaging"`** — the default, pinned so a future odek default change cannot silently alter your output.
- **`limits`** — a runaway agent stops at the wall-clock, tool-call, token, and spend ceilings instead of your invoice. Cost enforcement activates only because both per-million prices are set; add `model_prices` entries keyed by exact model ID when you use several models.
- **`maintenance.enabled`** — sessions, audit records, and logs get retention-swept automatically.
Expand Down
17 changes: 8 additions & 9 deletions docs/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,22 +148,21 @@ When `facts/user.md` and `facts/env.md` are empty (fresh install), `Fit()` produ

## Subagent Memory

Subagents (separate OS processes via `odek subagent`) inherit a **read-only snapshot** of facts:
Subagents are separate OS processes (`odek subagent`, spawned by `delegate_tasks`) that receive
the resolved `memory` config. They read the same on-disk store (`~/.odek/memory`), so the memory
block in their system prompt carries the current facts — there is no snapshot file or flag:

```
odek subagent --memory-snapshot /tmp/kode-mem-<rand>.json
```

The subagent's system prompt includes:
```
# Memory Context (read-only)
═══ MEMORY [N% — X/Y chars] ═══
── User Profile ──
... (facts/user.md)
── Environment ──
... (facts/env.md)
```

Subagents do NOT get a `memory` tool — they cannot modify parent memory.
The `memory` tool is registered for subagents under the same `tools` filter as any other agent,
so they can write facts. Add `memory` to `tools.disabled` to withhold it from every agent,
subagents included.

## Config

Expand Down Expand Up @@ -249,7 +248,7 @@ Every memory lifecycle moment emits a `memory.MemoryEvent` so operators can see
activity that was previously silent. Events fan out (via `MultiMemoryNotifier`)
to whichever surfaces are wired:

- **Terminal** — shown in verbose interaction mode (`--interaction verbose`),
- **Terminal** — shown in verbose interaction mode (`--interaction-mode verbose`),
e.g. `🧠 memory[user] added: ...`, `🧠 consolidated memory[env] (5 → 2 entries)`.
- **Web UI** — streamed over the WebSocket as `memory_event` and surfaced as toasts.
- **Telegram** — posted in the chat when the bot runs verbose.
Expand Down
2 changes: 1 addition & 1 deletion docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ See [PROVIDERS.md](PROVIDERS.md) and the [SDK provider table](https://github.com
| `--provider` / `ODEK_PROVIDER` | New. Default `deepseek`. |
| `--model` / `ODEK_MODEL` | Unchanged. |
| `--base-url` / `ODEK_BASE_URL` | Override for the **selected** provider only. |
| `--api-key` / `ODEK_API_KEY` | Override for the **selected** provider only. |
| `ODEK_API_KEY` | Override for the **selected** provider only. |

DeepSeek-only leftover: when `provider` is `deepseek`, `ODEK_API_KEY` → `DEEPSEEK_API_KEY` → `OPENAI_API_KEY`. That hop does **not** apply to `--provider openai`.

Expand Down
2 changes: 1 addition & 1 deletion docs/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Unsandboxed runs print a one-time stderr warning that the agent has full host ac

- No filesystem access beyond the working directory (mounted read-only when configured).
- `write_file`, `patch`, and `batch_patch` do not touch the host filesystem when `--sandbox` is active; they translate the host path to `/workspace/...` and copy content into the running container with `docker cp`. This makes `--sandbox-readonly` enforceable for the agent's own file tools, not only for commands run through `shell`.
- Extra bind volumes supplied with `--sandbox-volume` are confined to the working directory: the host path must resolve to a location under the working directory, cannot contain `..` or symlink escapes, and cannot match sensitive prefixes such as `/`, `/boot`, `/etc`, `/proc`, `/sys`, `/dev`, `/root`, `/home`, `/var`, `/run`, or `/var/run/docker.sock` (a forbidden volume is dropped with a warning).
- Extra bind volumes supplied with the `sandbox_volumes` config key are confined to the working directory: the host path must resolve to a location under the working directory, cannot contain `..` or symlink escapes, and cannot match sensitive prefixes such as `/`, `/boot`, `/etc`, `/proc`, `/sys`, `/dev`, `/root`, `/home`, `/var`, `/run`, or `/var/run/docker.sock` (a forbidden volume is dropped with a warning).
- No network by default. `sandbox_network` defaults to `none`; `host` is coerced back to `none` with a warning, and `bridge` is available only as an explicit choice.
- Zero kernel capabilities even as root inside the container.
- No privilege escalation: `--security-opt no-new-privileges` blocks setuid/setgid, and `/tmp` is a `noexec` tmpfs.
Expand Down
7 changes: 6 additions & 1 deletion docs/SESSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,13 @@ From inside the Telegram bot, session recall is seamless: the current user messa

## Programmatic API

> **In-module only.** The snippet below imports `internal/session`, which Go only allows
> inside this module. External programs should use `agent.Run` and the other public-type
> methods; `RunWithMessages` and the session store are in-module APIs. For external session
> handling, use `odek run` / `odek continue` or the REST API ([API.md](API.md)).

```go
import "github.com/BackendStack21/odek/internal/session"
import "github.com/BackendStack21/odek/internal/session" // in-module only

agent, err := odek.New(odek.Config{...})

Expand Down
2 changes: 1 addition & 1 deletion docs/TELEGRAM.md
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ ls -la ~/.odek/config.json
| Config field | Env var | Description |
|---|---|---|
| `telegram.bot_token` | `ODEK_TELEGRAM_BOT_TOKEN` | Telegram bot API token (required) |
| `telegram.default_chat_id` | | Numeric chat ID to deliver results to (required) |
| `telegram.default_chat_id` | `ODEK_TELEGRAM_DEFAULT_CHAT_ID` | Numeric chat ID to deliver results to (required) |

## Testing

Expand Down
2 changes: 1 addition & 1 deletion docs/TOOL_SELECTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ Unknown names are silently ignored, so typos do not crash startup.

There is only one session-related tool: `session_search`. Session
management (save, list, delete, trim, continue) is handled by the `odek
session` command and by flags such as `--session` and `--continue`, not by
session` and `odek continue` commands and by the `--session` flag, not by
tools exposed to the LLM.

## Mode-specific required tools
Expand Down
2 changes: 1 addition & 1 deletion docs/WEBUI.md
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ Plus the shared sandbox flags (`--sandbox`, `--no-sandbox`, `--sandbox-image`,

## WebSocket Protocol

The UI communicates entirely over a single WebSocket at `/ws`. Messages are newline-delimited JSON. The protocol is a simplex prompt → stream → done flow: the client sends one prompt, and the server streams back events until done.
The UI communicates entirely over a single WebSocket at `/ws`. Messages are newline-delimited JSON. The server streams events for a prompt until `done`, and the client may send control frames on the same socket (`cancel`, `subagent_cancel`, `ping`, `approval_response`, `session_switch` — see [Client → Server](#client--server)).

### Client → Server

Expand Down
Loading