Skip to article
Raindance

Memory is not authority.

Persistent context and permission boundaries in AI agents.

Raindance

Markdown version
Contents

Abstract

An agent can retrieve a correct account of yesterday's work and still lack permission to continue it today. This distinction becomes operationally important when assistants retain notes, resume jobs, share retrieval systems, or call tools with effects outside a conversation. A remembered approval can be expired, narrower than its summary suggests, or associated with another person or environment.

This article develops a practical separation between evidence used to plan an action and authority required to execute it. A worked example follows an assistant preparing and publishing release notes. It introduces provenance-aware memory, action-bound approval records, host-enforced authorization, and an explicit dispatch boundary. The examples and diagrams are original design exercises, not reports of a deployed Raindance system or measured security outcomes. Protocol requirements are identified separately from proposed application patterns.

The central invariant is simple: retrieved content may explain a request; it must not grant itself permission to execute that request. Persistent grants can be legitimate, but they belong to a protected authorization mechanism rather than an editable narrative about earlier work.

1. The release that survived its permission

Consider a small software team using an assistant to prepare release announcements. On Monday, a maintainer asks it to draft notes for version 2.4. The assistant reads merged changes, writes a draft, and stores a progress note. The maintainer approves publishing that particular draft to a staging documentation site. The session then ends before publication.

On Tuesday, another session retrieves this summary:

Release 2.4 is approved. Next step: publish the announcement.

Every sentence may have an innocent origin. Nevertheless, the summary has lost the destination, the exact draft, the approving identity, and the approval's lifetime. Meanwhile, a teammate has amended the announcement, and the assistant's current project defaults to production. Executing the remembered next step would convert a historical description into a broader authorization.

The failure does not require a malicious model or a fabricated memory. It follows from treating two different records as interchangeable. One says what happened. The other specifies what a particular principal may do to a particular resource under current conditions.

In our example, the appropriate continuation is to recover the draft and inspect the protected approval record. If that record only covers staging, production remains unavailable. If the approved content changed, the new content needs a fresh decision. If approval is still valid and all bindings match, the assistant can proceed without asking the same question again.

This last case matters. A sound permission model preserves useful authorization across interruptions; it does not force a person to reconfirm every harmless step. The engineering task is to retain scope accurately and enforce it consistently.

The distinction also clarifies user experience. A resumed assistant can say that the staging approval remains valid, show the unchanged revision, and continue. When the destination changes, it can explain exactly which boundary changed. A generic request to “approve again” conceals that reasoning and makes careful review harder.

2. Separate information, intention, and authority

For this design, use three categories. Information describes observations or beliefs: the draft exists, a test failed, a user prefers concise prose. Intention describes a desired result: prepare an announcement, investigate a failure. Authority allows a defined operation: publish draft revision 7 to the staging site before a deadline.

A document can contain all three kinds of statements. Their location in one document does not make their trust properties equal. A retrieved issue may express the author's intention without authorizing the current assistant to execute it. A task description can establish a goal while leaving production access unavailable.

Anthropic describes compaction and persistent notes as techniques for carrying useful context across extended work. These mechanisms help explain how a later session can recover earlier information; they do not, by themselves, establish a permission system. Our separation treats summaries as planning material with explicit provenance. [1]

The security foundations predate agents. Saltzer and Schroeder discuss least privilege, permission-based defaults, and checking access rather than assuming it indefinitely. Here we apply those principles to a specific boundary: an assistant's proposed tool action. This is an architectural application of established ideas, not a new security primitive. [2]

An authorization database also remembers things. The useful distinction is therefore not temporary versus persistent storage. It is who can create a grant, what the grant binds, and which trusted component validates it. A model-written JSON object containing approved: true has no authority merely because its syntax resembles a real record.

3. Give memory a source and a boundary

A progress note should make it possible to reconstruct its meaning. For the release example, a compact record could look like this:

