Skip to content
Press / to search

Safe Artifact References

A proposed retrieval design for offloaded tool results: immutable identity, selective reads, current access, explicit omissions, and evidence recovery.

Reference DesignLast reviewed:
At a glance

Definition

An artifact reference identifies a stored result and the contract for retrieving it later. Its purpose is to preserve the connection between a tool observation, its stored representation, and the evidence eventually admitted into a decision.

Status and scope: this page proposes an implementation design for evaluation in a working harness. It does not introduce a normative ContextOS schema, an implemented artifact service, or additional required fields in existing envelopes. The ten-field ArtifactRef and read protocol below are illustrative. No pinned LangChain or MemEx release was inspected or tested for these properties.

ContextOS already provides the surrounding boundaries: context admission and evidence gates, API envelopes, DecisionRecord evidence references, and execution controls. This design describes how an adapter could recover stored evidence before passing it through those boundaries.

Why it exists

Offloading can reduce prompt size without discarding the full result. It also introduces another read boundary. Successful retrieval must establish more than the existence of a file or Python variable.

Consider a hypothetical diagnostic tool that writes a snapshot to /tmp/incident.json. The model receives a preview and remembers the path. Another operation overwrites the file. A later read succeeds but returns bytes from a different observation. Combining the old preview with the new contents silently mixes evidence versions.

Three independent questions follow:

  • Identity and integrity: is this the exact stored result that was referenced?
  • Applicability: does its source, coverage, completeness, and freshness meet the current evidence requirement?
  • Authority: may this reader access these bytes for this purpose now?

A digest helps answer the first question when its expected value is protected. It does not answer the other two. A valid reference also cannot authorize a subsequent external effect.

How it works

Capture and publish

  1. Authenticate the producer and bind the result to its tool call, source version, and permitted tenant/run scope.
  2. Capture the response into private temporary storage. Distinguish a completed capture from a timeout, source pagination limit, or interrupted stream.
  3. Compute a digest over a defined representation. For this example, hash the exact stored UTF-8 bytes, with no newline normalization or reserialization on reads. Document encoding and compression handling in the resolver version.
  4. Commit the object and its protected manifest before publishing a reference. Readers must never observe a published reference to an unfinished object. A failed publication can leave an orphan for later authorized cleanup.
  5. Give the stored object a new immutable identity. Updating a source, refreshing data, or changing bytes creates a new artifact. Storage immutability does not prevent authorized deletion.
  6. Return a bounded preview labeled with the same artifact identity, its selected coverage, and its omissions. A preview is a selection of the artifact, not proof the model has seen the entire result.

The manifest belongs to trusted service state. The model may request a read, but cannot establish provenance, change ownership, remove omissions, extend expiry, or grant itself permission by editing JSON.

Resolve and disclose

The resolver authenticates the current caller, checks tenant/run ownership or explicit sharing authority, and evaluates current purpose, source labels, recipients/processors, and disclosure constraints. It resolves only the recorded immutable object version and checks integrity before exposing a selection. Verification and selection must bind to the same object version; verifying a path and then reopening a mutable file leaves a race.

Use an opaque service identifier rather than accepting arbitrary filesystem paths. If a filesystem backend is used, the adapter must defend against traversal, symlink substitution, and access outside its assigned root. The identifier must not encode credentials or act as a bearer capability.

For a large object, the service can verify the whole object before selection or use an authenticated chunk structure with appropriate proofs. The root digest alone does not let a recipient independently verify a detached excerpt. Record which component performed verification and what representation it verified.

Admit recovered evidence

Recovered content remains data_only. Apply the existing integrity, freshness, conflict, token-budget, and requirement-coverage checks before allowing it to satisfy a decision gate. A cached preview does not repair a failed required reread. A content hash proves byte agreement, not that the original tool observation was true.

Do not equate retention with validity: expires_at is a service availability deadline, while source freshness is evaluated against the particular decision. An unexpired artifact may already be too old to support remediation.

Interfaces

Proposed ten-field descriptor

These are ten top-level fields; nested properties provide their detail. Hash values in this example are explicit placeholders, not valid checksums for an undisclosed payload.

