Skip to content

Commit 16704a6

Browse files
committed
docs: memory system docs + CI fix for subagent/security tests
- README.md: persistent memory feature section - docs/CONFIG.md: memory config section - docs/MEMORY.md: full design doc (already in previous commit) - .github/workflows/test.yml: build binary before tests + KODE_BINARY env - security_e2e_test.go: fix assertions for non-root CI environment
1 parent f2a1dd6 commit 16704a6

4 files changed

Lines changed: 61 additions & 6 deletions

File tree

.github/workflows/test.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ jobs:
1616
with:
1717
go-version: "1.24"
1818

19+
- name: build
20+
run: go build -o /tmp/kode-test github.com/BackendStack21/kode/cmd/kode && chmod +x /tmp/kode-test
21+
1922
- name: test
20-
run: go test ./... -race -coverprofile=coverage.out -covermode=atomic -count=1
23+
run: KODE_BINARY=/tmp/kode-test go test ./... -race -coverprofile=coverage.out -covermode=atomic -count=1
2124

2225
- name: coverage
2326
run: go tool cover -func=coverage.out

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ kode run "Fix the OOM bug in default-hooks.js"
2222
- **Multi-turn**`kode run --session` and `kode continue` for persistent conversations
2323
- **Configurable** — 4-layer config (global → project → env → CLI), `${VAR}` substitution
2424
- **Skills system** — On-demand knowledge through trigger‑matched SKILL.md files. Auto‑learn patterns with `--learn`. Import skills from URIs with LLM risk assessment.
25+
- **Persistent memory** — Three‑tier memory system (facts + session buffer + episode search). Agent‑managed via `memory` tool. Merge‑on‑write with go‑vector similarity detection saves ~80% LLM calls.
2526

2627
## Install
2728

@@ -122,6 +123,24 @@ kode version # Print version
122123
--no-agents # Skip AGENTS.md
123124
```
124125

126+
## Features
127+
128+
### Persistent Memory
129+
130+
Three tiers managed automatically by the agent via the `memory` tool:
131+
132+
| Tier | Storage | Cap | Managed by |
133+
|------|---------|-----|------------|
134+
| Facts | `~/.kode/memory/facts/{user,env}.md` | 1,500 + 2,500 chars | Agent via `memory` tool |
135+
| Buffer | In-session ring | 20 lines | Auto-appended each turn |
136+
| Episodes | `~/.kode/memory/episodes/<id>.md` | 1 KB each | LLM-extracted on session end |
137+
138+
The agent can **add**, **replace**, **remove**, **consolidate**, **read**, or **search** memory using a single `memory` tool with six actions.
139+
140+
**Merge-on-write** uses go-vector RandomProjections to detect duplicate entries before writing — cosine >0.7 auto-merges, <0.3 auto-adds, 0.3-0.7 asks the LLM. Saves ~80% of LLM calls.
141+
142+
See [docs/MEMORY.md](docs/MEMORY.md) for the full design.
143+
125144
## Programmatic API
126145

127146
```go

cmd/kode/security_e2e_test.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ func TestSecurity_WriteFile_DestructivePath(t *testing.T) {
110110

111111
func TestSecurity_WriteFile_CustomAllowlist(t *testing.T) {
112112
// /etc is system_write → deny by default in deny-non-interactive mode.
113-
// But an allowlist for this specific path should override.
113+
// But non_interactive=allow should override the security denial.
114+
// Note: the actual os.WriteFile may still fail due to filesystem
115+
// permissions (we're not root in CI). That's OK — we're testing
116+
// that the security layer allows the operation, not that the
117+
// filesystem write succeeds.
114118
allow := "allow"
115119
dc := danger.DangerousConfig{
116120
NonInteractive: &allow,
@@ -119,9 +123,10 @@ func TestSecurity_WriteFile_CustomAllowlist(t *testing.T) {
119123
result := callJSON(t, tool, `{"path":"/etc/passwd","content":"hack"}`)
120124
var r struct{ Error string `json:"error"` }
121125
mustUnmarshal(t, result, &r)
122-
// With non_interactive=allow, all operations are allowed
123-
if r.Error != "" {
124-
t.Errorf("expected allow with non_interactive=allow, got: %s", r.Error)
126+
// With non_interactive=allow, the security layer should NOT issue
127+
// a denial. A filesystem-level permission error is acceptable.
128+
if strings.Contains(r.Error, "denied") {
129+
t.Errorf("expected security layer to allow, got denial: %s", r.Error)
125130
}
126131
}
127132

@@ -354,7 +359,7 @@ func TestSecurity_ClassOverride_SystemWriteAllowed(t *testing.T) {
354359
var r struct{ Error string `json:"error"` }
355360
mustUnmarshal(t, result, &r)
356361
// Write will fail because /etc is not writable, but it should NOT be a security denial
357-
if r.Error != "" && strings.Contains(r.Error, "denied") {
362+
if r.Error != "" && (strings.Contains(r.Error, "security") || strings.Contains(r.Error, "class")) {
358363
t.Errorf("expected no security denial after system_write=allow, got: %s", r.Error)
359364
}
360365
// Error should be "cannot create directory" or similar FS error, not a config denial

docs/CONFIG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,34 @@ The `skills` section controls the skill system:
110110
| `curation.staleness_days` || 90 | Days without use before flagging as stale |
111111
| `curation.auto_prune` || false | Auto-delete stale skills on curate (no prompt) |
112112

113+
## Memory configuration
114+
115+
The `memory` section controls the persistent memory system (see [docs/MEMORY.md](docs/MEMORY.md)):
116+
117+
```json
118+
{
119+
"memory": {
120+
"enabled": true,
121+
"facts_limit_user": 1500,
122+
"facts_limit_env": 2500,
123+
"buffer_lines": 20,
124+
"buffer_enabled": true,
125+
"merge_on_write": true,
126+
"extract_on_end": true
127+
}
128+
}
129+
```
130+
131+
| Field | Default | Description |
132+
|-------|---------|-------------|
133+
| `enabled` | true | Enable memory system entirely |
134+
| `facts_limit_user` | 1500 | Max chars for `user.md` fact file |
135+
| `facts_limit_env` | 2500 | Max chars for `env.md` fact file |
136+
| `buffer_lines` | 20 | Max turn summaries in session buffer |
137+
| `buffer_enabled` | true | Enable the turn-level buffer |
138+
| `merge_on_write` | true | Use go-vector RP similarity to auto-merge related entries |
139+
| `extract_on_end` | true | Extract durable facts via LLM at session end (≥3 turns) |
140+
113141
## Sub-agent configuration
114142

115143
The `subagent` section controls task decomposition and parallel sub-agent execution (see [docs/SUBAGENTS.md](docs/SUBAGENTS.md)):

0 commit comments

Comments
 (0)