Memory & Context Builder
See memory-context selection for the shared visual model.
Agentweaver maintains persistent memory for each project. Before an eligible agent turn, a structured context block is compiled from that memory and injected into the agent's system prompt. Stored text is serialized inside an explicitly untrusted JSON envelope; it is historical data, never prompt structure or executable instructions.
How context is built
MemoryContextCompiler.CompileAsync(projectId, agentName) gathers approved decisions, eligible memory, and the current session into one envelope-aware compilation result. The total token budget applies to the complete serialized context block, not just memory content. Its bounded composition metadata reports omitted memory/session counts and causes plus the stable record id, revision number, and immutable revision id of every selected knowledge record. It never emits record content in telemetry.
Decisions: active, approved architectural/scope records, ordered by creation time
Memory candidates: eligible active own core context + active learnings/patterns
Selection for runs: decisions mandatory; then task relevance, importance, recency, and record id; one bounded item/envelope budget
Session: most recent open session (ties by record id), included only as one complete recordIf all layers are empty the method returns null and no context block is injected.
Layer 1 — Decisions (team boundaries)
Decision rows where Type = architectural | scope, Status = active, and TrustState = approved, ordered by creation time.
These are serialized first in the untrusted context envelope. Their position and type make them the highest-priority project data, but their stored strings remain untrusted.
| Field | Values |
|---|---|
Type | architectural · scope · process · technical |
Status | active · superseded · archived |
TrustState | legacy · pending · approved |
Only active, approved architectural and scope decisions are injected (high-signal, team-wide). process and technical decisions stay in the database for governance and bookkeeping.
Layer 2 — Core context memories
AgentMemory rows where Type = core_context, scoped to this agentName, and TrustState != legacy, ordered by creation time.
Core memories are eligible regardless of importance, not guaranteed inclusion. They share the ranked memory item limit with eligible learnings/patterns. Defaults are 20 items and about 4,000 tokens at four characters per token. Positive call-site overrides precede MemoryContext:MaxItems / MaxTokens, then legacy Memory:ContextMaxItems / ContextMaxTokens. The complete serialized envelope must fit the token budget; selection stops before the next full record would exceed it. Active approved decisions are mandatory: compilation fails before a model call with a typed budget error if all decision records cannot fit. The session is included only if its entire serialized record fits the remaining envelope budget.
AKS deployments set the same defaults with MemoryContext__MaxItems=20 and MemoryContext__MaxTokens=4000 on both the API and worker pod templates. These are deployment-scoped operator settings. Agentweaver intentionally has no request header, query parameter, run option, project setting, or public API that overrides context budgets. The staging API harness can temporarily lower the deployment values through its explicit non-production pressure profile; it snapshots and restores the exact prior Kubernetes environment entries and requires the independently managed namespace label agentweaver.io/environment=staging. It must never be used as a production fixture. A failed restoration retains the profile Lease and snapshot to fence out another run until an operator recovers the deployments.
Layer 3 — High-importance learnings & patterns
High-importance learning and pattern rows are selected when either:
- they belong to the target agent and are not
legacy; or - they are
approvedand taggedcross-team.
The cross-team tag alone is not authority. Cross-agent selection requires explicit approval by a project owner or verified Coordinator run.
Before a fresh or delegated run, eligible learnings and patterns are filtered against the run task. Normalized tags are the primary relevance signal; memory content also requires multiple meaningful terms to overlap the task, and the exact irrelevant tag always excludes a record. This keeps unrelated retained facts out of the prompt. Relevant records are ranked deterministically before the existing importance, recency, and record-id tie breakers. Core context remains available to fresh runs, while delegated runs omit core context and session state to preserve their lean worktree-safe prompt.
Layer 4 — Current session
The most recent open SessionContext (no EndedAt) for the project. Provides the current focus area, active issues, and running summary.
Memory entities
Provenance and trust
AgentMemory and Decision expose:
| Field | Values / meaning |
|---|---|
SourceKind | human, run, or legacy |
SourceIdentity | Authenticated user or verified run:{id} identity |
SourceRunId | Source run when SourceKind = run |
TrustState | pending, approved, or legacy |
ApprovedBy, ApprovedAt | Audit identity and time for approved records |
New memory starts pending. It can inform its named agent under the normal layer rules, but cannot cross to another agent until approved. Direct active decisions and promoted inbox decisions are created as approved.
Rows that existed before provenance tracking migrate as SourceKind = legacy and TrustState = legacy. They remain queryable but are excluded from prompt compilation until a project owner or verified Coordinator explicitly approves them.
Exact-write convergence
Memory and active-decision writes are idempotent at the database boundary. Repeating the same logical write, including concurrent requests, resolves to one durable record and one stable id. The first request returns 201 Created; retries that resolve the existing record return 200 OK. Exports therefore contain one entry for that identity.
Identity includes the project, author/agent, content fields, normalized tags, and source provenance. Memory identity also includes its session, type, and importance. Decision identity includes its type, status, and supersession link. Approval metadata and timestamps do not create a new identity, so separate identical inbox entries and Scribe retries converge on the same promoted decision.
Superseding or archiving a decision changes its identity. A later write may therefore create a new active version with the same content without reviving or overwriting the historical record.
Immutable revisions and optimistic writes
Every memory and decision record has a stable numeric id plus a current revision and current_revision_id. Creation and every content, provenance, trust, approval, or lifecycle change append an immutable snapshot. Revision history stores a predecessor, actor or source run, timestamp, and reason. History responses redact recognized secrets and PII and expose fingerprints instead of raw source identities.
Updates, approvals, and restores require expected_revision. If another writer already advanced the record, the API returns 409 with error: stale_revision and the current revision. A restore copies the selected snapshot into a new active, pending revision; it never edits or deletes an older revision and never silently carries approval forward.
Memory lifecycle states are active, superseded, and archived. Superseded memory must identify a replacement in the same project, and replacement chains cannot cycle. Normal list/search and prompt compilation include only active memory. Pass status=all, or request a specific state, to inspect inactive records explicitly.
Project memory search accepts q, type, and comma-separated tags, applies all filters before paging, orders by update time and stable id, and caps pages at 100 items. The revision list, single-revision, compare, and restore routes use the same project authorization boundary.
In-run agents use the native get_memory and list_decisions tools with page and pageSize to retrieve later pages. get_memory also accepts text, agent, type, tag, and lifecycle filters. The read-only get_memory_history and get_decision_history tools expose paginated immutable revisions without exposing raw source or approver identities.
AgentMemory
Per-agent long-term memory. New entries are written through record_memory and retain the server-resolved human or run identity. record_memory commits directly to the memory database and returns without rebuilding the filesystem snapshot. This keeps the agent tool call independent of remote workspace-volume latency; export_memory refreshes .squad/ and .agentweaver/context/ explicitly at the end of the Scribe pass. An explicit export also publishes only the generated ledger files to the project's default branch, so they are visible through list_project_workspace and can be read with get_project_workspace_file. The response lists every repository-relative path written. The boundaries.md and patterns.md files are created even when they contain no entries, so a successful export always leaves a visible .agentweaver/context/ snapshot. Unrelated working-tree changes are not staged or committed.
| Field | Description |
|---|---|
Type | core_context — eligible for Layer 2 when non-legacy; learning — observation from a run; pattern — reusable practice; update — correction to prior knowledge |
Importance | high (injected in L3) · medium · low |
Tags | Comma-separated. cross-team makes approved memory eligible for another agent's Layer 3 |
Status | active by default; superseded requires an acyclic same-project replacement; archived is retained but inactive |
Revision | Monotonic expected-revision token used for updates, approvals, and restores |
Decision
Team-wide architectural or scope decisions. Injected in Layer 1 for all agents on the project.
Only a project owner or verified Coordinator run can create or update an active decision. Agents propose decisions through the inbox. Active architectural and scope decisions compile only when TrustState = approved.
DecisionInboxEntry
Drop-box for agent-proposed decisions. Agents write here via submit_inbox_entry. Inbox entries carry provenance but no independent trust state; their pending, merged, or rejected status records the review transition.
| Field | Description |
|---|---|
Type | architectural · scope · process · pattern · learning · update |
Status | pending → merged or rejected |
Scribe only auto-merges learning, pattern, and update entries that are attributed to the exact completed run and its agent. Ordinary-agent architectural and scope entries stay pending. Manual merge, promote, and reject require a project owner or verified Coordinator; Coordinator finalization may promote architectural and scope entries authored by that same verified Coordinator run.
Inbox promotion is atomic across API replicas. Concurrent merge/promote requests and deterministic Scribe reruns resolve the existing inbox-to-decision link, return the same decision id, and retain one completed Scribe audit outcome. PostgreSQL serialization, deadlock, and bounded lock-wait conflicts are retried before the operation fails.
SessionContext
Tracks the current work focus for a project. One open session at a time (EndedAt = null).
Updated by agents via update_session(summary). Scribe closes/summarises the session at run end via export_memory.
Scribe's role in memory
Standalone completion and Coordinator finalization own their Scribe work. Coordinator children stop at assemble-ready, bypassing their own review/merge/Scribe stages. Where the final Scribe pass runs, it:
- Select pending inbox entries for the completed run's agent, creation window, and verified source run id.
- Promote
learning/pattern/updateentries to approved ledger records; leave ordinary-agentarchitectural/scopeproposals pending. update_session(summary)— record what the agent accomplished in this runexport_memory()— write updated state to.squad/and.agentweaver/context/
For memories to accumulate, the running agent must call submit_inbox_entry when it discovers something worth remembering. The agent has to judge relevance.
Runtime prompt guidance names project-memory and coordination tools only after the final session tool list is built. A turn with no callable project-memory tools receives no memory section; a partial tool set lists only its callable names. Tool declarations remain the authority for required arguments and scopes.
Context injection point
RunOrchestrator.BuildContextAsync calls MemoryContextCompiler.CompileAsync and passes the result to the agent as systemPromptContext in SetupAsync. This runs once per turn, before the agent session is created. Selected data is serialized into one guarded JSON envelope:
## Untrusted Project Context Data
BEGIN_AGENTWEAVER_UNTRUSTED_CONTEXT_JSON
{"schema":"agentweaver.untrusted-context.v1","decisions":[...],"memory":[...],"session":{...}}
END_AGENTWEAVER_UNTRUSTED_CONTEXT_JSONIf there is no memory yet for a project, the block is omitted entirely and the agent runs with only the base prompt.
memory.context_composition records this structured-context selection on the run stream. Its payload includes included, omission counts and causes, and revisionReferences. Each reference contains only the knowledge kind, stable record id, revision number, and immutable revision id. Prompt text, source identities, and character/token measurements are deliberately excluded. Consumers must treat a changed revision reference as a new approval/cache input rather than reusing an approval for an older snapshot.
Coordinator child workers — lean relevant context
Coordinator child runs (a run with a ParentRunId) do not receive the full four-layer stack. Core context and session state duplicated the child's charter and carried artifact-write instructions that pointed at session-state / .copilot paths absent from a child worktree, which the sandbox rejected and stalled the child.
Instead, RunOrchestrator.BuildContextAsync injects the child's charter plus active, approved architectural/scope decisions and task-relevant high-importance learning or pattern memory eligible for that agent. Core context and session data stay omitted. The same deterministic item/envelope budgets and omission telemetry apply to fresh and child runs. Compilation non-budget failures are logged as warnings and the child proceeds with its charter alone. A mandatory-decision budget failure is terminalized before model invocation.
Runtime tools record_memory, submit_inbox_entry, update_session and export_memory correspond to public MCP memory_record, decision_inbox_submit, session_update and memory_export. MCP also exposes bounded memory_search, memory_history, memory_compare, memory_restore, decision_history, decision_compare, and decision_restore; mutation tools require the current expected revision.
Diagram details and constraints
| Element | Contract |
|---|---|
| title | Context is selected data, not instructions |
| takeaway | Approved decisions, jointly ranked memories and the open session converge into untrusted JSON. |
| group-title0 | SCOPED INPUTS |
| group-title1 | SELECTION AND SERIALIZATION |
| Active decisions | Active decisions |
| Active decisions | Project-wide boundaries |
| Active decisions | Approved architecture / scope |
| Active decisions | Oldest-created first |
| Active decisions | Child prompts: decisions plus task-relevant memory |
| Core + learnings | Core + learnings |
| Core + learnings | Agent-scoped candidates |
| Core + learnings | Core: exclude legacy trust |
| Core + learnings | High learning / pattern |
| Core + learnings | Approved cross-team allowed |
| Open session | Open session |
| Open session | Latest active session |
| Open session | Focus / issues / summary |
| Open session | Ended sessions excluded |
| Open session | Latest StartedAt wins |
| Joint rank + budget | Joint rank + budget |
| Joint rank + budget | One combined memory list |
| Joint rank + budget | Importance, then recency |
| Joint rank + budget | Stop at item / char limit |
| Joint rank + budget | Approximation: 4 chars/token |
| Context compiler | Context compiler |
| Context compiler | Assemble scoped sections |
| Context compiler | Decisions + selected memory |
| Context compiler | Add current session |
| Context compiler | Empty inputs → null |
| Untrusted JSON | Untrusted JSON |
| Untrusted JSON | Historical data, not authority |
| Untrusted JSON | Explicit boundary markers |
| Untrusted JSON | Ignore embedded instructions |
| Untrusted JSON | untrusted-context.v1 |
| relation-0 | 1 combine / sort |
| relation-1 | 2 approved |
| relation-2 | 3 latest open |
| relation-3 | 4 selected |
| relation-4 | 5 serialize |
| assurance | Defaults: 20 memory items / ≈4,000 tokens. The complete serialized envelope must fit; active approved decisions are mandatory and fail compilation when they exceed it. |
| assurance-0-label | Joint memory ordering |
| assurance-0-fact | Importance first; recency breaks ties. |
| assurance-0-source | MemoryContextCompiler.cs |
| assurance-1-label | Bounded selection |
| assurance-1-fact | Item / character limits cover the complete envelope. |
| assurance-2-label | Injection resistance |
| assurance-2-fact | Context is wrapped as untrusted JSON. |
| assurance-2-source | MemoryContextCompilerSecurityTests.cs |
| n0 | Approved architecture / scope; Oldest-created first |
| n1 | Core: exclude legacy trust; High learning / pattern |
| n2 | Focus / issues / summary; Ended sessions excluded |
| n3 | Importance, then recency; Stop at item / char limit |
| n4 | Decisions + selected memory; Add current session |
| n5 | Explicit boundary markers; Ignore embedded instructions |
| groups | SCOPED INPUTS; SELECTION AND SERIALIZATION |