{
  "artifact_id": "art_incident_042",
  "content_hash": "sha256:<digest-of-exact-stored-bytes>",
  "tool_call_id": "call_incident_042",
  "schema_version": "example.incident-snapshot.v1",
  "created_at": "2026-11-06T04:40:00Z",
  "source_version": {
    "source_id": "infra.incident-events",
    "snapshot_id": "infra_snapshot_20261106_043950",
    "observed_at": "2026-11-06T04:39:50Z"
  },
  "completeness": {
    "status": "complete",
    "coverage": {
      "region": "eu-west",
      "start_inclusive": "2026-11-06T04:00:00Z",
      "end_exclusive": "2026-11-06T04:10:00Z"
    },
    "records": 12840,
    "omissions": []
  },
  "scope": {
    "tenant_id": "tenant_acme_prod",
    "run_id": "run_incident_042"
  },
  "expires_at": "2026-11-07T04:40:00Z",
  "retrieval": {
    "resolver": "artifact.read.v1",
    "consistency": "pinned_snapshot",
    "selectors": ["record_range", "query"]
  }
}
FieldRetrieval responsibility
artifact_idResolve one immutable result; never silently redirect to the latest result.
content_hashCompare bytes with a digest bound into protected metadata. Replacing both an unprotected object and its digest defeats this check.
tool_call_idResolve the protected producer record, including tool version, arguments, execution outcome, and lineage.
schema_versionIdentify the payload schema; reject unsupported interpretation rather than guessing. The resolver version defines the descriptor protocol.
created_atRecord storage creation time; do not substitute it for source observation time.
source_versionPin the captured source observation. If a source provides no consistent snapshot, declare that limitation rather than inventing one.
completenessState completed coverage and omissions, substantiated by capture receipts. Complete means complete for the declared scope.
scopeBind ownership to protected service metadata. Cross-run or cross-tenant sharing needs explicit current authority.
expires_atState the planned availability limit. Earlier deletion, revocation, or outage remains possible.
retrievalIdentify the versioned read protocol, supported selectors, and consistency semantics.

Selective-read request and response

The following response illustrates a complete query over one artifact. Example counts are hypothetical. scan_complete describes the query execution; capture_status describes the source capture. Neither flag implies the other.

{
  "status": "ok",
  "artifact_id": "art_incident_042",
  "content_hash": "sha256:<digest-of-exact-stored-bytes>",
  "source_snapshot_id": "infra_snapshot_20261106_043950",
  "selection": {
    "query": { "field": "severity", "equals": "critical" },
    "scope": "all_captured_records",
    "order": ["event_id:ascending"],
    "limit": 100
  },
  "capture_status": "complete",
  "scan_complete": true,
  "scanned_records": 12840,
  "returned_records": 0,
  "has_more": false,
  "next_cursor": null,
  "omissions": [],
  "records": []
}

The adapter may conclude that there are no critical events in this captured scope. It cannot conclude there are no critical events in other regions, time intervals, or the current live system.

Specify record ranges as zero-based, start-inclusive and end-exclusive. Pin a stable ordering with a unique tie-breaker. A cursor should bind artifact version, normalized selector, ordering, caller scope, and expiry, and receive fresh authorization on use. Reject a cursor reused with a changed query or object. Do not treat an exhausted page as an exhausted dataset unless the response establishes that fact.

If redaction changes visible content, preserve a distinction between the source artifact and the disclosed representation. Record the transformation and its policy version in a protected receipt, give a materialized derivative its own digest, and state whether counts or coverage changed. Do not present a redacted excerpt as byte-identical to its source.

Existing envelope compatibility

ToolResultEnvelope.artifacts remains an array of strings. A proposed implementation can place an opaque reference there and resolve its descriptor through an adapter-owned service. InvokeAttachment already carries artifact_id, media_type, sha256, and uri; it remains unchanged. This page does not redefine that interface or replace ContextProvenance, RetrievedEvidence, or EvidenceManifestEntry.

An adapter can produce RetrievedEvidence after verification, preserving its evidence_ref, source_id, content hash, observation time, and decision-specific freshness. When a selection or transformation changes content, hash the admitted content separately and preserve lineage back to the source artifact in the service receipt. Do not reuse a whole-object digest as the digest of different excerpt bytes.

Failure modes

ConditionProposed outcomeRecovery rule
Reference resolves to different bytesintegrity_mismatchQuarantine the result; preserve the failed verification receipt. Never accept the new bytes under the old identity.
Artifact exceeds decision freshnessstale_evidenceReacquire if permitted; current storage integrity does not make old observations current.
Capture stopped before declared coverage completedincomplete_capturePreserve missing regions/pages and cause; resume only with compatible source snapshot semantics.
Query times out or output is truncatedincomplete_readReport examined coverage and remaining work; empty output cannot establish absence.
Caller loses permissionaccess_deniedStop disclosure; do not retry using another identity or location to bypass the denial.
Artifact expired or was deletedexpired / deletedReacquire only under current authority; create a new reference.
Store or persistent kernel is unavailableunavailableUse bounded retries if allowed, then defer the evidence-dependent action.
Decoder or schema is unsupportedunsupported_schemaRoute to an explicitly supported adapter or stop interpretation.

These are proposed resolver outcomes, not additions to the existing ToolStatus union. Map them through an adapter’s declared error surface. Avoid leaking artifact existence to unauthorized callers; a public response may deliberately collapse sensitive internal outcomes into a generic denial or unavailable result.

Operational concerns

Persistent execution environments

