Skip to main content

Memory Privacy & Access Control

SIs need rich lives while maintaining trust boundaries. A care SI for a child should never leak school data when socializing with other SIs. An SI managing a pet’s health shouldn’t share medical details at the “dog park.”
Core Principle: Private by default, shareable by consent.

The Four Privacy Fields

Every memory carries four privacy-related fields:
FieldTypePurposeDefault
source_entityOptional[string]Who told me this?null (self-observed)
subject_idsArray[string]Who/what is this about?[] (general)
access_grantsArray[string]Who is authorized to see this?[] (private to self)
consent_grantsArray[string]Who authorized sharing?[] (no consent given)

Privacy Scopes

Privacy scopes are derived from access_grants:

Self-Only

access_grants = []Only I can see this. Default for all new memories.

Private Entity

access_grants = ["human:sean"]Me + specific entity only.

Contextual

access_grants = ["ctx:bella_health"]Me + anyone in this context.

Public

access_grants = ["*"]Anyone I interact with.

Entity ID Format

Consistent namespaced identifiers for precise access control:
human:sean          → Specific human
human:kid_123       → Anonymous child
si:ash              → Specific SI
si:my-project           → Another SI
dog:bella           → Non-human entity

Context-Based Privacy

SIs operate in different contexts throughout their day. Context determines what’s visible and what privacy scope new memories inherit:
# Enter health care context
kernle context enter ctx:bella_health \
  --participants human:sean si:bella_agent \
  --role care_agent

# Memories created here auto-inherit:
# access_grants: ["human:sean", "si:bella_agent", "ctx:bella_health"]
Medical information is visible and new health observations are shared with the care team.

Access Control Rules

Memories with empty access_grants are visible only to the owning SI.No memory is shared unless explicitly granted.
Memories with subject_ids are automatically private to those subjects.Even with access_grants = ["*"], subject-tagged memories require explicit consent.“A memory about someone is private to that relationship by default.”
Memories created within a context inherit that context’s access scope.Can be narrowed (more private) but not widened without consent.
  • source_entity = null (self-observed) → strictest privacy
  • source_entity = "human:sean" → private to that relationship
  • source_entity = "si:other" → inherits chain’s most restrictive grant

Privacy-Preserving Generalization

SIs learn from private experiences and can form shareable insights — without revealing the private source:
Core Principle: SIs can generalize, but must err on the side of privacy.

The Generalization Process

# Generalize from private experience
kernle.generalize(
    source="episode:private_health_incident",     # stays private
    belief="Heart murmurs in small breeds need exercise monitoring",
    access_grants=["*"],                          # public shareable
    abstraction_note="Generalized from direct care experience. "
                     "No identifying details — applies to breed, not individual."
)

Safety Checks

Before sharing generalized knowledge:

Entity Name Check

Does the text contain names from source’s subject_ids?→ Block. Must revise to remove identifiers.

Specificity Check

Does it contain dates, locations, or unique details?→ Warn. Consider if details make source identifiable.

Reversibility Check

Could someone reverse-engineer the source?→ Advisory. SI exercises judgment.

Generalization Examples

  • Private: “Sean’s son struggled with fractions last Tuesday”
  • General: “Visual fraction models help kids who are concrete thinkers”
  • Why safe: No name, no date, no identifying details

CLI Interface

Privacy controls are built into all memory operations:
# Set privacy on creation
kernle raw "Bella has a heart murmur" \
    --subject dog:bella \
    --access human:sean si:bella_agent \
    --consent human:sean \
    --source vet:dr_smith

# Context management
kernle context enter ctx:bella_health \
    --role care_agent \
    --participants human:sean si:bella_agent

kernle context list                    # Show available contexts
kernle context show                    # Current context status

# Privacy operations
kernle privacy grant <memory_id> --to si:new_vet --consent human:sean
kernle privacy revoke <memory_id> --from si:old_agent
kernle privacy audit --subject dog:bella

Stack Sharing with Privacy

When an SI loads a shared stack, memories are filtered by their access grants:
# Loading shared stack with privacy filtering
shared_memories = load_stack("student_123", requesting_si="si:tutor_b")

# Only sees memories where:
# - "si:tutor_b" IN access_grants, OR
# - "*" IN access_grants, OR
# - matching context/group grants
Private memories exist in the stack but are logically invisible to unauthorized entities.

MCP Tools

Privacy is integrated throughout the MCP interface:
ToolPurposePrivacy Integration
memory_*Create memoriessource, subject_ids, access_grants params
context_enterDeclare contextSets default access grants for new memories
privacy_auditCheck accessShows who can see a memory/subject
consent_grantRecord consentAuthorizes sharing with specific entities
memory_generalizeSafe abstractionCreates public insights from private sources

Schema Design

Privacy fields are added to all memory tables:
-- Add to episodes, beliefs, notes, raw_entries, etc.
ALTER TABLE episodes ADD COLUMN subject_ids TEXT DEFAULT '[]';      -- JSON array
ALTER TABLE episodes ADD COLUMN access_grants TEXT DEFAULT '[]';    -- JSON array
ALTER TABLE episodes ADD COLUMN consent_grants TEXT DEFAULT '[]';   -- JSON array

-- Context tracking
CREATE TABLE privacy_contexts (
    id TEXT PRIMARY KEY,
    stack_id TEXT NOT NULL,
    context_id TEXT NOT NULL,
    participants TEXT DEFAULT '[]',
    default_access_grants TEXT DEFAULT '[]',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Consent audit trail
CREATE TABLE consent_records (
    id TEXT PRIMARY KEY,
    stack_id TEXT NOT NULL,
    grantor TEXT NOT NULL,              -- who gave consent
    grantee TEXT NOT NULL,              -- who received consent
    scope TEXT NOT NULL,                -- what was consented
    granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    revoked_at TIMESTAMP               -- NULL = still active
);

Security Considerations

Query-Time Filtering

Enforcement is logical (query-time), not cryptographic in Phase 8a.Sufficient for trusted environments.

Audit Trail

Every access grant/revoke is logged with timestamps and reasoning.

No Root Access

Even stack owners can’t see memories they’re not granted access to when acting as a different entity.

Memory Sovereignty

An SI’s own observations remain accessible to them. Privacy controls visibility to others.

Application Examples

# Enter academic context
kernle.context_enter("ctx:student_123_academic",
    participants=["human:parent_456", "si:school_agent"],
    role="role:tutor")

# Observe struggle (auto-private to context)
kernle.raw("Student struggling with algebra concepts",
    subject_ids=["human:student_123"],
    access_grants=["ctx:student_123_academic"])  # inherited

# Parent authorizes sharing with specialist
kernle.consent_grant(
    grantor="human:parent_456",
    grantee="si:reading_specialist",
    scope="ctx:student_123_academic")
Privacy preserving memory enables SIs to be both trusted caregivers and social beings — maintaining boundaries while growing through diverse experiences.