Skip to content
Open
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The goal is a trustworthy substrate for coding agents that can:
- **Candidate claim workflow** — episodic events can produce staged claims that are promoted or rejected explicitly.
- **Observation continuity surfaces** — episodic events can produce privacy-checked, source-backed observations that are recallable by ID, summarized by compaction, and coverage-accounted across full session event ranges.
- **Continuity reliability controls** — coverage accounting, deterministic `catch-up`, gap warnings in summaries, destructive prune operations blocked when gaps remain, prune markers preserved in logs, and audit-aware observation recall.
- **MCP/OAuth server** — `aver-server` exposes memory tools over Streamable HTTP MCP behind a local OAuth-style token flow, including the ADR-0008 five-tool surface with validated recall/write/event/extraction-trigger parameters, observation projection tools, explicit unsupported-scope errors, persisted confidence overrides, and recall subgraphs with confidence floors.
- **MCP/OAuth server** — `aver-server` exposes memory tools over Streamable HTTP MCP behind a local OAuth-style token flow, including the ADR-0008 five-tool surface with validated recall/write/event/extraction-trigger parameters, observation projection tools, ADR-0021/0022 scoped memory parameters and connection defaults, persisted confidence overrides, and recall subgraphs with confidence floors.
- **Evaluation harnesses** — fixture evaluation plus a BEAM100K runner using local Ollama for embeddings, answer generation, and judging.

## Quick Start
Expand Down Expand Up @@ -219,6 +219,8 @@ MCP currently exposes 18 tools through a progressive discovery card so agents ke

Aver's MCP guide is intentionally proactive but selective: agents should recall first, then record durable user-shared preferences, project facts, and long-lived working context even when the user does not say "remember this" explicitly. Identity details should be recorded only when they are necessary, user-shared, and not sensitive personal data. When durability is uncertain, agents should prefer `record_event` over `remember_claim`, and they must not store secrets, credentials, sensitive personal data, transient chat, or facts they cannot explain with provenance.

Scope is a first-class memory dimension. Write tools such as `remember_claim`, `add_triple`, `record_event`, `record_observation`, and `propose_candidate_claim` accept an optional `scope`; when omitted through MCP, the request's ADR-0022 resolved scope applies, falling back to `global` for clients that send no scope signal. Read tools (`recall`, `expand`) accept `scope` plus `scope_walk`: use `ancestors` for normal project memory, `exact` for isolation, `descendants` for subtree audits, and `any` only for intentional cross-scope search. Vector chunks do not carry their own scope; they attach to a claim and inherit the claim's effective scope.

CLI-only continuity and maintenance surfaces (`catch-up`, `compaction-summary`) are implemented in `aver-cli`; MCP exposes `record_observation`, `assemble_compaction_summary`, and the observation audit tools above, while claim-maintenance tasks stay available through the four advanced tools when agents explicitly need them.

