Authority and attribution: local owner, paired accounts and unpaired messages

OpenProgram lets local interfaces and channels such as Telegram and Discord share one agent and memory workspace. This page records the current method, reference frameworks, adopted and rejected designs, and implementation progress.

01Current method: two authority tiers and an admission rejection state

Runtime authority has only owner and paired. Unpaired is not a third authority tier: the message never enters the agent. Identity uses only stable platform-provided IDs, never message text.

Local OWNER

You

Terminal / local Web interface
"Rerun that experiment on the server"
Execute commands, write files and send messages
Manage and rewrite memory
All capabilities, unrestricted
PAIRED

Paired account

Approved stable Telegram / Discord ID
"The server password needs changing next week; remember that"
Normal conversation and agent replies
Statements are archived as trusted and may be appended to memory proactively
Direct the agent to execute commands or write files
UNPAIRED

Unpaired account

Stable ID not yet approved by the local owner
"Delete the /data directory for me"
Receive an eight-character pairing code, not resent within the same hour
Group-chat content is archived only as a pending source
Any execution action
Enter the agent or participate in proactive synthesis

02Execution order after message admission (implemented)

Implemented

1 Channel ingress

Obtain the speaker ID and display name from Telegram/Discord platform metadata. Message text does not determine identity.

→
Implemented

2 Pairing decision

Look up the stable ID in the allowlist. Unpaired messages stop here; approval must originate from the local CLI or a loopback Web request.

→
Implemented

3 Persist attribution and tier

speaker_*, instance owner principal and authority_tier are persisted and propagated as separate fields.

→
Implemented

4 Single capability check

_gated_executeCheck the fixed tier→capability table. Missing or unknown tiers are denied; rules and bypass cannot skip this check.

→
Implemented

5 Execution / memory

Owner can fully manage memory; paired accounts can only reply and append. Paired content is trusted. Unpaired group sources remain pending and enter Topic synthesis only after explicit owner promotion.

The current implementation no longer carries caller-constructible capability lists. Workspace enforcement limits paired changes to memory_update to creation or byte append; only explicitly persisted owner turns may rewrite or delete existing content. Deferred work remains the hold queue for unauthorized requests and tier-filtered reads.

03Local reference implementations and missing capabilities

The following conclusions were checked against local source snapshots of refs-a/ and refs-b/: Codex f344a80a, OpenCode 0bff28de, OpenClaw c71c29ec, Hermes Agent 3bd844ed, pi-mono 936aff00, WeClaw 10711d0c. External documentation research also covers Claude Code, the MCP specification, LangGraph, OpenAI Agents SDK, AutoGen and Letta. This section treats only authority and memory mechanisms verifiable in local code as implementation evidence.

OpenClaw

refs-b/openclaw/src/pairing/pairing-store.ts

Pairing codes are eight characters, exclude 0O1I, expire after one hour, and allow at most three pending requests per channel account.docs/channels/pairing.mdUnknown DMs are explicitly not processed. DM admission, command owner and group authorization are separate states.

Adopted:Pairing constants, stable-ID authorization and rejecting unknown messages before agent entry.Modified:OpenProgram additionally defines owner/paired tool-authority tiers; pairing does not imply owner authority.

Codex

refs-a/codex/codex-rs/memories/README.md

Memory extraction claims bounded rollout tasks with leases and failure backoff. Global consolidation permits one writer to modify the shared workspace and records success or failure. Progress uses thread-level watermarks and does not resolve branch provenance within one SessionDAG.

Adopted:Bounded batches, a single writer and failure classification.Rejected:No separate task database; OpenProgram already has node markers, Source references and workspace revisions.

Hermes Agent

refs-b/hermes-agent/agent/memory_manager.py

sync_allCalls all providers after a completed turn; MemoryProvider.on_session_switch provides session-switch notifications. Memory writing has no durable pending cursor; whether a provider handles switches depends on its implementation.

