Agent-Safe Reads (Read-Time Processing)
Keep raw data at rest. Let AI agents read only the safe projection — Maskura scrubs PII and encrypts on the way out, not on the way in.
The problem
Write-time processing is table stakes: your app PUTs through Maskura and PII is cleaned before storage. But agents often need to read existing datasets — buckets written by other systems, exports, or raw collections. Today the industry answer is a second cleaned copy, which drifts out of sync and doubles storage.
Maskura does the inverse: the object at rest stays raw. Every read runs the workspace's resolved read pipeline — redacting emails, cards, SSNs, and encrypting fields before the agent ever sees them. There is no client-elected mode: an agent cannot ask for raw bytes, and a read the pipeline cannot fully serve is denied rather than passed through.
How it works
- Your app writes raw objects (via Maskura's write path, your own S3 client, or a pre-existing bucket).
- An AI agent GETs the object through Maskura — nothing else is required.
- Maskura fetches the raw bytes, runs the PII/encryption pipeline, and returns the scrubbed result.
- The underlying object is unchanged — your app keeps full-fidelity data; the agent gets a safe projection.
Need raw reads for a bucket (bulk exports, media)? Assign that scope an explicit passthrough pipeline — a deliberate, audited policy decision in the same place every other pipeline is assigned, never a header the agent can send.
Example
# A read through Maskura — the assigned pipeline runs on the way out
curl https://api.maskura.dev/customers/customer-1.json \
-H "x-maskura-access-key: s4_..." \
-H "x-maskura-secret-key: s4s_..."
# → {"email":"[REDACTED_EMAIL]","card":"[REDACTED_CARD]","note":"hi"}Via MCP
The public maskura-mcp stdio server's maskura_get_object tool applies the resolved read pipeline to every read — the process parameter is retained for compatibility and does not change what is served:
// "Read customers/export.json with the configured read pipeline"
maskura_get_object(bucket="customers", key="export.json")Joinable reads (stable encryption)
Sometimes the agent doesn't just need safe data — it needs to join it (merge on a shared key, dedupe, or pivot). Redaction destroys that: every email becomes [REDACTED_EMAIL], so everything joins to everything. Envelope encryption (randomized AES-GCM) does too.
For joinable output, configure stable-encrypt before any redactor that would replace the join field, then set x-maskura-stable-fields on the read. The header supplies field names to the plugin; it does not reorder the pipeline or automatically bypass redaction. With that ordering, stable-encrypt applies deterministic AES-SIV, so the same value yields the same ciphertext without exposing plaintext.
# Agent joins two datasets on email, without seeing any email
curl https://api.maskura.dev/customers/c1.json \
-H "x-maskura-access-key: s4_..." \
-H "x-maskura-secret-key: s4s_..." \
-H "x-maskura-stable-fields: email"
# → {"email":"ZuXfsc392EIpZaxcMJSPd1NoYfhadX7aR6+umdNkHv4=","note":"first"}
curl https://api.maskura.dev/customers/c2.json \
... -H "x-maskura-stable-fields: email"
# → {"email":"ZuXfsc392EIpZaxcMJSPd1NoYfhadX7aR6+umdNkHv4=","note":"second"}
# the email ciphertext is identical -> joinableThe ciphertext is deterministic for the configured stable key, so reads using the same configuration agree. This is the joinable + safe pattern when the pipeline is ordered as described above.
Why this matters
- Single source of truth — no duplicate cleaned datasets to keep in sync.
- Zero raw exposure — the model/agent context never contains PII, and no request shape can select raw bytes.
- Same pipeline — redaction and encryption rules are identical to write-time.
- Joinable when configured — stable-encrypt preserves equality when it runs before redaction on the selected fields.
- Works with existing buckets — raw data written by any client is handled.
Limits and streaming
- Hosted PUT and GET requests are capped at 64 MiB. Text records and complete JSON documents are capped at 8 MiB.
- Joinable mode: order stable-encrypt before redaction, then add
x-maskura-stable-fields: email,card(comma-separated). The header does not skip or reconfigure other plugins. - Protected reads apply to your configured storage backend. Presigned backend URLs cannot provide the metadata preflight a protected read needs, so they are available only under explicit passthrough scopes.
Range/partNumberreads and formats the pipeline cannot decode are denied under protected scopes — never served raw.HEADis denied until transformed metadata is available.- If the pipeline errors, the read fails closed; Maskura does not fall back to returning raw bytes.
- When a plugin cannot be streamed safely, Maskura may stage the transformed read in a temporary encrypted local spool before returning any response bytes. Spool data shares a 256 MiB process quota, and stale artifacts are removed within a bounded cleanup window.
- Envelope encryption requires the reading key to have a public key attached (see Envelope Encryption); stable-encrypt derives its key from the API key secret.