Skip to content

Commit c5858bf

Browse files
committed
fix: wire up --prompt-caching flag, curate flags, and fix doc/env-var inaccuracies
- Add --prompt-caching CLI flag for odek run/repl/serve - Add ODEK_PROMPT_CACHING env var and prompt_caching config key - Wire up --apply and --interactive flags for 'odek skill curate' - Fix SANDBOXING.md: KODE_SANDBOX_* -> ODEK_SANDBOX_* (wrong prefix) - Fix odek-session-management skill: session cleanup uses UpdatedAt, not file mtime - Fix odek-prompt-caching skill: config key is prompt_caching, not cache - Remove non-existent --sse-addr from MCP docs/skills - Add ODEK_PROMPT_CACHING to env var tables in CONFIG.md and CHEATSHEET.md
1 parent 60983b0 commit c5858bf

8 files changed

Lines changed: 73 additions & 20 deletions

File tree

cmd/odek/main.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ type runFlags struct {
235235
Sandbox *bool // nil = not set
236236
NoColor *bool // nil = not set
237237
NoAgents *bool // nil = not set
238+
PromptCaching *bool // nil = not set; true = enable prompt caching
238239
Session *bool // nil = not set; true = save session after run
239240
Learn *bool // nil = not set; true = enable skills learning mode
240241
Task string
@@ -300,6 +301,9 @@ func parseRunFlags(args []string) (runFlags, error) {
300301
case "--no-agents":
301302
f.NoAgents = boolPtr(true)
302303
i++
304+
case "--prompt-caching":
305+
f.PromptCaching = boolPtr(true)
306+
i++
303307
case "--session":
304308
f.Session = boolPtr(true)
305309
i++
@@ -353,6 +357,7 @@ type replFlags struct {
353357
Model string
354358
Thinking string
355359
Sandbox *bool // nil = not set
360+
PromptCaching *bool // nil = not set; true = enable prompt caching
356361

357362
// Sandbox-specific CLI flags
358363
SandboxImage string
@@ -415,6 +420,9 @@ func parseReplFlags(args []string) (replFlags, error) {
415420
case "--sandbox-user":
416421
f.SandboxUser = args[i+1]
417422
i += 2
423+
case "--prompt-caching":
424+
f.PromptCaching = boolPtr(true)
425+
i++
418426
default:
419427
// Unrecognized flag or positional — skip it
420428
i++
@@ -443,7 +451,7 @@ Commands:
443451
run --session Execute and save conversation as a session
444452
continue Continue the most recent session (or by --id)
445453
repl Interactive REPL mode (multi-turn session)
446-
Accepts --model, --thinking, --sandbox, and
454+
Accepts --model, --thinking, --sandbox, --prompt-caching, and
447455
--sandbox-* flags just like odek run.
448456
serve Web UI server with WebSocket streaming
449457
Open http://localhost:8080 in your browser.
@@ -476,6 +484,7 @@ Run flags:
476484
--temperature <n> LLM temperature 0.0–2.0 (default: 0 = deterministic)
477485
--no-color Disable colored terminal output
478486
--no-agents Skip loading AGENTS.md from working directory
487+
--prompt-caching Enable prompt caching markers (Anthropic/DeepSeek/OpenAI)
479488
--session Save conversation as a multi-turn session
480489
--learn Enable skill learning mode — on by default, no flag needed
481490
--no-learn Disable skill learning mode (overrides config/default)
@@ -488,6 +497,7 @@ Skill commands:
488497
odek skill import <uri> [flags] Import a skill from file:// or https://
489498
Flags: --basic (skip LLM), --yes (auto-approve)
490499
odek skill curate Analyze skills for quality, staleness, overlap
500+
Flags: --apply (apply changes), --interactive (review one-by-one)
491501
492502
Sandbox flags:
493503
--sandbox Run in isolated Docker container
@@ -782,6 +792,7 @@ func run(args []string) error {
782792
Sandbox: f.Sandbox,
783793
NoColor: f.NoColor,
784794
NoAgents: f.NoAgents,
795+
PromptCaching: f.PromptCaching,
785796
Learn: f.Learn,
786797
System: f.System,
787798
Task: f.Task,
@@ -906,6 +917,7 @@ func run(args []string) error {
906917
Renderer: rend,
907918
Skills: skillsCfg,
908919
SkillManager: sm,
920+
PromptCaching: resolved.PromptCaching,
909921
})
910922
if err != nil {
911923
return err
@@ -1628,11 +1640,27 @@ func skillCmd(args []string) error {
16281640
return nil
16291641

16301642
case "curate":
1643+
// Parse --apply and --interactive flags
1644+
apply := false
1645+
interactive := false
1646+
var remainingArgs []string
1647+
for _, arg := range subArgs {
1648+
switch arg {
1649+
case "--apply":
1650+
apply = true
1651+
case "--interactive":
1652+
interactive = true
1653+
default:
1654+
remainingArgs = append(remainingArgs, arg)
1655+
}
1656+
}
1657+
_ = remainingArgs // future use: filter by skill name
16311658
sm := skills.NewSkillManager(userDir, "./.odek/skills")
16321659
allSkills := append(sm.Result.AutoLoad, sm.Result.Lazy...)
16331660
report := skills.CurateSkills(allSkills, skills.CurateOptions{
16341661
StalenessDays: 90,
1635-
Apply: false,
1662+
Apply: apply,
1663+
Interactive: interactive,
16361664
})
16371665
fmt.Print(skills.FormatCurationReport(report))
16381666
return nil
@@ -1801,6 +1829,7 @@ func continueCmd(args []string) error {
18011829
Renderer: rend,
18021830
Skills: skillsCfg,
18031831
SkillManager: sm,
1832+
PromptCaching: resolved.PromptCaching,
18041833
})
18051834
if err != nil {
18061835
return err

cmd/odek/repl.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func replCmd(args []string) error {
5050
Model: f.Model,
5151
Thinking: f.Thinking,
5252
Sandbox: f.Sandbox,
53+
PromptCaching: f.PromptCaching,
5354

5455
SandboxImage: f.SandboxImage,
5556
SandboxNetwork: f.SandboxNetwork,
@@ -145,6 +146,7 @@ func replCmd(args []string) error {
145146
Skills: skillsCfg,
146147
SkillManager: sm,
147148
MemoryConfig: resolved.Memory,
149+
PromptCaching: resolved.PromptCaching,
148150
})
149151
if err != nil {
150152
return err

cmd/odek/serve.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func serveCmd(args []string) error {
3535
// Sandbox CLI flags (nil pointers = not set)
3636
var sandbox *bool
3737
var sandboxReadonly *bool
38+
var promptCaching *bool
3839
var sandboxImage, sandboxNetwork, sandboxMemory, sandboxCPUs, sandboxUser string
3940

4041
for i := 0; i < len(args); i++ {
@@ -78,13 +79,16 @@ func serveCmd(args []string) error {
7879
if i < len(args) {
7980
sandboxUser = args[i]
8081
}
82+
case "--prompt-caching":
83+
promptCaching = boolPtr(true)
8184
default:
8285
return fmt.Errorf("unknown flag %q for serve", args[i])
8386
}
8487
}
8588

8689
resolved := config.LoadConfig(config.CLIFlags{
8790
Sandbox: sandbox,
91+
PromptCaching: promptCaching,
8892
SandboxImage: sandboxImage,
8993
SandboxNetwork: sandboxNetwork,
9094
SandboxReadonly: sandboxReadonly,

docs/CHEATSHEET.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ odek serve # Web UI (http://127.0.0.1:8080)
1212
odek serve --open # Web UI + auto-open browser
1313
odek subagent --goal "review auth" # Spawn subagent
1414
odek mcp # Expose tools via MCP stdio
15-
odek mcp --sse-addr :8081 # Expose via SSE
1615

1716
# Sandbox flags (apply to run/repl/serve)
1817
odek run --sandbox "build safely"
@@ -197,6 +196,7 @@ odek mcp --sse-addr :8081 # SSE transport
197196
| `ODEK_SYSTEM` | system |
198197
| `ODEK_NO_COLOR` | no_color |
199198
| `ODEK_NO_AGENTS` | no_agents |
199+
| `ODEK_PROMPT_CACHING` | prompt_caching |
200200
| `ODEK_MAX_CONCURRENCY` | max_concurrency |
201201
| `ODEK_CTX` | ctx (comma-separated file paths) |
202202
| `ODEK_API_KEY` | api_key (preferred) |

docs/CLI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
| Flag | Type | Default | Description |
3434
|------|------|---------|-------------|
35-
| `--model <name>` | string | `deepseek-chat` | LLM model — profiles auto-set thinking/timeout (see [Providers](docs/PROVIDERS.md)) |
35+
| `--model <name>` | string | `deepseek-chat` | LLM model — profiles auto-set thinking/timeout (see [Providers](docs/PROVIDERS.md)). Consider using `deepseek-v4-flash` for faster/cheaper tasks. |
3636
| `--base-url <url>` | string | `https://api.deepseek.com/v1` | OpenAI-compatible API endpoint |
3737
| `--max-iter <n>` | int | `90` | Max think→act cycles |
3838
| `--thinking <level>` | string | profile default | Reasoning depth: `enabled`/`disabled`/`low`/`medium`/`high` |

docs/CONFIG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Every config knob has a `ODEK_*` counterpart:
6363
| `ODEK_NO_AGENTS` | `--no-agents` | bool |
6464
| `ODEK_SYSTEM` | `--system` | string |
6565
| `ODEK_SKILLS_LEARN` | `skills.learn` | bool |
66+
| `ODEK_PROMPT_CACHING` | `prompt_caching` | bool |
6667
| `ODEK_SANDBOX_IMAGE` | `--sandbox-image` | string |
6768
| `ODEK_SANDBOX_NETWORK` | `--sandbox-network` | string |
6869
| `ODEK_SANDBOX_READONLY` | `--sandbox-readonly` | bool |

docs/SANDBOXING.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ odek run --sandbox "protoc --version"
2020

2121
## Config reference
2222

23-
All sandbox settings are available in `~/.odek/config.json`, `./kode.json`, `KODE_*` env vars, and CLI flags, following the same [priority chain](CONFIG.md).
23+
All sandbox settings are available in `~/.odek/config.json`, `./kode.json`, `ODEK_*` env vars, and CLI flags, following the same [priority chain](CONFIG.md).
2424

2525
### Config file fields
2626

@@ -47,28 +47,28 @@ All sandbox settings are available in `~/.odek/config.json`, `./kode.json`, `KOD
4747

4848
| Field | Env var | CLI flag | Type | Default | Description |
4949
|-------|---------|----------|------|---------|-------------|
50-
| `sandbox` | `KODE_SANDBOX` | `--sandbox` | bool | `false` | Enable/disable sandbox isolation |
51-
| `sandbox_image` | `KODE_SANDBOX_IMAGE` | `--sandbox-image` | string | `alpine:latest` | Docker image for the sandbox container |
52-
| `sandbox_network` | `KODE_SANDBOX_NETWORK` | `--sandbox-network` | string | `bridge` | Docker network mode |
53-
| `sandbox_readonly` | `KODE_SANDBOX_READONLY` | `--sandbox-readonly` | bool | `false` | Mount working directory read-only |
54-
| `sandbox_memory` | `KODE_SANDBOX_MEMORY` | `--sandbox-memory` | string | `""` | Memory limit (e.g. `512m`, `2g`) |
55-
| `sandbox_cpus` | `KODE_SANDBOX_CPUS` | `--sandbox-cpus` | string | `""` | CPU limit (e.g. `0.5`, `2`) |
56-
| `sandbox_user` | `KODE_SANDBOX_USER` | `--sandbox-user` | string | `""` | Run as user (`uid:gid` or name) |
50+
| `sandbox` | `ODEK_SANDBOX` | `--sandbox` | bool | `false` | Enable/disable sandbox isolation |
51+
| `sandbox_image` | `ODEK_SANDBOX_IMAGE` | `--sandbox-image` | string | `alpine:latest` | Docker image for the sandbox container |
52+
| `sandbox_network` | `ODEK_SANDBOX_NETWORK` | `--sandbox-network` | string | `bridge` | Docker network mode |
53+
| `sandbox_readonly` | `ODEK_SANDBOX_READONLY` | `--sandbox-readonly` | bool | `false` | Mount working directory read-only |
54+
| `sandbox_memory` | `ODEK_SANDBOX_MEMORY` | `--sandbox-memory` | string | `""` | Memory limit (e.g. `512m`, `2g`) |
55+
| `sandbox_cpus` | `ODEK_SANDBOX_CPUS` | `--sandbox-cpus` | string | `""` | CPU limit (e.g. `0.5`, `2`) |
56+
| `sandbox_user` | `ODEK_SANDBOX_USER` | `--sandbox-user` | string | `""` | Run as user (`uid:gid` or name) |
5757
| `sandbox_env` ||| object | `{}` | Extra env vars injected into container |
5858
| `sandbox_volumes` ||| array | `[]` | Extra volume mounts (`host:container`) |
5959

60-
> **Note:** `sandbox_env` and `sandbox_volumes` are config-file-only — they're too complex for flat env vars or CLI flags. For all other fields, env vars and CLI flags follow the standard `KODE_*` pattern.
60+
> **Note:** `sandbox_env` and `sandbox_volumes` are config-file-only — they're too complex for flat env vars or CLI flags. For all other fields, env vars and CLI flags follow the standard `ODEK_*` pattern.
6161
6262
### Env var examples
6363

6464
```bash
65-
KODE_SANDBOX=true \
66-
KODE_SANDBOX_IMAGE=python:3.12-slim \
67-
KODE_SANDBOX_NETWORK=none \
68-
KODE_SANDBOX_READONLY=true \
69-
KODE_SANDBOX_MEMORY=1g \
70-
KODE_SANDBOX_CPUS=4 \
71-
KODE_SANDBOX_USER=1000:1000 \
65+
ODEK_SANDBOX=true \
66+
ODEK_SANDBOX_IMAGE=python:3.12-slim \
67+
ODEK_SANDBOX_NETWORK=none \
68+
ODEK_SANDBOX_READONLY=true \
69+
ODEK_SANDBOX_MEMORY=1g \
70+
ODEK_SANDBOX_CPUS=4 \
71+
ODEK_SANDBOX_USER=1000:1000 \
7272
odek run "process untrusted data"
7373
```
7474

internal/config/loader.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ type CLIFlags struct {
4949
Learn *bool // nil = not set
5050
Task string
5151

52+
// PromptCaching enables prompt caching markers for supported providers.
53+
// Config: prompt_caching, ODEK_PROMPT_CACHING, --prompt-caching.
54+
PromptCaching *bool // nil = not set
55+
5256
// Sandbox-specific
5357
SandboxImage string
5458
SandboxNetwork string
@@ -92,6 +96,9 @@ type FileConfig struct {
9296
NoColor *bool `json:"no_color,omitempty"`
9397
NoAgents *bool `json:"no_agents,omitempty"`
9498

99+
// PromptCaching enables prompt caching markers for supported providers.
100+
PromptCaching *bool `json:"prompt_caching,omitempty"`
101+
95102
System string `json:"system,omitempty"`
96103

97104
// Sandbox-specific fields.
@@ -158,6 +165,7 @@ type ResolvedConfig struct {
158165
Sandbox bool
159166
NoColor bool
160167
NoAgents bool
168+
PromptCaching bool
161169
System string
162170

163171
// SandboxImage is the Docker image for the sandbox container.
@@ -380,6 +388,9 @@ func LoadConfig(cli CLIFlags) ResolvedConfig {
380388
if v := envBool("NO_AGENTS"); v != nil {
381389
cfg.NoAgents = v
382390
}
391+
if v := envBool("PROMPT_CACHING"); v != nil {
392+
cfg.PromptCaching = v
393+
}
383394
if v := envString("SYSTEM"); v != "" {
384395
cfg.System = v
385396
}
@@ -456,6 +467,9 @@ func LoadConfig(cli CLIFlags) ResolvedConfig {
456467
if cli.NoAgents != nil {
457468
cfg.NoAgents = cli.NoAgents
458469
}
470+
if cli.PromptCaching != nil {
471+
cfg.PromptCaching = cli.PromptCaching
472+
}
459473
if cli.Learn != nil {
460474
if cfg.Skills == nil {
461475
cfg.Skills = &SkillsConfig{}
@@ -532,6 +546,9 @@ func LoadConfig(cli CLIFlags) ResolvedConfig {
532546
if cfg.NoAgents != nil {
533547
resolved.NoAgents = *cfg.NoAgents
534548
}
549+
if cfg.PromptCaching != nil {
550+
resolved.PromptCaching = *cfg.PromptCaching
551+
}
535552
if cfg.SandboxReadonly != nil {
536553
resolved.SandboxReadonly = *cfg.SandboxReadonly
537554
}

0 commit comments

Comments
 (0)