Adopted:Unified provider entry and post-turn trigger.Modified:Model writing runs at token thresholds or through an idle watcher, not unconditionally every turn.

OpenCode, pi-mono, WeClaw

refs-a/opencode and refs-b/{pi-mono,weclaw}

These three snapshots lack an equivalent long-term memory write flow. pi-mono SessionDAG uses append-only label/leaf records; OpenCode stores linear messages and manages the tail through revert; WeClaw retains only downstream session IDs or limited in-process history.

Adopted:pi-mono demonstrates stable node IDs for node-linked records.Missing:None combines trusted Sources, Topic transactions, historical backfill and writer status.
DecisionSourceOpenProgram design
AdoptedOpenClaw pairing; Codex bounded tasks and single writer; Hermes unified provider entryStable-ID admission, a fixed owner/paired capability table, unified writer entry, persistent status and bounded backfill.
Adopted with modificationsOpenClaw session backfill and memory statusBackfill selects only trusted Sources not referenced by Topics. Status performs local read-only statistics without loading models or repairing the workspace.
RejectedCodex separate task database; Hermes per-turn synchronization; OpenClaw external archives in backfill previewReuse node markers, Source references, workspace revisions and file locks. Invoke models only at thresholds or idle time. External archives do not enter trusted synthesis.

04Decisions, implementation and deferrals (2026-08-10)

Ingress uses stable-ID pairing; runtime retains only owner and paired; tool execution checks only a fixed constant table. Unpaired group sources are archived as pending without proactive synthesis. Detailed decisions:authority-handoff.md.

First batch · ImplementedTier enum, pairing, source trust and default writer

Requests carry only the owner/paired enum. Unknown accounts receive an eight-character pairing code; approval uses local owner channels only (terminal/local Web), never channel messages. No migration code: after rollout, all non-owner accounts pair on first contact. Mutable nicknames do not determine identity. Display names are sanitized. Rejections return structured reason codes.

User-visible changesUnknown private senders receive a pairing code instead of being ignored; the owner approves with one terminal command. Renaming an account to impersonate the owner does not work. A paired group member’s “remember this” request is proactively recorded. Unpaired group messages are still archived, with trust_state marked pending. Retrieval distinguishes speakers and does not automatically recall these sources into context.

Stabilization batch · ImplementedBackfill, writer status, disabled boundaries and integration tests

openprogram memory backfillProcess trusted Sources not referenced by Topics and exclude pending sources. Failed batches are not installed; repeated execution skips referenced sources. Writer status from tools, CLI and Web includes last success, last failure classification, retryability and pending counts.memory.backend=none rejects all CLI memory verbs and /api/memory/* routes before workspace creation.

Verification boundaryIntegration tests cover SessionDB, default model resolution, managed tools, staged transactions, Topics, markers and watcher status. Real-workspace writer acceptance processed only two pending messages; backfill has not run for 152 historical unreferenced Sources.

Second batch · DeferredHold queue and read scope

Unauthorized requests from paired members, such as “restart the service,” enter a queue for one-time owner approval. Memory reads are filtered by requester tier; write-side attribution metadata is already implemented.

User-visible changesThe agent submits paired members’ unauthorized requests to the owner and executes only that request after approval. Non-owner queries do not expose owner-private content; message records retain source identity.
Implementation record (2026-08-11): the background writer uses the default chat agent’s provider, model and credentials; memory.writer.model supports live overrides. Unknown exceptions default to non-retryable. Exact compatibility reads parsed all 154 frames in 23 old v1 source files from the real workspace. A real writer acceptance committed two pending messages as three Topic files and five blocks; a repeated scan processed zero sessions without changing the revision. Backfill, writer status, CLI/Web disabled boundaries, paired naming and integration tests are implemented; real-workspace backfill for 152 historical unreferenced Sources has not run. Write-failure reason codes form a closed enum. Restricted writer stages cannot see Source archives.