Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
210 commits
Select commit Hold shift + click to select a range
6b85d9d
test(memory): pin the three source_scope predicates before inverting …
senamakel Aug 7, 2026
8d27a4e
test(memory): isolate the memory query tests from shared workspace te…
senamakel Aug 7, 2026
b778be9
chore(vendor): land the tinycortex-api memory contract crate
senamakel Aug 7, 2026
b2ba8d5
feat(config): add subsystems memory env overrides and shared engine c…
senamakel Aug 7, 2026
af5f0d7
chore(config): document the subsystems env overrides
senamakel Aug 7, 2026
4d43b84
feat(core): add the generic subsystem registry and driver vocabulary
senamakel Aug 7, 2026
a9c4e63
feat(memory): bind a memory driver per workspace behind the subsystem…
senamakel Aug 7, 2026
495fb44
fix(memory): correct global memory ordering
senamakel Aug 7, 2026
93ff488
fix(memory): correct global memory ordering
senamakel Aug 7, 2026
324154f
feat(memory): implement the embedded TinyCortex driver across all thi…
senamakel Aug 8, 2026
0b5ccb6
feat(memory): enforce policy through a MemoryGuard decorator
senamakel Aug 8, 2026
10cb8b4
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
f997da3
test(core): pin memory controller registry contiguity
senamakel Aug 8, 2026
a2f0a69
chore(memory): add schemas module
senamakel Aug 8, 2026
5f1f497
chore(memory): add schemas module
senamakel Aug 8, 2026
ca0eb64
chore(memory): remove unused module
senamakel Aug 8, 2026
921f267
chore(core): remove unused all module
senamakel Aug 8, 2026
31e6874
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
7659af2
chore(registry): add schema registry module
senamakel Aug 8, 2026
738c5b7
fix(memory): validate document metadata on schema load
senamakel Aug 8, 2026
20d8cae
fix(memory): validate document schema on load
senamakel Aug 8, 2026
d6d8f1c
chore(memory): add schemas module
senamakel Aug 8, 2026
78c30ba
chore(memory): add schema module for memory types
senamakel Aug 8, 2026
6c485d5
chore(memory): add schemas module
senamakel Aug 8, 2026
04d5523
chore(memory): add schema module for memory persistence
senamakel Aug 8, 2026
eb62ac4
chore(memory): add schema module for memory persistence
senamakel Aug 8, 2026
90994eb
chore(memory): remove unused module
senamakel Aug 8, 2026
ea57134
chore(memory): remove unused module
senamakel Aug 8, 2026
abedf71
chore(core): remove unused all module
senamakel Aug 8, 2026
0f22026
chore(core): remove unused all module
senamakel Aug 8, 2026
66a8f0f
chore(core): remove unused all module
senamakel Aug 8, 2026
b143757
chore(core): remove unused all module
senamakel Aug 8, 2026
f6bbaa5
chore(core): remove unused all module
senamakel Aug 8, 2026
70233b3
chore(core): remove unused all module
senamakel Aug 8, 2026
bdfadf2
chore(core): remove unused all module
senamakel Aug 8, 2026
ab772d9
chore(core): remove unused all module
senamakel Aug 8, 2026
40689b6
chore(core): remove unused all module
senamakel Aug 8, 2026
a278c9a
chore(core): remove unused all module
senamakel Aug 8, 2026
5cd346e
chore(core): remove unused all module
senamakel Aug 8, 2026
d5c3bda
chore(core): remove unused all module
senamakel Aug 8, 2026
7390f3c
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
0e020b6
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
8fe3bc8
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
3a1ade6
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
d9ae9f1
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
f1aa791
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
8786812
test(memory): add tests for memory schemas
senamakel Aug 8, 2026
f2ff5bf
chore: rename pinned controller order test reference
senamakel Aug 8, 2026
a8ab8d4
test: add temporary test to dump memory capabilities
senamakel Aug 8, 2026
056b8dc
chore(core): remove all_tests.rs
senamakel Aug 8, 2026
f07f4f0
test(memory): add capability registration filter tests
senamakel Aug 8, 2026
988ab56
test: reformat long assertions in capability tests
senamakel Aug 8, 2026
95d1411
chore(core): remove unused all module
senamakel Aug 8, 2026
c1efbf9
chore(ops): remove unused import in ops tool
senamakel Aug 8, 2026
5155be7
chore(ops): remove unused import in ops tool
senamakel Aug 8, 2026
7c0c418
test(tools): add drift guards for memory tool capability mapping
senamakel Aug 8, 2026
0395a26
test: remove obsolete memory tool capability drift guards
senamakel Aug 8, 2026
d879e6e
test: add drift guards for memory tool capability mapping
senamakel Aug 8, 2026
edb874e
fix(security): enforce policy on all admin actions
senamakel Aug 8, 2026
7081a1e
fix(security): enforce policy on all admin actions
senamakel Aug 8, 2026
db77c84
fix(memory): enforce policy guard on memory access
senamakel Aug 8, 2026
e6f516b
test(memory): add policy guard tests
senamakel Aug 8, 2026
bce2e4f
fix(binding): handle empty memory binding lists
senamakel Aug 8, 2026
135ca3f
refactor(memory): rename MemoryBinding::provider to unguarded_provider
senamakel Aug 8, 2026
33c4bc6
test(memory): add bypass allowlist tests
senamakel Aug 8, 2026
df6ea87
test(memory): add bypass allowlist tests
senamakel Aug 8, 2026
589c2f2
test(memory): add bypass allowlist tests
senamakel Aug 8, 2026
1a738f9
docs(specs): document the unguarded_provider allowlist entry
senamakel Aug 8, 2026
5b3439a
test(core): add null-driver degradation gate tests
senamakel Aug 8, 2026
dec6706
chore: format test assertions for readability
senamakel Aug 8, 2026
d284dae
test(core): add throwaway adversarial verification tests
senamakel Aug 8, 2026
6080341
test(core): add exhaustive null-driver degradation test for memory co…
senamakel Aug 8, 2026
3ef88d0
test(tools): add throwaway adversarial verification for tool degradation
senamakel Aug 8, 2026
7df33b3
chore: remove throwaway adversarial verification tests
senamakel Aug 8, 2026
fd7516c
chore(core): remove unused all module
senamakel Aug 8, 2026
e24efcd
fix(cli): handle missing capability gracefully
senamakel Aug 8, 2026
e1c4e1a
chore(core): remove unused module
senamakel Aug 8, 2026
c2b47fe
fix(cli): handle missing subcommand gracefully
senamakel Aug 8, 2026
248cac4
fix(cli): handle missing subcommand gracefully
senamakel Aug 8, 2026
65b0871
fix(core): add memory CLI module
senamakel Aug 8, 2026
5efb088
fix(core): add memory CLI module
senamakel Aug 8, 2026
d801d31
fix(core): pass command name to memory client factory
senamakel Aug 8, 2026
c21b36c
fix(core): add memory CLI module
senamakel Aug 8, 2026
07fd586
test(core): add capability gating tests for memory CLI
senamakel Aug 8, 2026
57b026a
chore(core): add CLI capability tests
senamakel Aug 8, 2026
b788017
test(core): cover unfiltered capability lookup for CLI config-fact
senamakel Aug 8, 2026
8283813
test(core): add capability-gate regression tests for CLI namespaces
senamakel Aug 8, 2026
8ee15e9
fix(cli): handle missing capability gracefully
senamakel Aug 8, 2026
6a5267a
fix(core): add memory CLI module
senamakel Aug 8, 2026
a5acb88
fix(core): add memory CLI module
senamakel Aug 8, 2026
b50edf3
fix(core): add memory CLI module
senamakel Aug 8, 2026
a200653
test(memory): add bypass allowlist tests
senamakel Aug 8, 2026
ec100df
docs(specs): add memory guard allowlist spec
senamakel Aug 8, 2026
6068ccd
docs(specs): add kernel specification
senamakel Aug 8, 2026
dc7145e
style: format multi-line expressions in core tests
senamakel Aug 8, 2026
030c6ee
chore(memory): rename chunk store module for clarity
senamakel Aug 8, 2026
224cf6f
refactor(memory): drop the chunks::produce re-export shim
senamakel Aug 8, 2026
162b2c8
refactor(raw_coverage): update FreshnessLabel path in e2e test
senamakel Aug 8, 2026
328b20a
chore(sync-status): add module for sync status tracking
senamakel Aug 8, 2026
ab03247
chore(sync-status): add rpc module for sync status queries
senamakel Aug 8, 2026
c81a6ce
chore(memory): add sync status schemas
senamakel Aug 8, 2026
eb405ae
refactor(memory): drop the sync_status::types re-export shim
senamakel Aug 8, 2026
643d483
chore(cli): add throwaway verification test module
senamakel Aug 8, 2026
79df76b
refactor(tests): update memory tree io type paths in e2e test
senamakel Aug 8, 2026
16c6d52
fix(memory): correct tree node pruning condition
senamakel Aug 8, 2026
9b7019c
fix(memory): correct tree node ordering on insert
senamakel Aug 8, 2026
0e5ddf9
refactor(memory): drop the tree::io re-export shim
senamakel Aug 8, 2026
55bd813
test(core): add probe for generic path under null driver
senamakel Aug 8, 2026
c4cdf0b
chore(search): add vector search tool
senamakel Aug 8, 2026
5ee73f5
chore(store): add memory store module
senamakel Aug 8, 2026
32e8023
refactor(tree-runtime): import shared types from tinycortex
senamakel Aug 8, 2026
1732747
refactor(tests): update tree runtime imports in turn tests
senamakel Aug 8, 2026
2b367c1
refactor(memory): drop the store::vectors re-export shim
senamakel Aug 8, 2026
9b08d40
refactor(memory): drop the tree_runtime::types re-export shim
senamakel Aug 8, 2026
19fc182
chore: remove throwaway capability verification tests
senamakel Aug 8, 2026
049ec85
refactor(github): pass workspace path to git_cache_dir
senamakel Aug 8, 2026
2e1339e
chore(github-reader): drop three dead items ahead of the move
senamakel Aug 8, 2026
0650dc9
style(memory): apply cargo fmt import ordering left by the shim removals
senamakel Aug 8, 2026
48263b4
style(github-reader): drop the blank line left by the dead-item removal
senamakel Aug 8, 2026
f673421
chore(vendor): bump tinycortex to fd996f5 (github/rss/web_page source…
senamakel Aug 8, 2026
70df2f8
refactor(sources): delegate the github, rss, and web_page readers to …
senamakel Aug 8, 2026
f06a989
chore(vendor): bump tinycortex for the Cargo.lock refresh
senamakel Aug 8, 2026
ddee224
chore(deps): bump tinycortex gitlink for normalize::helpers::pick_str
senamakel Aug 8, 2026
4fe5d91
fix(cli): gate gated functions before schema resolution
senamakel Aug 8, 2026
188bc88
chore(composio): add provider module for memory sync
senamakel Aug 8, 2026
8c39657
chore(composio): add helper for provider sync
senamakel Aug 8, 2026
35e18aa
chore(deps): bump tinycortex gitlink for providers::normalize
senamakel Aug 8, 2026
a84f2d3
fix(cli): check capability only for known functions
senamakel Aug 8, 2026
a110610
refactor(memory): source the Composio provider normalisers from tinyc…
senamakel Aug 8, 2026
dee3fb0
fix(cli): check capability before unknown function error
senamakel Aug 8, 2026
978c24a
chore(vendor): bump tinycortex for the ported obsidian and wiki-git s…
senamakel Aug 8, 2026
e97e0b9
refactor(content): delegate obsidian and wiki-git modules to tinycortex
senamakel Aug 8, 2026
9c47b16
chore(vendor): bump tinycortex for the ported pipeline failure taxonomy
senamakel Aug 8, 2026
ec1b97f
style(memory): apply rustfmt drift in two re-export blocks
senamakel Aug 8, 2026
21d764f
refactor(memory): re-export the failure taxonomy from tinycortex
senamakel Aug 8, 2026
6da4465
chore(vendor): bump tinycortex for the rustfmt-drift fixup
senamakel Aug 8, 2026
ad609d1
chore(vendor): rebase the tinycortex work onto upstream main
senamakel Aug 8, 2026
8cccaa6
chore(vendor): bump tinycortex for the relocated from_str lint fix
senamakel Aug 8, 2026
4efc2ca
Merge remote-tracking branch 'refs/remotes/upstream/main' into pr/5446
senamakel Aug 8, 2026
72bd2c2
chore: files changed app/src-tauri/Cargo.lock
senamakel Aug 8, 2026
5ef91c4
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
96b0b7c
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
dd47290
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
a598375
chore: files changed src/openhuman/memory/binding_tests.rs
senamakel Aug 8, 2026
b6a7fca
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
344ef13
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
c2855ba
chore: files changed src/openhuman/memory/binding_tests.rs
senamakel Aug 8, 2026
9be943f
chore: files changed src/core/subsystems_cli.rs
senamakel Aug 8, 2026
0c2779b
chore: files changed src/core/subsystems_cli.rs
senamakel Aug 8, 2026
32a0de2
chore: files changed src/core/cli_capability.rs
senamakel Aug 8, 2026
f7ed791
chore: files changed src/core/cli_capability.rs
senamakel Aug 8, 2026
4d7bac8
chore: files changed src/core/cli_capability.rs
senamakel Aug 8, 2026
3e7f0e0
chore: files changed src/core/cli_capability.rs
senamakel Aug 8, 2026
a8cb3cf
chore: files changed src/core/memory_cli.rs
senamakel Aug 8, 2026
699ca21
chore: files changed src/core/memory_cli.rs
senamakel Aug 8, 2026
7814ca2
chore: files changed src/core/memory_cli.rs
senamakel Aug 8, 2026
691c9c5
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
6bb64f0
chore: files changed src/openhuman/memory/ops/documents.rs
senamakel Aug 8, 2026
7de1ec9
chore: files changed src/openhuman/memory/ops/documents.rs
senamakel Aug 8, 2026
9edf2e4
chore: files changed src/openhuman/memory/ops/documents.rs
senamakel Aug 8, 2026
77327a7
chore: files changed src/openhuman/memory/ops/documents.rs
senamakel Aug 8, 2026
668cf5e
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
b5b6030
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
1b883d2
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
7bee039
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
31643e0
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
89d8744
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
2744861
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
a35a90e
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
4b68182
chore: files changed src/openhuman/desktop/app_state/ops.rs
senamakel Aug 8, 2026
a94c0d0
chore: files changed src/openhuman/config/schema/subsystems.rs
senamakel Aug 8, 2026
f867333
chore: files changed src/openhuman/config/schema/subsystems.rs
senamakel Aug 8, 2026
2b94792
chore: files changed src/openhuman/config/schema/subsystems.rs
senamakel Aug 8, 2026
d2a8665
chore: files changed scripts/kernel-floor.limits
senamakel Aug 8, 2026
f5cac92
chore: files changed src/openhuman/memory/tree/README.md
senamakel Aug 8, 2026
4798a36
chore: files changed src/openhuman/memory/tree/README.md
senamakel Aug 8, 2026
348068f
chore: files changed src/openhuman/memory/store/README.md
senamakel Aug 8, 2026
dd76abe
chore: files changed src/openhuman/memory/store/README.md
senamakel Aug 8, 2026
d3b7c68
chore: files changed src/core/subsystems_cli.rs
senamakel Aug 8, 2026
2ccd0cb
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
bf74d7f
chore: files changed src/core/runtime/context.rs
senamakel Aug 8, 2026
1fcb68d
chore: files changed src/openhuman/memory/bypass_allowlist_tests.rs
senamakel Aug 8, 2026
b6f19ec
chore: files changed docs/specs/memory-guard-allowlist.md
senamakel Aug 8, 2026
f29f5b2
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
c53c106
chore: files changed src/core/cli_capability.rs,src/core/memory_cli.r…
senamakel Aug 8, 2026
422ec58
chore: files changed .github/workflows/ci-lite.yml
senamakel Aug 8, 2026
298dbb4
Merge remote-tracking branch 'refs/remotes/upstream/main' into pr/5446
senamakel Aug 8, 2026
b569e4f
fix(memory): rebind subsystem config together with the workspace at l…
senamakel Aug 8, 2026
5e1a8d2
chore: files changed src/openhuman/config/schema/subsystems.rs
senamakel Aug 8, 2026
ab82708
chore: files changed src/openhuman/config/schema/subsystems.rs
senamakel Aug 8, 2026
f50cd7b
chore: files changed src/openhuman/config/schema/subsystems.rs
senamakel Aug 8, 2026
10d885c
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
4ebf4a4
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
248c408
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
d1c651f
chore: files changed src/openhuman/memory/ops/provider.rs
senamakel Aug 8, 2026
1bb7fbb
chore: files changed src/core/subsystems_cli.rs
senamakel Aug 8, 2026
a8857e2
chore: files changed docs/specs/memory-guard-allowlist.md
senamakel Aug 8, 2026
a9f9e56
chore: files changed src/openhuman/memory/bypass_allowlist_tests.rs
senamakel Aug 8, 2026
d6fc30e
chore: files changed src/openhuman/memory/binding_tests.rs
senamakel Aug 8, 2026
7301cc5
chore: files changed src/openhuman/memory/binding.rs
senamakel Aug 8, 2026
ffbab3f
Merge remote-tracking branch 'refs/remotes/upstream/main' into pr/5446
senamakel Aug 8, 2026
62d40cb
fix(core): bind workspace config atomically
senamakel Aug 8, 2026
030dc90
Merge remote-tracking branch 'refs/remotes/upstream/main' into pr/5446
senamakel Aug 8, 2026
e3ef3f2
fix(memory): gate raw calls and update dependency bindings
senamakel Aug 8, 2026
9bcfa14
fix(memory): satisfy clippy cache and reader lints
senamakel Aug 8, 2026
bed19be
test(core): stabilize registry and policy coverage
senamakel Aug 8, 2026
c0eb627
Merge remote-tracking branch 'refs/remotes/upstream/main' into pr/5446
senamakel Aug 9, 2026
a2e2492
fix(memory): address codex review findings and repair merged test fix…
senamakel Aug 9, 2026
9d75a4a
Merge remote-tracking branch 'upstream/main' into pr/5446
senamakel Aug 9, 2026
779ce1f
Merge remote-tracking branch 'upstream/main' into pr/5446
senamakel Aug 9, 2026
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
15 changes: 15 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,21 @@ OPENHUMAN_ANALYTICS_ENABLED=true
# (periodic auto-sync disabled). Unset → 24h default.
# OPENHUMAN_MEMORY_SYNC_INTERVAL_SECS=86400

# ---------------------------------------------------------------------------
# Subsystem driver binding ([subsystems.memory] — kernel.md §3.6)
# ---------------------------------------------------------------------------
# Which driver answers for the memory subsystem, and the memory-hook budgets.
# NOTHING READS THESE YET — the config surface exists so bindings can be
# authored ahead of the registry landing. Defaults reproduce today's behaviour.
# Per-driver option tables ([subsystems.memory.drivers.<id>], incl. the
# fail-closed `trust_state`) are config-file only; there is no env form.
# OPENHUMAN_MEMORY_DRIVER=tinycortex
# OPENHUMAN_MEMORY_HOOKS_AUTO_RECALL=true
# OPENHUMAN_MEMORY_HOOKS_AUTO_CAPTURE=true
# OPENHUMAN_MEMORY_HOOKS_MAX_CONTEXT_TOKENS=2000
# OPENHUMAN_MEMORY_HOOKS_RECALL_MAX_CHARS=1000
# OPENHUMAN_MEMORY_HOOKS_CAPTURE_MAX_CHARS=500

# ---------------------------------------------------------------------------
# Logging
# ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-lite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ jobs:
#
# This asserts the calibration still holds. If it fails, every
# projection built on the simulator is suspect until it is fixed.
run: python3 scripts/dep-sim.py --cut-nothing --expect-names 285
run: python3 scripts/dep-sim.py --cut-nothing --expect-names 286

- name: Guard — new feature-gated test modules must be acknowledged
# Self-maintaining coverage: the set of source files that #[cfg]-gate a test on
Expand Down
18 changes: 18 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,23 @@ tinyagents = { version = "2.1", features = ["sqlite"] }
# aligned to the host pins (=0.40 / 0.21) so one bundled SQLite + one libgit2
# link. The submodule intentionally tracks reviewed upstream main commits;
# keep this semver requirement compatible with the vendored crate version.
tinycortex = { version = "0.1", features = ["git-diff", "persona", "sync"] }
tinycortex = { version = "0.1", features = [
"git-diff",
"obsidian",
"persona",
"sync",
"wiki-git",
] }
# The memory *contract* — value types, the thirteen capability families, the
# `MemoryProvider` driver trait, and the null reference driver. A direct path
# dependency rather than a re-export, because `tinycortex::memory` aliases back
# only `{error, traits, types}`; `capabilities`, `provider`, `null`, `health`,
# `recall`, and `version` are reachable only through the api crate itself.
# Deliberately dependency-light (no rusqlite/git2/reqwest/regex/async runtime)
# so a third-party driver can compile against the contract without pulling in
# the embedded engine. No `[patch.crates-io]` entry is needed: cargo unifies
# this with the `path = "api"` dependency the engine crate already declares.
tinycortex-api = { path = "vendor/tinycortex/api" }
tinychannels = { version = "0.1", features = ["relay-websocket"] }
# tinybus — the message bus. Owns what `src/core/event_bus/` used to: the typed
# pub/sub surface (`EventBus`, `EventHandler`, `SubscriptionHandle`), the
Expand Down
18 changes: 18 additions & 0 deletions app/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions docs/specs/kernel.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@ The one exception is the **CLI**, which keeps its subcommand arm and reports a *
("memory driver `supermemory` does not support tree summarisation") — same reasoning as the
retained `mcp` and `tui` CLI arms.

Implemented for memory at the CLI boundary. `core::cli_capability` resolves the bound driver
directly — no CLI subcommand except `run`/`serve` builds a `CoreContext`, so the ambient
`capability_allowed` gate would always default open — and `core::all::capability_for_parts` /
`sole_capability_for_namespace` supply the **unfiltered** lookup that tells "no such command"
apart from "gated", which every filtered lookup has already collapsed into one absence. Both CLI
paths are covered: the generic `openhuman <namespace> <function>` dispatcher and the hand-written
`openhuman memory <sub>` adapter. `core::dispatch` is deliberately untouched — it is the shared
`/rpc` path, where the absence rule above still holds. A genuinely unknown command still reports
unknown namespace / function / subcommand; collapsing the two would make real typos harder to
diagnose.

### 3.4 Policy is kernel-side and non-bypassable

Every subsystem call from product code goes through a kernel-owned **guard decorator**, never to
Expand Down
158 changes: 158 additions & 0 deletions docs/specs/memory-guard-allowlist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Memory-guard allowlist

Every place in the tree that still reaches memory **without** going through
`MemoryGuard`, and why. Produced by M4b; consumed by M4c.

Pinned by the ratchet in `src/openhuman/memory/bypass_allowlist_tests.rs`
(M4c), which fails **both ways** — when a new unguarded call site appears
(`no_new_memory_driver_bypasses`), and when an allowlisted one is cleaned up
without being struck from the list (`bypass_allowlist_has_no_stale_entries`).
Two further tests stop the lint rotting into a rubber stamp: the scanner must
find a known bypass, and every needle must still match something.

M4b shipped a provisional, file-keyed version of this guard inside
`memory/ops/guard_tests.rs`. M4c deleted it — two allowlists over one tree must
both be struck on every cleanup, and the one nobody remembers is exactly the
dead-string rot the ratchet exists to prevent.

## Scope

The lint scans `src/` for twelve patterns, keyed on `(file, pattern)` so the
failure message names the needle that tripped:

| Pattern | What it hands out |
| --- | --- |
| `active_memory_client(` | `MemoryClientRef` |
| `global::client_if_ready(` / `global::client(` | `MemoryClientRef` |
| `.memory_handle(` | raw `Arc<dyn Memory>` |
| `.profile_conn(` | raw `Arc<Mutex<rusqlite::Connection>>` |
| `.get_document(` | `pub(crate)` read-one escape hatch |
| `EmbeddedMemoryProvider::new(` / `NullMemoryProvider::new(` | a driver, built outside `binding::for_workspace` |
| `MemoryClient::from_workspace_dir(` | a second engine on the same store |
| `binding::for_workspace(` / `.memory_binding(` | a raw `MemoryBinding` |
| `.unguarded_provider(` | the raw `Arc<dyn MemoryProvider>` off a `MemoryBinding` |

**By-path test files (`*_tests.rs`, `tests.rs`, `test_support/`) are out of
scope.** Driver tests construct drivers — that is what a driver test *is* —
so allowlisting them would add ~25 entries that can never shrink and would
churn on every new test. Inline `#[cfg(test)] mod tests` blocks are *not*
stripped, because brace-tracking Rust with a line scanner is fragile and
getting it wrong silently hides production sites; the three files affected are
allowlisted with a reason saying so. Comment lines are skipped, so doc-comment
references are not mistaken for calls.

`global::init(workspace)` is deliberately **not** scanned. It binds the
workspace; it does not read or write memory, and every call site is a
login / active-user-switch / boot / CLI-entry lifecycle event
(`security/credentials/ops.rs`, `desktop/app_state/ops.rs`,
`core/runtime/context.rs`, `core/memory_cli.rs`, `core/subconscious_cli.rs`,
`bin/slack_backfill.rs`, `bin/gmail_backfill_3d.rs`,
`memory/ops/documents.rs`'s `memory_init`, `memory/tinycortex/sync.rs`).

## What M4b re-pointed

Four RPC handlers, all in `src/openhuman/memory/ops/`, each of whose contract
twin is a literal one-line delegation to the same host method on the same
store:

| Handler | Contract method | Driver body |
| --- | --- | --- |
| `documents::doc_put` | `MemoryDocuments::put_document` | `client.put_doc(input)` |
| `kv_graph::kv_set` | `MemoryGraph::kv_put` | `client.kv_set(ns, key, &value)` |
| `tool_memory::tool_rule_list` | `MemoryToolMemory::tool_rules` | `tool_memory_store(memory).list_rules(tool)` |
| `tool_memory::tool_rule_delete` | `MemoryToolMemory::delete_tool_rule` | `tool_memory_store(memory).delete_rule(tool, id)` |

**Three deltas ride along, and they are the point of the milestone, not
accidents:**

1. **Tier enforcement.** A write now goes through `ToolOperation::Act`, so a
`readonly` autonomy tier refuses it and the hourly action budget is charged
one unit. Reads take `ToolOperation::Read`, which `SecurityPolicy` answers
`Ok` for unconditionally today.
2. **Error strings gain a method prefix.** The driver wraps host failures
through `host_error(context, error)`, so `"<orig>"` becomes
`"put_document: <orig>"`. Additive context, never a swallowed cause.
3. **Taint may be raised.** `doc_put` still passes `MemoryTaint::Internal`; the
guard's `stamp_taint` promotes it to `ExternalSync` when the turn runs under
a source scope. It can never launder the other direction.

Redaction is a byte-identical pass-through for an embedded driver, and the
ambient source scope is applied only on `MemoryTree::query_source`, so neither
changes anything here.

## The allowlist

### A. Legitimate residents — the driver, the seam, the bind site

| Path | Reason |
| --- | --- |
| `memory/driver/embedded/mod.rs` | This **is** the driver. Guarding it would be a cycle. |
| `memory/driver/embedded/tool_memory_tests.rs` | Driver tests. |
| `memory/tinycortex/sync.rs` | The engine seam. |
| `memory/global.rs` | The process-global slot itself. |
| `memory/ops/helpers.rs` | Defines `active_memory_client`. |
| `memory/ops/guard.rs`, `guard_tests.rs` | The guarded resolver; matches only in prose and in its own fallback. |
| `memory/ops/provider.rs` (`.unguarded_provider(`) | Health probe on the bound driver; a liveness probe is not product code. |
| `core/cli_capability.rs` (`binding::for_workspace(`) | The CLI's capability gate (`kernel.md` §3.3's one exception to "degradation is absence"). Reads the driver id and advertised capability set only — the same two values `memory.provider_status` already returns over RPC — and never reaches memory content. No CLI subcommand except `run`/`serve` builds a `CoreContext`, so `CoreContext::memory()` resolves to nothing and there is no guard to route through. `core/memory_cli.rs` calls `bound_memory_driver_for` rather than binding itself. |
| `core/subsystems_cli.rs` | The `openhuman subsystems` slot table. Delegates to `memory_subsystem_status` (which itself resolves the binding in `memory/ops/provider.rs`, already allowlisted above), so `subsystems_cli.rs` never touches `binding::for_workspace(` directly — the CLI's command arms go through `bound_memory_driver_for`. |

### B. Unguardable raw SQLite — `profile_conn()`, out of scope for M4

No decorator can wrap an `Arc<Mutex<rusqlite::Connection>>`. These reach the
profile / facet tables beneath all seven policy steps. **This is why "the guard
is the only path" is not yet a true invariant.**

| Path | Sites |
| --- | --- |
| `memory/sync/composio/providers/profile.rs` | 5 |
| `agent/learning/schemas.rs` | 3 |
| `agent/learning/tools.rs` | 1 |
| `agent/learning/startup.rs` | 2 |
| `memory/store/client_tests.rs` | 2 (test) |

The brief named only the first two files. The other two were found by grep and
are recorded here so M4c starts from the real set.

### C. Needs a concrete engine type the contract does not expose

| Path | Reason |
| --- | --- |
| `agent/experience/ops.rs` | `AgentExperienceStore::new` takes `Arc<dyn Memory>`; the non-`"memory"` subdir branch also builds `UnifiedMemory::new_with_memory_dir` directly — a per-profile store the binding has no concept of. |
| `agent/harness/session/builder/factory.rs` | `.memory_handle()` → `Arc<dyn Memory>`. |
| `flows/tinyflows/memory_adapter.rs` | Returns `Arc<dyn Memory>` to satisfy a tinyflows engine trait. The contract has no `Arc<dyn Memory>` door. |
| `flows/bus.rs` | `resolve_memory() -> Option<Arc<dyn Memory>>`, and carries a `#[cfg(test)] memory_override` seam a guard would bypass. |
| `memory/tool_memory/tools/list.rs`, `tools/put.rs` | Agent tools building `ToolMemoryStore` from `memory_handle()`. Re-pointable in principle via `as_tool_memory()` — **deferred to M5**, which filters the tool surface by capability and would collide with a re-point made now. |
| `memory/ops/tool_memory.rs` (`open_store`) | Still needed by the four handlers left on the client. Shrank; did not disappear. |

### D. No contract method exists, or the wire shape would change

| Path | Reason |
| --- | --- |
| `memory/ops/documents.rs` — `namespace_list`, `doc_ingest`, `doc_list`, `doc_delete`, `clear_namespace`, `context_query`, `context_recall`, `memory_*` | Each answers with a `serde_json::Value` / `String` shape with no typed contract twin; `clear_namespace` has no contract method at all; `memory_query_namespace` depends on `query_limit_for_request(client: &MemoryClient, …)`. |
| `memory/ops/kv_graph.rs` — `kv_get`, `kv_delete`, `kv_list_namespace`, `graph_upsert`, `graph_query` | `kv_get` is an O(slice) scan in the driver and returns `MemoryKvRecord`, not `Value`; `kv_delete` has **no** contract method; `graph_query`'s camelCase→typed conversion is documented as new and lossy. |
| `memory/ops/tool_memory.rs` — `tool_rule_put`, `tool_rule_get`, `tool_rules_json`, `tool_rules_for_prompt` | `put_tool_rule` returns unit while the RPC returns the stored rule with a refreshed `updated_at`; the other three have no contract equivalent. |
| `memory/ops/sync.rs` | `client.ingestion_state().snapshot()` — queue telemetry, absent from the contract. |
| `memory/ops/learn.rs` | `list_namespaces() -> Vec<String>` vs the contract's `Vec<NamespaceSummary>`, then heavy engine work. |
| `flows/ops.rs` | `clear_namespace` (no contract method) plus a `memory_client_override` test seam. |
| `integrations/composio/schemas.rs` | Passes `&MemoryClientRef` into `user_scopes::save`. |
| `memory/sync/composio/providers/user_scopes.rs`, `types.rs` | Same `&MemoryClientRef` parameter shape. |

### E. Tests

`flows/ops_tests.rs`, `flows/tinyflows/memory_node_e2e_tests.rs`,
`integrations/composio/ops_tests.rs`, `core/runtime/context.rs` (its `#[cfg(test)]`
module).

## Honest scorecard

Four of the twenty-eight `active_memory_client()` call sites now route through
the guard. Eleven non-test `profile_conn()` sites and twelve non-test
`memory_handle()` sites still hand out raw handles. The defensible claim for M4
is therefore:

> Every memory RPC handler whose contract twin is a literal delegation now
> routes through the guard, and every remaining bypass is enumerated here with
> a reason and pinned by a drift guard.

"Impossible to skip by construction" is **not** true until `memory_handle()`
and `profile_conn()` are gone.
19 changes: 18 additions & 1 deletion scripts/kernel-floor.limits
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@
# Simulate with: scripts/dep-sim.py --cut <crates>
#
# History
# 307/284/5 2026-08-09 merge upstream/main + PR #5446 memory-subsystem work.
# Measured, not derived: `scripts/kernel-floor.sh flows`
# reports 307/284/5 on this merge. +3 names over the
# 304/281/5 below, and the split matters:
# * +2 INHERITED — `tinybus` + `tinybus-macros`, vendored
# by upstream #5459. The event bus is always-on kernel
# surface, so they are in the `flows` profile there too;
# upstream landed them without moving this number.
# * +1 OURS — `tinycortex-api`, the memory contract crate
# (`MemoryProvider`, `Capabilities`, `NullMemoryProvider`)
# that `MemorySubsystemConfig` -> `MemoryBinding` now
# depends on directly. It was already in the graph
# transitively via `tinycortex`, so no *new* third-party
# code enters the kernel profile — only a new direct edge.
# The -6 packages / -1 native from the tokio-tungstenite
# unification below is preserved, not spent: native builds
# stay at 5 and aws-lc-sys stays absent.
# 304/281/5 2026-08-08 local whisper.cpp STT deleted (`whisper-rs` +
# `whisper-rs-sys` out of BOTH Cargo worlds, and the
# `[patch.crates-io] whisper-rs-sys` fork entries with
Expand Down Expand Up @@ -130,4 +147,4 @@
# Native: aws-lc-sys libgit2-sys libsqlite3-sys libz-sys
# lzma-sys ring. Target after gating is 222 names / 2 native
# (libsqlite3-sys, ring) — see docs/plans MIGRATION-PLAN G6.
flows:304:281:5
flows:307:284:5
1 change: 1 addition & 0 deletions src/bin/library_profile/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ fn model_response(response: ChatResponse) -> ModelResponse {
raw: None,
resolved_model: None,
continue_turn: None,
served_from_cache: false,
}
}

Expand Down
Loading
Loading