Adapter boundaries are explicit in `aver-server` via the `adapters` module (`Pi`, `ClaudeCode`, `CodexOpenAi`, `OpenCode`, `Mcp`, `JsonlCliHarness`) so host runtimes can be added without leaking host-specific logic into `aver-core`.
Expand Down
2 changes: 2 additions & 0 deletions autoresearch.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,5 @@
{"run":536,"commit":"74552c9","metric":807,"metrics":{"tests_green":807,"tests_total":807,"milestone_index":9,"loc_core":6951,"commit_count_total":600,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject non-positive predicate closure children","timestamp":1779052727528,"segment":28,"confidence":6.3538461538461535,"asi":{"hypothesis":"Predicate closure child_id links should reject non-positive values so predicate ontology transitive-closure rows get precise diagnostics before foreign-key handling.","red_evidence":"`cargo test -q -p aver-core --test migrations predicate_closure_child_id_must_be_positive` failed for the intended reason after using the seeded `uses` predicate type: child_id=0 produced a generic foreign-key error.","green_evidence":"Targeted predicate closure child-id test passed; full migrations test passed with 110 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=807 tests_total=807.","implementation_notes":"Added migration `0115_predicate_closure_child_id_positive_checks.sql` with insert/update triggers rejecting predicate_closure.child_id <= 0.","anti_overfit_note":"This is a general predicate ontology closure integrity invariant and does not use benchmark expected outputs or labels."}}
{"run":537,"commit":"74fbeab","metric":808,"metrics":{"tests_green":808,"tests_total":808,"milestone_index":9,"loc_core":6951,"commit_count_total":601,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject non-positive predicate closure ancestors","timestamp":1779052824413,"segment":28,"confidence":6.369230769230769,"asi":{"hypothesis":"Predicate closure ancestor_id links should reject non-positive values so predicate ontology transitive-closure rows get precise diagnostics before foreign-key handling.","red_evidence":"`cargo test -q -p aver-core --test migrations predicate_closure_ancestor_id_must_be_positive` failed because ancestor_id=0 produced a generic foreign-key error.","green_evidence":"Targeted predicate closure ancestor-id test passed; full migrations test passed with 111 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=808 tests_total=808.","implementation_notes":"Added migration `0116_predicate_closure_ancestor_id_positive_checks.sql` with insert/update triggers rejecting predicate_closure.ancestor_id <= 0.","anti_overfit_note":"This is a general predicate ontology closure integrity invariant and does not use benchmark expected outputs or labels."}}
{"run":538,"commit":"5547e6f","metric":809,"metrics":{"tests_green":809,"tests_total":809,"milestone_index":9,"loc_core":6951,"commit_count_total":602,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject blank predicate alias notes","timestamp":1779052989417,"segment":28,"confidence":6.384615384615385,"asi":{"hypothesis":"Predicate alias notes are optional, but when present they should be nonblank so alias provenance remains meaningful and auditable.","red_evidence":"`cargo test -q -p aver-core --test migrations predicate_alias_note_must_not_be_blank_when_set` failed because direct SQL accepted a whitespace-only note.","green_evidence":"Targeted predicate alias note test passed; full migrations test passed with 112 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=809 tests_total=809.","implementation_notes":"Added migration `0117_predicate_alias_note_nonblank_checks.sql` with insert/update triggers rejecting non-null trimmed-empty predicate_alias.note values.","anti_overfit_note":"This is a general predicate alias auditability invariant and does not use benchmark expected outputs or labels."}}
{"run":539,"commit":"54da71f","metric":810,"metrics":{"tests_green":810,"tests_total":810,"milestone_index":9,"loc_core":6951,"commit_count_total":603,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject self-parent ontology extensions","timestamp":1779053189044,"segment":28,"confidence":6.351145038167939,"asi":{"hypothesis":"Ontology extension audit rows should reject self-parenting predicate relationships so the extension log cannot encode a cyclic immediate parent edge.","red_evidence":"`cargo test -q -p aver-core --test migrations ontology_extension_parent_must_not_self_reference` failed because direct SQL accepted predicate='uses' with parent='uses'.","green_evidence":"Targeted ontology extension self-parent test passed; full migrations test passed with 113 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=810 tests_total=810.","implementation_notes":"Added migration `0118_ontology_extension_parent_not_self_checks.sql` with insert/update triggers rejecting ontology_extension_log rows where parent equals predicate.","anti_overfit_note":"This is a general ontology hierarchy audit invariant and does not use benchmark expected outputs or labels."}}
{"run":540,"commit":"54da71f","metric":471,"metrics":{"tests_green":471,"tests_total":472,"milestone_index":9,"loc_core":6951,"commit_count_total":604,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":0,"mean_recall_at_k":0,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"crash","description":"Predicate type created_via trigger broke legacy migration replay","timestamp":1779053310404,"segment":28,"confidence":6.4,"asi":{"hypothesis":"Predicate type created_via should reject blank creation-source strings for auditability.","rollback_reason":"`./autoresearch.sh` failed because vector_index migration replay hit `error in trigger predicate_type_created_via_nonblank_insert after drop column: no such column: NEW.created_via`; older migration replay paths may temporarily lack the audit column, so this trigger placement is unsafe.","next_action_hint":"Do not retry a trigger that references predicate_types.created_via without first understanding the legacy vector_index replay/drop-column path; prefer a different invariant on stable columns or a migration-safe implementation.","error_details":"crates/aver-core/tests/vector_index.rs migration_backfills_existing_vector_chunks_rows failed after targeted migrations tests passed.","anti_overfit_note":"The attempted invariant was general auditability, not benchmark-specific, but implementation violated migration replay compatibility."}}
1 change: 1 addition & 0 deletions crates/aver-server/src/mcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ fn mcp_tool_instructions() -> String {
"Default active set: {}. ",
"Decision policy: recall before answering when durable memory may matter; remember_claim only for explicit stable long-term facts; record_event for useful raw history; record_observation and assemble_compaction_summary for source-backed continuity. ",
"Self-healing writes: predicates are strict, but unknown-predicate errors include fuzzy/semantic suggestions, accepted aliases, and a retry hint; retry with a suggested predicate rather than inventing new predicates or silently rewriting claims. Use `relates_to` as the safest generic fallback when no precise predicate fits. ",
"Scope policy: pass `scope` only for an explicit per-call override; otherwise the request's resolved scope applies. For scoped reads, use `scope_walk=ancestors` for normal project memory, `exact` for isolation, `descendants` for subtree audits, and `any` only for cross-scope search. ",
"Proactive memory policy: record durable user-shared preferences, project facts, and long-lived working context even without a direct remember command; only record identity details when they are necessary, user-shared, and not sensitive personal data; prefer record_event over remember_claim when durability is uncertain. Avoid storing secrets, credentials, sensitive personal data, transient chat, or facts you cannot explain with provenance. ",
"Default workflows: recall existing memory before answering or updating; record_event -> should_extract_memories -> propose_candidate_claim/list_candidate_claims -> promote_candidate_claim or reject_candidate_claim for event-to-claim promotion; record_observation -> recall_observation or observation_coverage -> assemble_compaction_summary for continuity and compaction. ",
"Graph navigation tools available: {}. Progressively load graph navigation tools only after recall returns an entity or you already know an anchor: expand; use add_triple instead of remember_claim only when confidence/source control is required. ",
Expand Down
2 changes: 1 addition & 1 deletion crates/aver-server/src/scope_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl ResolvedScope {
}

/// Validate a scope candidate without going through sqlite. Mirrors the
/// `[A-Za-z0-9_/-]` charset enforced by migration 0084.
/// `[A-Za-z0-9_/-]` charset enforced by migration 0085.
fn validate(scope: &str, source: &'static str) -> anyhow::Result<()> {
if scope.trim().is_empty() {
anyhow::bail!("{source}: scope must not be blank");
Expand Down
6 changes: 6 additions & 0 deletions crates/aver-server/tests/mcp_instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ fn mcp_instructions_are_a_progressive_discovery_card() {
assert!(instructions.contains(
"unknown-predicate errors include fuzzy/semantic suggestions, accepted aliases, and a retry hint"
));
assert!(instructions.contains(
"Scope policy: pass `scope` only for an explicit per-call override; otherwise the request's resolved scope applies."
));
assert!(instructions.contains(
"For scoped reads, use `scope_walk=ancestors` for normal project memory, `exact` for isolation, `descendants` for subtree audits, and `any` only for cross-scope search."
));
assert!(instructions.contains(
"Progressively load graph navigation tools only after recall returns an entity or you already know an anchor: expand; use add_triple instead of remember_claim only when confidence/source control is required."
));
Expand Down
35 changes: 19 additions & 16 deletions doc/adr/0021-scope-as-first-class-memory-dimension.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Date: 2026-05-10

## Status

Proposed
Accepted

## Context

Expand Down Expand Up @@ -75,24 +75,26 @@ the existing two ACTIVE claims valid.

### Schema change

A new migration `migrations/00NN_scope_column.sql` adds:
Migration `migrations/0085_scope_column.sql` adds:

```sql
ALTER TABLE claims ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE events ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE observations ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';

CREATE INDEX claims_scope ON claims(scope);
CREATE INDEX events_scope ON events(scope);
CREATE INDEX observations_scope ON observations(scope);
ALTER TABLE claims ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE episodic_events ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE observations ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE candidate_claims ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';

CREATE INDEX claims_scope ON claims(scope);
CREATE INDEX episodic_events_scope ON episodic_events(scope);
CREATE INDEX observations_scope ON observations(scope);
CREATE INDEX candidate_claims_scope ON candidate_claims(scope);
```

Triggers analogous to `claims_agent_id_*_insert/update`
(`migrations/0060`–`0061`) enforce `scope` non-blank and a charset of
`[A-Za-z0-9_/-]` (note the `/` — paths are first-class).

The candidate-claim staging table inherits a `scope` column on the same
migration so candidates carry the writer's intended scope through promotion.
The candidate-claim staging table carries the writer's intended scope through
promotion.
Comment on lines +78 to +97

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Correct the index count in the consequences section.

This migration creates four scope indexes, including candidate_claims_scope, but the ADR still describes the cost as “three indexes.” Update that statement so the schema contract is internally consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doc/adr/0021-scope-as-first-class-memory-dimension.md` around lines 78 - 97,
Update the consequences section of the ADR to state that the migration adds four
scope indexes, including candidate_claims_scope, instead of three. Keep the
surrounding cost discussion unchanged.


### Path convention

Expand Down Expand Up @@ -129,11 +131,12 @@ this one.

### Write-path semantics

`add_triple`, `remember_claim`, `record_event`, `record_observation`,
`propose_candidate_claim`, and `add_vector_chunk` accept an optional `scope`.
When omitted: `'global'` (preserves today's behavior). `promote_candidate_claim`
copies the candidate's `scope` onto the durable claim; it is not a separate
parameter on promote.
`add_triple`, `remember_claim`, `record_event`, `record_observation`, and
`propose_candidate_claim` accept an optional `scope`. When omitted: `'global'`
(preserves today's behavior). `promote_candidate_claim` copies the candidate's
`scope` onto the durable claim; it is not a separate parameter on promote.
`add_vector_chunk` does not accept a separate scope because vector chunks attach
to a claim and inherit the claim's effective scope.

### Migration

Expand Down
Loading
Loading