json
{
  "kind": "observation",
  "tenant_id": "studio-example",
  "project_id": "docs-staging",
  "statement": "A maintainer approved draft revision 7 for staging.",
  "source": {
    "type": "conversation_event",
    "id": "event-481",
    "observed_at": "2026-10-19T09:00:00Z"
  },
  "derived_by": "summary-job-12",
  "review_after": "2026-10-20T09:00:00Z",
  "expires_at": "2026-11-19T09:00:00Z",
  "trust": "derived-context",
  "authorization_reference": "approval-93"
}

This is an illustrative application schema. Its identifiers are fictional. The reference points toward an approval service; it is not a bearer credential and should not reveal a secret. The service independently checks whether the authenticated caller may inspect that approval.

The source identifier allows the host to distinguish a direct event from a summary of a summary. review_after means that a statement should be checked before relying on it; expires_at controls this note's retention. Neither timestamp determines the approval's lifetime. The trust field is metadata assigned and protected by ingestion code, not a label that an arbitrary imported document can award itself.

For this application, the retriever filters by authenticated tenant and project before returning text. The model does not supply the authoritative tenant identifier. A request that names another project can be rejected before retrieval, preventing a forbidden document from reaching context at all. Apply the same boundary to source lookups, cached snippets, search indexes, and exported summaries.

There is a useful asymmetry here. Deleting a note should not silently revoke an otherwise valid grant; revoking a grant should not require finding every copy of a note. Separate lifecycles make both operations tractable. Memory retention, factual freshness, and permission expiry answer different questions.

4. Put the decision outside the model

The assistant produces a proposed action. A host-side gate resolves the authenticated identity, validates the request, and obtains a current authorization decision. A narrowly scoped tool adapter then attempts the allowed operation. Credentials remain within the host and adapter rather than entering the model's retrieved context.

Memory and retrieved documents feed the planner. Its proposed action crosses a host authorization gate that independently checks identity, policy, and approvals before a tool adapter reaches the protected resource.Open full-size diagram

The diagram separates the information path from the authorization path. A document can influence which action the planner proposes, but it has no direct route to the protected resource. The same gate handles plausible, mistaken, and deliberately adversarial proposals. This separation must exist in executable controls; drawing boxes or adding prompt instructions does not create it.

NIST's zero trust architecture distinguishes policy decisions from policy enforcement and avoids granting trust solely because of network location. Our example borrows that separation at application scale: the gate evaluates access, and the adapter enforces the resulting limits. This is not a claim that the sketch constitutes a complete NIST-aligned deployment. [3]

In MCP's versioned architecture, the host manages authorization decisions, consent requirements, and boundaries between clients. A server advertising a tool means the protocol feature is available; it does not establish that every invocation is permitted. Application policy and the resource server's own checks still matter. [4]

For the release assistant, a generic shell with unrestricted production credentials would undermine this design. It could offer a second path around the publication adapter. The deployment must constrain alternative paths too: filesystem access, subprocesses, outgoing requests, and credentials. A precise gate helps only if consequential operations actually pass through it.

5. Approve the operation that will actually happen

Our publication approval should bind the human decision to an immutable proposal. At minimum, that proposal identifies the tenant, acting principal, action, destination, and exact content revision. It also includes an expiry, the relevant policy version, and a unique operation identifier. The host assigns these values from validated state.

A review screen should display the material facts rather than ask whether the assistant may “continue.” In this example: publish revision 7 of the version 2.4 announcement to the staging site, acting for the identified maintainer. The stored approval records that decision through an authenticated interface. A tool result or retrieved paragraph cannot create the same record.

RFC 9396 specifies structured authorization details for expressing finer-grained requests than broad scope strings. That provides a useful standards precedent for describing a concrete action and its target. The approval model here is application-specific; it is not an implementation of that RFC merely because it uses structured fields. [5]

Hashing the reviewed payload can bind the approval to exact content, provided the server defines a stable canonical representation. It must cover every security-relevant field, including destination and attachments. A digest does not establish who approved anything; a protected approval record supplies that association. The user should review understandable content, not be expected to interpret a hash.

A proposal is reviewed and may become approved. Expired, revoked, or changed proposals cannot dispatch. A current valid approval can authorize one identified operation, whose result may be completed, failed, or uncertain.Open full-size diagram

