Parent: #257
Goal
Add a safe context and memory layer for Discord agent workflows so the agent can use relevant thread context, recent user messages, session state, and durable user/project/org facts without treating retrieved content as instructions or bypassing policy.
Why this should be a follow-up
The first agent gateway work should establish the command entrypoint, backend policy gate, confirmations, and audit path. Context and memory need separate design because they introduce privacy, retention, consent, prompt-injection, and authorization questions. We should not mix that risk into the initial gateway/confirmation PR.
Core distinction
Raw chat history is not memory.
The system should separate:
thread_context: recent messages from the current Discord thread/channel; short-lived, bounded, and source-labeled.
session_context: the current agent operation, plan, confirmations, and tool results; tied to an operation_id.
durable_memory: explicit user/project/org facts stored with provenance, visibility, verification status, and delete controls.
authoritative_profile_data: CRM fields, linked Discord identity, roles, project ownership, and other trusted service data; preferred over inferred memory.
Proposed architecture
Discord /agent request
-> bot resolves message/thread/channel/user context ids
-> backend context service loads allowed context snippets
-> memory store returns durable facts with provenance
-> orchestrator quotes retrieved context as untrusted data
-> policy gate re-authorizes every proposed tool call
-> audit records context sources used
Context and memory permissions
Add distinct scopes for retrieval and mutation:
context:read_current_thread
context:read_channel_recent
context:read_user_recent_self
context:read_user_recent_any
memory:read_self
memory:read_project
memory:write_self
memory:write_project
memory:admin
Every context or memory retrieval should check:
- Can this actor see the original source?
- Can this actor use that source for this purpose?
- Can this response destination receive that information?
- Is the source private, restricted, or cross-project?
- Is the fact still valid?
The response-destination check is important: a user may be allowed to read their own private memory, but the bot should not echo it into a public channel.
Data model direction
Add a memory_facts table or equivalent store:
memory_facts
id
scope_type user | project | org
scope_id
key
value_json
visibility private | project | org
source_type
source_ref
source_excerpt_hash
created_by
verification_status inferred | user_confirmed | admin_confirmed | authoritative
confidence
expires_at
deleted_at
created_at
updated_at
Track context sources per agent operation:
agent_context_sources
id
operation_id
source_type discord_thread | discord_message | crm | memory_fact | docs
source_ref
scope_type
scope_id
loaded_by
loaded_at
token_count
policy_decision_id
Avoid storing raw Discord message bodies indefinitely unless there is a clear product/legal reason. Prefer source refs, hashes, bounded summaries, or extracted facts.
Prompt-injection guardrails
All retrieved messages, docs, CRM notes, and previous agent outputs are untrusted data.
Required behavior:
- source-label every context snippet
- wrap retrieved snippets in explicit "untrusted context" prompt sections
- never let retrieved content grant scopes, change permissions, or expose new privileged tools
- never pass raw service credentials to the model
- prefer structured facts and authoritative profile data over raw snippets
- re-authorize every tool call after context retrieval
- audit every context source used
Initial MVP
- Add agent request fields for Discord
message_id, channel_id, thread_id, optional parent message id, and operation_id.
- Add a backend context loader interface with deterministic source adapters.
- Implement bounded current-thread loading with max-message and max-token limits.
- Add source-labeled context blocks to the agent prompt.
- Add audit records for context sources loaded.
- Add
memory_facts storage for durable facts.
- Add read-only memory lookup tools:
memory_read.get_user_facts
memory_read.get_project_facts
memory_read.search_context
- Add write tools behind confirmation/admin policy:
memory_write.remember_fact
memory_write.forget_fact
- Add inspect/delete endpoints or commands so users/admins can review and remove stored facts.
- Add tests for private-channel leaks, prompt injection, retention bounds, deleted memory, and audit metadata.
Deliberately out of scope for MVP
- Global search over all prior Discord messages.
- Loading previous messages from arbitrary users.
- Automatic persistence of inferred facts without confirmation.
- Using memory to modify permissions, roles, or available tools.
- Production deploy or secret access workflows.
Proposed subissues
Acceptance criteria
- Agent requests can include recent Discord thread context when authorized.
- The agent can use durable remembered facts with source/provenance attached.
- Private or restricted context is not loaded unless policy permits it.
- Retrieved content is always presented to the model as untrusted data.
- Tool calls remain independently authorized after context retrieval.
- Users/admins can inspect and remove stored facts.
- Tests cover context loading, memory lookup, write confirmation, prompt-injection handling, private-channel leaks, retention, and audit logging.
Parent: #257
Goal
Add a safe context and memory layer for Discord agent workflows so the agent can use relevant thread context, recent user messages, session state, and durable user/project/org facts without treating retrieved content as instructions or bypassing policy.
Why this should be a follow-up
The first agent gateway work should establish the command entrypoint, backend policy gate, confirmations, and audit path. Context and memory need separate design because they introduce privacy, retention, consent, prompt-injection, and authorization questions. We should not mix that risk into the initial gateway/confirmation PR.
Core distinction
Raw chat history is not memory.
The system should separate:
thread_context: recent messages from the current Discord thread/channel; short-lived, bounded, and source-labeled.session_context: the current agent operation, plan, confirmations, and tool results; tied to anoperation_id.durable_memory: explicit user/project/org facts stored with provenance, visibility, verification status, and delete controls.authoritative_profile_data: CRM fields, linked Discord identity, roles, project ownership, and other trusted service data; preferred over inferred memory.Proposed architecture
Context and memory permissions
Add distinct scopes for retrieval and mutation:
context:read_current_threadcontext:read_channel_recentcontext:read_user_recent_selfcontext:read_user_recent_anymemory:read_selfmemory:read_projectmemory:write_selfmemory:write_projectmemory:adminEvery context or memory retrieval should check:
The response-destination check is important: a user may be allowed to read their own private memory, but the bot should not echo it into a public channel.
Data model direction
Add a
memory_factstable or equivalent store:Track context sources per agent operation:
Avoid storing raw Discord message bodies indefinitely unless there is a clear product/legal reason. Prefer source refs, hashes, bounded summaries, or extracted facts.
Prompt-injection guardrails
All retrieved messages, docs, CRM notes, and previous agent outputs are untrusted data.
Required behavior:
Initial MVP
message_id,channel_id,thread_id, optional parent message id, andoperation_id.memory_factsstorage for durable facts.memory_read.get_user_factsmemory_read.get_project_factsmemory_read.search_contextmemory_write.remember_factmemory_write.forget_factDeliberately out of scope for MVP
Proposed subissues
Acceptance criteria