Mount
A mount is the file substrate an agent works in: the scoped storage that an agent's file references resolve against. It is not a tool runtime — it is shared infrastructure that every part of the system uses to read and write persistent data.
Mounts are the only source of model-visible bytes. Every file a model sees — uploaded by a user, produced by a capability, generated by the model itself — is written to the agent's mount first and referenced from there.
Where those bytes physically live, and under whose credential, is a deployment concern and is outside this specification. An agent declares which scopes it addresses; the deployment supplies the storage.
Mount scopes
An agent's mount field is a list of the scopes it addresses. Each entry contributes one virtual root:
| Entry | What it addresses | Virtual root |
|---|---|---|
workspace | the workspace's shared scope | workspace:// |
agent | this agent's own scope | agent:// |
task | the running task's scope | task:// |
An absent field means [task], which is what an ordinary agent needs. An explicit empty list means the agent has no mount: no root is injected and file references do not resolve, and it is the only way to say so. The two MUST stay distinguishable wherever the document is carried — folding them together would hand a mount to an author who refused one. An unrecognised entry MUST be rejected, and so MUST a repeated one.
The scopes are independent, and an agent MAY hold any combination of them:
mount: [workspace, agent] # reads the shared corpus and keeps its own files
mount: [task] # a conversation's files, and nothing beyond it
mount: [] # no files at all (omitting the field gives [task])
Scope decides sharing. Two agents that both enable workspace address the same files, so one can hand work to the other by name; task confines a conversation's files to that conversation; agent persists across every task an agent runs.
An agent addresses only its own mount scopes. agent is this agent's scope and never another's; task is the running task's scope and never another task's. There is no scope that addresses the parent of either.
File references
A file is referenced by a URI whose scheme is its root:
workspace://report.pdf
agent://scripts/office/unpack.py
task://output.png
This is the whole reference form. There is no bare-filename form, and there is no separate marker wrapping it: a reference names its scope or it names nothing.
agent:// and task:// are aliases, which is what makes the form usable — the model never writes its own name or the running task's id, and could not address a different agent or task if it did. The runtime resolves the alias, being the only thing that knows which agent and which task are running.
The remainder after the scheme is an ordinary relative path and MAY contain /. It is subject to the usual traversal rules: a remainder that escapes its own scope MUST be rejected.
A reference carrying no recognised scheme, or naming a root the agent has not enabled, MUST be refused rather than resolved — and the refusal MUST name the roots that ARE available. A model that has just used the wrong root can correct itself from that; one told only that a file does not exist will look for the file.
Because // opens a line comment in CEL, a reference in a CEL expression MUST be written as a quoted string literal. There is no unquoted spelling.
What a mount enables
When an agent's mount list is non-empty:
- CEL I/O functions —
mount.read(),mount.write()andmount.list()are available in CEL tool expressions. - File references — capability parameters declared
type: fileaccept reference URIs, so files pass between capabilities without their contents entering the conversation. - Multimedia output — when
model_capabilitiesincludesimage_generation,audio_generationorvideo_generation, the runtime writes generated media to the mount. These capabilities requiretaskinmount.
Additional mount.* values
mount.read(), mount.write() and mount.list() are the whole of the mount surface this specification defines.
An implementation MAY expose further values under the mount.* namespace. What those are — and whether there are any — is implementation-defined and MUST be documented by the implementation; a manifest that uses one is portable only to implementations that publish the same value.
Whatever an implementation exposes, it MUST NOT expose a value that reaches beyond the scopes the agent declared, or the grant would be wider than the agent making it.
CEL I/O functions
| Function | Description |
|---|---|
mount.read(ref) | Stat a file and return a lazy handle ({file, mime_type, size_bytes, hash}). Content is never fetched into the expression. A handle in the action's result becomes a context attachment, delivered to the model on the next request. |
mount.write(ref, content) | Write a file and return its handle. content is a string, or a handle for a server-side copy. The two references MAY name different roots, which is how a file moves between scopes. |
mount.list() | List the agent's files as sorted reference URIs, across every enabled root. |
These are available only in CEL tool expression fields — not in middleware, bindings, or guardrails. There are no built-in file capabilities: an agent's model can read, list or write only through a tool the author wrote against these functions and the agent explicitly granted.
Ownership of mount I/O
Two unrelated things are settled about a mount operation. Who decided it settles whether a capability is required. Where the file resides settles which scope holds it.
Who decided it is the user or the model:
- User-decided — a file the user uploads and sends as input. The user made that decision, so no capability is required.
- LLM-decided — the model reading, listing or writing at its own initiative, which is a privilege granted like any other capability.
This is the axis model_capabilities reasons about: a user's attachment and a capability's mount.read() are gated identically on the way into the model's context.
Where the file resides has only one answer for a user's attachment, a model's output, and a delegated sub-task's result: the task scope. They belong to the exchange they arrived in, and the other two scopes outlive it. An agent that does not enable task MUST therefore be refused rather than quietly redirected, and the user having decided does not exempt the attachment — what is missing is not a capability but somewhere for the file to be. That is why task is the default mount value.
Moving files is not opening them. An agent that declares no media-understanding capability can still list, copy, rename, download and upload files, and pass references between capabilities. Fetching a file into the mount attaches nothing to the model's context; only reading one does.
Examples
An agent reading shared files and keeping its own
kind: commonagents.info/v1beta2/agent
name: coder
mount: [workspace, agent] # workspace:// and agent:// resolve; task:// does not
capabilities:
summarise_doc: "*"
This agent's model addresses workspace://design.md and agent://skill.md by name — the shared corpus and its own accumulated files — and passes either to summarise_doc as a file reference. Having not declared task, it cannot be sent an attachment or generate media.
A memory tool using the CEL mount functions
kind: commonagents.info/v1beta2/tool
name: memory
description: Key-value memory for agents, persisted to the agent's mount.
actions:
- name: write
description: Save a key-value pair to persistent memory.
parameters:
type: object
properties:
key:
type: string
value:
type: string
execute:
cel:
expression: >
mount.write("agent://_memory/" + input.key, input.value)
- name: read
description: Read a value from persistent memory by key.
parameters:
type: object
properties:
key:
type: string
execute:
cel:
expression: >
mount.read("agent://_memory/" + input.key)
Memory under agent:// persists across every task the agent runs. The same tool written against task:// would give the agent a memory that lasts one conversation.