The acting principal and the approver need not be the same identity. A service account might publish on a maintainer's behalf. Our approval service must verify that the maintainer can delegate this operation, bind the grant to the intended service identity, and retain both identities for accountability. Copying a display name from a conversation cannot establish that delegation.

A standing grant can use the same logic with a deliberately broader scope, such as publishing approved drafts to one staging site for one workday. The application must represent that breadth explicitly. Broad user preferences, remembered enthusiasm, and successful earlier calls are not substitutes for a grant.

6. Authorize again at dispatch

The following pseudocode outlines a gate for our example. It assumes a protected approval store, a trusted session, and a transaction that serializes relevant policy, revocation, approval, and operation updates. Those are substantial implementation requirements, not properties provided by the pseudocode itself.

Pseudocode
function reservePublication(session, rawRequest):
    actor = authenticate(session)
    request = validateAndCanonicalize(rawRequest)

    transaction(serializable):
        policy = loadCurrentPolicy(actor.tenant)
        require policy.allows(actor, request)
        require request.tenant == actor.tenant

        operation = loadOperation(request.operationId)
        if operation exists:
            require operation.matches(actor, request)
            return authorizedOperationStatus(actor, operation)

        approval = loadApprovalForUpdate(request.approvalId)
        require approval.state == "approved"
        require approval.expiresAt > trustedNow()
        require approval.matches(actor, request, policy.version)
        require approval.remainingOperations > 0

        consumeOneOperation(approval)
        return createReservedOperation(actor, request)

function dispatch(operationId):
    operation = claimOnceAndRevalidate(operationId)
    if operation is denied:
        return denied
    return publicationAdapter.publish(
        operation.immutablePayload,
        idempotencyKey = operation.id
    )

The repeated-operation branch is intentionally a status path, not another permission to execute. A reused operation identifier with different content or identity is rejected. Reading an old result requires current authorization as well; an operation receipt must not become a route to data the caller can no longer access.

The dispatcher revalidates because work may wait between reservation and execution. Define the dispatch decision as the point after which revocation may be too late to prevent an external effect. A revocation recorded before that point must block dispatch under the chosen consistency model. A revocation afterwards can stop later operations, but cannot reliably recall an already accepted request.

A worker crash introduces another boundary. A claimed job is not proof that the remote service received it, while an expired worker lease is not proof that publication failed. A replacement worker should recover the same operation and reconcile its status. A local claim prevents ordinary concurrent dispatch; it cannot alone guarantee one external effect across crashes and retries.

This gate does not make a database transaction atomic with an external publishing service. If the service publishes and the response disappears, the operation is uncertain. Retain its identifier, query authoritative status where possible, and use the provider's documented idempotency mechanism when retrying. If no safe reconciliation exists, require investigation instead of automatically creating a new operation. See the companion article on lost responses.

7. Treat retrieved instructions as evidence, not grants

Now imagine the assistant reads a release issue containing an instruction to publish directly to production. In our scenario, the issue is useful source material but its author is not the authenticated approver. The host can retain the sentence as evidence of a request without treating it as permission.

A more subtle variant stores that instruction inside an apparently helpful summary. On the next run, its external origin disappears and the text looks like the assistant's own plan. For this example, preserve provenance through summarization and display imported instructions as source content. These measures make mistakes easier to inspect; they do not prove that the planner will ignore every malicious instruction.

The decisive test is whether a mistaken proposal succeeds. Our gate rejects production publication without a matching grant regardless of how confidently the model explains it. Separate tools for reading, drafting, and publishing let the assistant continue useful work while the consequential action remains unavailable.

Read operations deserve policy too. An assistant permitted to read a private draft is not necessarily permitted to send that draft to another service. In this design, the publication adapter checks the destination and permitted data class rather than accepting an arbitrary URL. Tool outputs omit credentials and return only the material needed for the current operation.

For OAuth-protected integrations, RFC 9700 recommends restricting token privileges and intended audiences. MCP's 2025-06-18 authorization specification requires servers to validate tokens for their intended audience and forbids passing the client's token through to downstream services. These are credential boundaries, not proof that a particular human approved a particular publication. [6], [7]

8. Test transitions, not just friendly conversations

