You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
System prompt is loaded by priority: `--system` flag > `~/.odek/IDENTITY.md` > compiled-in defaultSystem. The default is a concise identity focused on TDD workflow, tool discipline, and safety rules.
82
74
83
-
**Performance/parallelism** (added v0.38-v0.40):
84
-
| Category | Tools |
85
-
|----------|-------|
86
-
| Parallel batch |`batch_read` — N files in 1 call, `batch_patch` — N edits atomically, `parallel_shell` — N commands true-parallel, `http_batch` — N URLs parallel fetch |
-`send_message`: Sends text/photo/document/voice to the Telegram chat with inline keyboard support.
95
-
- All file tools: `O_NOFOLLOW` on opens, `danger.ClassifyPath` per path, atomic temp+rename for writes.
96
-
- All network tools: `danger.ClassifyURL` per URL, configurable network egress gate.
97
-
98
-
### 3. Skills
99
-
Trigger-matched `SKILL.md` files loaded on-demand via lazy injection. Auto-learns from patterns every session.
100
-
- Stored in `~/.odek/skills/` (user) and `skills/` (project).
101
-
-`odek skill curate` analyzes quality, staleness, and trigger overlap.
102
-
- Skills with `auto_load: true` are injected as passive reference; `auto_load: false` + strong triggers → lazy injection as system message (stronger signal).
103
-
104
-
### 4. Memory (`internal/memory/`)
105
-
Three-tier persistence:
106
-
-**Facts** — Markdown files on disk, merge-on-write via go-vector cosine similarity (~80% fewer LLM calls).
107
-
-**Session buffer** — Full conversation history.
108
-
-**Episodes** — Searchable summaries extracted by LLM on session end.
109
-
- go-vector RP is ephemeral — rebuilt from text on every write, no embedding state to persist.
110
-
111
-
### 5. Config System (`internal/config/loader.go`)
112
-
Five-layer priority chain:
113
-
```
114
-
0. ~/.odek/secrets.env ← Auto-loaded into process environment
- Inline keyboard for approvals, clarifications, and cancel
135
-
-`send_message` tool — agent can send structured messages, files, and keyboards back to chat
136
-
-`--deliver` flag delivers final response to configured default chat (cron integration)
137
-
- Per-chat session management with TTL-based cleanup
138
-
139
-
### 8. Web UI
140
-
`odek serve` — single-page browser interface with WebSocket streaming, `@` resource completion, token economics display, drag-and-drop file attachments, inline loading. Built from Go's embed — zero npm.
141
-
142
-
### 9. Dynamic Model Discovery
143
-
On startup, odek queries the LLM provider's `GET /models` endpoint and auto-discovers model capabilities (max context, thinking support, parallel tool support). This replaces hardcoded model profiles — the agent adapts to whatever the provider exposes.
144
-
145
-
### 10. Secret Redaction (`internal/redact/`)
146
-
Active at two layers:
147
-
- Tool outputs are redacted before the LLM sees them (ReAct loop).
148
-
- Session files are sanitized on save (defense-in-depth).
149
-
- 13-pattern scanner covers OpenAI, GitHub, AWS, JWT, private keys, Slack, Stripe, Google, Twilio, generic API keys, Auth headers, and env var credentials.
150
-
151
-
## Key Conventions
152
-
153
-
-**No external frameworks.** Stdlib + four focused packages (go-vector, yaml.v3 for MCP, goja for JS, chroma for highlight).
154
-
-**Single binary.** Everything compiles into one static executable (~12 MB).
155
-
-**Tests live alongside code.**`*_test.go` files in the same package, never in a separate `test/` directory.
156
-
-**Test data** uses `t.TempDir()` for isolation.
157
-
-**CLI commands** follow the pattern: `cobra.Command` with `RunE` handler. Flag parsing is in `main.go`.
158
-
-**New config fields** require 11-point wiring: FileConfig → CLIFlags → ResolvedConfig → loadFile → overlayFile → env var → CLI flag → resolved mapping → flag parsing → pass-through → call sites. Missing any step = silent failure.
159
-
-**Build before test.** Always `go build ./...` first to catch compile errors before running tests.
160
-
-**Use `odek run` for analysis.** Prefer delegating complex code questions to odek itself (Pattern 2 in odek-file-qa skill).
161
-
-**The odek Tool interface** is `Call(args string) (string, error)` and `Schema() any` — NOT `Execute()` or `json.RawMessage`.
162
-
-**MarkdownV2 reserved chars** must be escaped in Telegram messages. The escape function handles `_*[]()~>#+-=|{}.!`.
163
-
-**Inline keyboard buttons** use `*telegram.InlineKeyboardMarkup`, not raw `map[string]any`.
164
-
-**Skill auto_load: false** with strong trigger keywords is STRONGER than `auto_load: true` — lazy injection as a system message right before the user message beats passive reference injection.
165
-
-**Patch old_string must be unique** in the file. For repeated patterns (class="card"), include enough surrounding context (e.g., the card's inner content).
166
-
-**After modifying shared files in parallel subagents**, always run `go build ./... && go test ./...` to catch integration errors. Subagent patch conflicts produce `Could not find a match for old_string` warnings.
167
-
168
-
## Testing
169
-
170
-
```bash
171
-
# Full test suite
172
-
go test ./... -count=1
173
-
174
-
# With race detector (recommended for loop/tool/telegram changes)
175
-
go test -race ./... -count=1
176
-
177
-
# Specific package with verbose output
178
-
go test -v ./internal/loop/ -run TestTrimContext -count=1
179
-
180
-
# Benchmark
181
-
go test -bench=. -benchmem ./internal/loop/
182
-
183
-
# Run integration/E2E tests (require Docker and/or network)
184
-
go test -v -run "TestTelegram|TestMCP" ./cmd/odek/ -count=1
185
-
```
186
-
187
-
### Test Conventions
188
-
- Coverage targets: 70%+ for new packages, no regression on existing.
189
-
-`httptest.Server` for mocking HTTP endpoints (LLM, Telegram, MCP).
190
-
-`t.Setenv` for environment variable overrides (no global env mutation).
191
-
- Parallel tests must use `-race` to catch data races on shared slices.
192
-
-`timedTool` pattern for testing parallel execution with configurable delays.
193
-
- Secret redaction tests must use runtime string concatenation to avoid triggering GitHub's push-time secret scanner.
194
-
195
-
## Common Pitfalls
196
-
197
-
-**Session files are JSON in `~/.odek/sessions/`.** Corrupt data is handled gracefully with fallback scan.
198
-
-**The Telegram bot uses long-polling (no webhooks),** built on stdlib `net/http`.
199
-
-**Background subprocesses don't inherit `ODEK_API_KEY`.** When running odek as a subprocess, the spawned process may not have the key. Pass it explicitly or save to `/tmp/.aieb_odek_key`.
200
-
-**`go build .` ≠ `go build ./cmd/odek`.** The bare `.` builds the library package (an ar archive, not an executable).
201
-
-**Config partial overlay + Go zero values = missing defaults.** Always start from `DefaultConfig()` and overlay only non-zero user fields. Sentinel values or pointer fields are needed to distinguish "unset" from "explicitly zero."
202
-
-**`delegate_tasks` sub-agents have a 120s default timeout.** Override via `subagent.timeout_seconds` config.
203
-
-**Parallel tool tests** use `timedTool` with configurable delays — always run with `-race` to catch data races on the results slice.
204
-
-**Batch approval gate** checks `e.approver != nil && len(result.ToolCalls) > 1` — single-tool responses skip the gate. When adding a new approver, implement `SetTrustAll(bool)` to benefit from batch trust cascade.
205
-
-**SetTrustAll is bounded by `defer`** — it's enabled before Phase 2 and disabled when `runLoop` returns. The mockApprover's `trustAll` field will be `false` after `Run()` returns.
206
-
-**Approval callbacks must route BEFORE `OnCallbackQuery`.** If it falls through to the generic handler, the approver's channel never receives the response → 120s timeout deadlock.
207
-
-**Async dispatch prevents update loop deadlock.** Agent loop processing MUST run in a goroutine from the callback handler.
208
-
-**`DownloadFile` hardcodes the production API URL.** Add `FileBaseURL` to Bot for testability; both `BaseURL` and `FileBaseURL` must be overridden in tests.
209
-
-**Review every interface path for goroutine safety** after writing a new subsystem (Telegram, approvals, parallel tools). Checklist: mutable shared state, mutex protection, per-chat state isolation, `httptest.Server` URL configurability.
210
-
-**`reasoning_content` echo for DeepSeek models.** If the API returns `reasoning_content`, it must be echoed back in subsequent assistant messages or the next call fails with `400 Bad Request`.
211
-
-**`frame-ancestors` in `<meta>` produces a browser warning.** CSP meta tags ignore this directive — set it via HTTP headers or accept the cosmetic warning.
212
-
-**Rebuild the binary after source changes.**`go build -o /usr/local/bin/odek ./cmd/odek`. Source changes don't take effect until rebuilt.
213
-
214
-
## Release Checklist
215
-
216
-
1.`go build ./...` — compile check
217
-
2.`go test ./... -count=1` — full test suite
218
-
3.`go test -race ./... -count=1` — race detection
219
-
4. Update `docs/CHANGELOG.md` with notable changes
220
-
5. Commit and push to `main`
221
-
6. Tag: `git tag -a vX.Y.Z -m "vX.Y.Z: short description"`
0 commit comments