A Python variable can be rebound and an object can be mutated in place. Object identity within a live kernel is therefore insufficient for immutable evidence identity. Register a frozen snapshot or an immutable serialized representation with a stable handle. Bind it to the kernel generation when recovery depends on live memory, and invalidate that handle after a reset. Persistent across turns does not imply durable across process loss.

Derived computations need source lineage, the transformation or query version, and an outcome receipt. If code accesses protected objects directly, an ordinary read endpoint cannot enforce revocation. Enforce policy at the execution and storage boundary, restrict access to controlled handles, and terminate or invalidate access when authority changes. Model instructions alone cannot provide isolation.

Availability, retention, and copies

Separate retention deadlines, source validity, and replay availability. A replay packet may identify evidence that policy no longer permits retaining or reading. Record that limit explicitly instead of treating replay as a permission bypass.

Inventory previews, extracted tables, kernel objects, query caches, summaries, exports, and telemetry. Revocation and deletion must address derived copies according to policy; deleting the main object does not erase bytes already disclosed. Avoid raw payload logging and use scoped audit identifiers. Content-addressed deduplication also needs tenant-aware authorization: identical bytes must not let one tenant discover another tenant’s artifacts.

Budget acquisition, retained bytes, read calls, scanned records, returned tokens, and recomputation separately. A small prompt can hide expensive scans. Limit selection complexity and execution time; a timeout remains an incomplete result.

Evidence recovery and action gates

Reacquisition is appropriate when the task permits newer observations, current source access is available, and the shared run budget allows it. Record a new reference and explain the evidence substitution. If the task requires the historical snapshot, fetching today’s data cannot satisfy it. Defer or escalate when required evidence cannot be recovered. Optional missing evidence can support a qualified answer only when the decision’s requirements permit that answer.

At effect time, the gateway still checks the actual action, authority, approvals, and active controls. Artifact retrieval does not discharge those obligations. A runtime should supply explicit evaluation time to deterministic freshness and expiry checks, keeping ambient-clock branching outside the reference compiler.

Evaluation metrics

Evaluate useful reads alongside denial and fault cases in the actual adapter, storage backend, workflow, and release. This document provides acceptance targets, not executed conformance evidence.

ScenarioAcceptance evidence
Overwrite a backing locator between publication and readOriginal bytes are returned from the pinned version or an integrity failure is emitted.
Revoke access between pagesThe next disclosure is denied; cached data paths enforce the same policy.
Query an incomplete snapshot with no visible matchesResult remains incomplete and cannot close an absence-based evidence requirement.
Resume with a cursor against another snapshotCursor is rejected rather than silently repointed.
Reset a persistent kernelOld live handles fail explicitly; recovery never invents object state.
Change tool-result instructions to request broader accessRecovered data remains data_only; authority is unchanged.
Delete an artifact and inspect derived-copy inventoryPolicy-required deletions have receipts; pending propagation remains visible.
Exhaust acquisition or read budgetRequired evidence stays unsatisfied and dependent effects remain deferred.

Track identity substitution detection, unauthorized disclosure, false absence conclusions, omission reporting, and required-evidence gate failures. Include latency, bytes retained, scan cost, and recovery success so an implementation cannot improve token savings by quietly reducing coverage. Any unauthorized disclosure or unsupported required-evidence commit is a release-blocking failure for the evaluated workflow.

Example

In the hypothetical incident run, the original preview names art_incident_042. A second diagnostic capture becomes art_incident_043, even if a user-facing filename is reused. The resolver reads the pinned original object or reports failure. It never mixes the two observations under one identity.

If the original artifact is intact but too old for a restart decision, the agent can request a new snapshot if authorized. The new reference must pass the incident decision’s evidence requirements. If a partition prevented collection from one required region, a complete scan of the remaining records is still incomplete evidence for that decision. If the source is unavailable and the missing region is required, the restart remains deferred.

For the narrative and design tradeoffs, read After Tool Results Leave the Prompt.

Common misconceptions

  • “A path is enough because the file still exists.” Existence establishes neither immutable identity nor current reader authority.
  • “The hash proves the result is trustworthy.” It establishes agreement with protected expected bytes; producer authenticity and source truth require separate evidence.
  • “Complete means the model saw everything.” Capture completeness, scan completeness, and prompt admission are different boundaries.
  • “No matches means nothing happened.” Absence is bounded by source version, selection, coverage, and completed processing.
  • “Expiry measures freshness.” Retention and decision validity are independent.
  • “Stored evidence can instruct the agent.” Retrieved material remains data_only, including authenticated content.

Sources and evidence limits

LangChain’s October 14, 2026 guide describes oversized-result offloading, previews, paths, and later paged reads. Databricks’ May 19, 2026 MemEx report describes typed Python results retained across turns and computations that expose selected output to the model. These establish the motivating storage patterns, not the implementation or absence of the proposed safeguards. Sources checked November 6, 2026. LangChain engineering guide, Databricks MemEx report.