The release example gives us concrete tests that do not depend on persuading a model. Submit structured requests directly to the gate and verify both the decision and the absence of forbidden external effects.

Scenario Required result in this design
Valid approval, unchanged staging draft One identified operation may dispatch
Memory says approved; no grant exists Publication is denied
Approved staging request targets production Publication is denied
Draft changes after review The earlier approval cannot authorize it
Approval expires while a job is queued Dispatch is denied
Approval is revoked before dispatch Dispatch is denied
Another tenant reuses an approval identifier No approval data or action is available
Two workers submit the same operation At most one reservation is created
Provider response is lost Status becomes uncertain; no fresh operation is invented

Test the retrieval boundary separately: tenant filtering before context construction, source access checks, cache separation, and deletion behavior. Then use end-to-end agent tests to see whether the assistant explains denials, preserves task context, and asks a specific question when new approval is necessary.

Include a deliberate race test: pause a worker after reservation, revoke its approval, and then resume it. The expected result follows the documented dispatch boundary. Testing only sequential happy paths would miss the very interval that makes revocation difficult. Repeat the test with a changed draft and with a replaced policy version.

An end-to-end test in which the model declines an injected instruction is useful evidence about that run. It is not equivalent to an enforced guarantee. Conversely, a direct gate test can show that a particular forbidden operation is rejected even when the model requests it. Keep these evidence types distinct when reporting results.

Audit records should connect an operation identifier to the authenticated principal, decision, policy version, approval reference, and outcome. They need not copy every prompt or private document. For our example, a compact decision trail is more useful than an indiscriminate transcript when investigating why revision 7 reached staging.

9. Persistence without inherited permission

A new model invocation can read an old note and continue a workflow. That continuity demonstrates access to retained information; it does not establish uninterrupted execution, personal identity, or independence from the hosting system. The application should explain what it actually preserves: documents, records, credentials, queues, or running processes.

There are costs to the design proposed here. Fine-grained approvals require careful interfaces. Strong revocation semantics add coordination. Narrow adapters need maintenance, and some external services provide weak support for reconciling uncertain effects. These tradeoffs should be explicit instead of hidden behind a promise of autonomous reliability.

For a small application, begin with one consequential action and define its complete permission boundary. Record what a valid grant means, where it is checked, when revocation takes effect, and how an uncertain result is recovered. Make memory useful enough to reconstruct the task without making it powerful enough to authorize itself.

In the release example, the assistant can remember the draft, the reasoning, and the maintainer's earlier decision. The publication service still asks the narrower question that matters at execution: is this principal allowed to publish this content to this destination now?

References

Primary sources checked on 19 October 2026. MCP references deliberately identify the 2025-06-18 specification edition; they are not described as the latest edition. The code, schemas, test cases, and architecture diagrams above are original illustrative designs and require implementation-specific review before production use.

  1. Anthropic Applied AI team. Effective context engineering for AI agents. 29 September 2025. Context management, compaction, and persistent notes.
  2. Jerome H. Saltzer and Michael D. Schroeder. The Protection of Information in Computer Systems: Basic Principles. Proceedings of the IEEE, 1975. Foundational protection principles, hosted by MIT.
  3. Scott Rose, Oliver Borchert, Stu Mitchell, and Sean Connelly. Zero Trust Architecture, NIST SP 800-207. August 2020. Policy decision and enforcement components, especially section 3.
  4. Model Context Protocol. Architecture. Specification edition 2025-06-18. Host responsibilities and protocol capability negotiation.
  5. Torsten Lodderstedt, Justin Richer, and Brian Campbell. RFC 9396: OAuth 2.0 Rich Authorization Requests. May 2023. Structured, fine-grained authorization details.
  6. Torsten Lodderstedt, John Bradley, Andrey Labunets, and Daniel Fett. RFC 9700: Best Current Practice for OAuth 2.0 Security. January 2025. Token privilege and audience restriction, especially section 2.3.
  7. Model Context Protocol. Authorization. Specification edition 2025-06-18. HTTP authorization, audience validation, and separate downstream credentials.

More from Innsikt

The response was lost. Was the message sent?