zotfile agents
A zotfile packages an agent's behavior into one portable .zot file. It can contain the agent's instructions, reusable skills, static assets, and metadata describing the runtime, model, operating-system, binary, and tool permissions it needs.
The current implementation supports creating, inspecting, verifying, and running local directories and .zot archives. It can also run an agent directory directly from a public GitHub repository without keeping a clone. Short names resolve local-first and then fall back to zot's official GitHub agent collection. Indexed registry distribution, installation, signatures, bundled executable extensions, network permissions, and environment permissions are not implemented yet.
Quick start
Create a directory for the agent:
reviewer/
├── manifest.json
├── AGENT.md
└── skills/
└── code-review/SKILL.md
Add a minimal manifest.json:
{
"zotfile": 1,
"name": "code-reviewer",
"version": "0.1.0",
"description": "Reviews a repository and reports actionable findings.",
"runtime": {
"min_zot": "0.2.76"
},
"model": {
"requires": ["tools"],
"min_context": 64000
},
"permissions": {
"fs": {
"read": ["${workspace}"],
"write": []
},
"bash": {
"mode": "none"
}
},
"requirements": {
"os": ["darwin", "linux", "windows"]
},
"entry": {
"greeting": "What should I review?",
"default_prompt": null
}
}
Add the agent's standing instructions to AGENT.md:
# Code reviewer
Review the current repository without modifying it.
Prioritize correctness, security, regressions, and missing tests. Report findings
in severity order with file and line references. Do not praise the code or
summarize files that have no findings.
Test the directory directly during development:
zot inspect ./reviewer
zot run ./reviewer
zot run ./reviewer "Review the authentication package"
Package it when ready:
zot pack ./reviewer
# wrote code-reviewer.zot
# digest sha256:...
zot verify ./code-reviewer.zot
zot run ./code-reviewer.zot
The first run displays the declared permissions and asks for consent before the agent starts.
Directory layout
my-agent/
├── manifest.json # identity, requirements, and permissions, required
├── AGENT.md # persona and standing instructions, required
├── skills/ # SKILL.md directories, optional
│ └── my-skill/SKILL.md
├── assets/ # static files, optional
└── README.md # human-facing documentation, optional
Only manifest.json and a regular AGENT.md file are required. Other ordinary files and directories are included in the archive, but the runtime gives no special behavior to assets/ or README.md yet. Files in assets/ are not automatically added to the model context or granted filesystem access.
Do not include executable extensions in extensions/. The local runtime rejects any bundled extension directory containing extension.json because extension subprocesses cannot yet be confined to the manifest permissions. This is a deliberate fail-closed restriction.
Symlinks are not supported and cause zot pack to fail.
AGENT.md
By default, AGENT.md is appended to zot's system prompt. It should describe the agent's role, workflow, constraints, output format, and when to load bundled skills.
Keep capability and security declarations out of this file. Permissions come only from manifest.json and are enforced independently of agent-authored prose.
Set replace_system_prompt to true in the manifest to use AGENT.md as the replacement system prompt:
{
"replace_system_prompt": true
}
Replacement is intended for fully specialized agents. The default layering behavior is usually preferable because it retains zot's normal identity and tool-use guidance.
Bundled skills
Place skills under skills/<name>/SKILL.md using the normal zot skill format:
skills/
└── investigate-failure/
└── SKILL.md
---
name: investigate-failure
description: Diagnose a failing command from its output and relevant source files.
---
# Investigate failure
1. Reproduce the failure if permissions allow it.
2. Identify the first meaningful error rather than downstream noise.
3. Read the implementation and nearest tests.
4. Propose the smallest correction and validation plan.
Bundled skills are added to normal skill discovery while the zotfile is running. The model sees their name and description in the skill manifest and can load the full body through the skill tool. See skills.md for the complete skill format.
Manifest reference
The current manifest shape is:
{
"zotfile": 1,
"name": "code-reviewer",
"version": "0.1.0",
"description": "Reviews a repository and reports actionable findings.",
"license": "MIT",
"runtime": {
"min_zot": "0.2.76"
},
"model": {
"requires": ["tools", "reasoning"],
"min_context": 64000,
"preferred": ["claude-opus-4-5", "gpt-5.5"],
"min_tier": ""
},
"permissions": {
"fs": {
"read": ["${workspace}", "${agent_data}"],
"write": ["${agent_data}"]
},
"bash": {
"mode": "allowlist",
"allow": ["git", "go"]
},
"net": {
"allow": []
},
"env": {
"read": []
}
},
"requirements": {
"bin": ["git", "go"],
"os": ["darwin", "linux"]
},
"entry": {
"greeting": "What should I review?",
"default_prompt": null
},
"replace_system_prompt": false
}
Top-level fields
| Field |
Required |
Current behavior |
zotfile |
yes |
Format version. Must be 1. |
name |
yes |
Local agent identity and session/data namespace. See naming rules below. |
version |
no |
Displayed in consent and inspection output. Semver is recommended but not currently validated. |
description |
no |
Displayed by zot inspect. |
license |
no |
Package metadata. Not otherwise interpreted by the local runtime. |
runtime.min_zot |
no |
Minimum zot version. Older binaries refuse to run the agent. Unversioned development builds cannot satisfy a non-empty minimum. |
model |
no |
Model capabilities, minimum context, and preferences. |
permissions |
no |
Filesystem and bash permission ceiling. Omitted scopes deny access. |
requirements |
no |
Required operating systems and executables. |
entry |
no |
Initial presentation and prompt metadata. |
replace_system_prompt |
no |
Replaces rather than appends to the normal system prompt when true. Defaults to false. |
Name rules
The local runtime currently accepts a flat lowercase name containing only:
a to z
0 to 9
., -, and _
Examples:
code-reviewer
repo_onboarder
acme.audit
Names containing /, uppercase letters, spaces, or path-like values such as .. are rejected. Registry-style namespace/agent names are reserved for the future distribution runtime and are not accepted locally yet.
Model requirements
model.requires currently recognizes:
| Capability |
Behavior |
tools |
Accepted. Every model in the current catalog is treated as tool-capable. |
reasoning |
Requires a catalog model marked as supporting reasoning. |
vision |
Recognized, but currently fails closed because vision support is not represented in the model catalog. No model qualifies. |
Unknown capabilities are rejected. Use tools, not the draft spelling tool_calling.
model.min_context requires a catalog model with at least that many context tokens.
model.preferred is an ordered list of model IDs. It is a preference, not a provider requirement. Selection proceeds as follows:
- An explicitly selected model, if present, must satisfy the requirements.
- The user's configured default is retained if it satisfies them.
- The first compatible model in
preferred is selected.
- Otherwise, zot chooses a compatible active catalog model.
- If none qualifies, execution stops with an error.
model.min_tier is present in the format shape but is not supported by the local runtime. Leave it empty or omit it. A non-empty value is rejected.
Runtime and host requirements
Use requirements.os to restrict the agent to Go operating-system names:
{
"requirements": {
"os": ["darwin", "linux", "windows"]
}
}
Use requirements.bin for commands that must already be on PATH:
{
"requirements": {
"bin": ["git", "python3"]
}
}
Zot checks these requirements before requesting consent. These zotfiles do not have install or postinstall hooks, so authors must document how users can obtain missing programs.
Entry fields
entry.default_prompt is used when the user runs the agent without a prompt. It may be a string or null:
{
"entry": {
"default_prompt": "Review the current repository"
}
}
A prompt supplied on the command line takes precedence.
entry.greeting is part of the manifest, but the current local runtime does not render it yet.
Filesystem permissions
Filesystem permissions are enforced by the built-in read, write, and edit tools. Empty or omitted scopes deny the operation.
Two variables are available in filesystem scopes:
| Variable |
Resolves to |
${workspace} |
The current working directory used for the run. |
${agent_data} |
The agent's persistent private data directory under $ZOT_HOME/agents/<name>/data/. |
Relative paths are resolved beneath ${workspace}. For example:
{
"permissions": {
"fs": {
"read": ["src", "go.mod"],
"write": ["${agent_data}"]
}
}
}
This allows reads under <workspace>/src and at <workspace>/go.mod, plus writes under the private agent data directory. It does not grant general workspace writes.
Common permission profiles follow.
Read-only repository agent:
{
"permissions": {
"fs": {
"read": ["${workspace}"],
"write": []
},
"bash": { "mode": "none" }
}
}
Repository editor with private persistent state:
{
"permissions": {
"fs": {
"read": ["${workspace}", "${agent_data}"],
"write": ["${workspace}", "${agent_data}"]
},
"bash": { "mode": "none" }
}
}
Data-only agent:
{
"permissions": {
"fs": {
"read": ["${agent_data}"],
"write": ["${agent_data}"]
},
"bash": { "mode": "none" }
}
}
Filesystem checks canonicalize existing paths, or the nearest existing parent for a new path, so symlinks cannot be used to escape a declared scope.
If the working directory changes during a run, ${workspace} permissions are expanded again for the new directory.
Bash permissions
permissions.bash.mode supports three values.
none
{
"bash": { "mode": "none" }
}
All bash tool calls are denied. This is also the default when mode is omitted.
ask
{
"bash": { "mode": "ask" }
}
Bash is available after the user approves the agent at launch. Consent for an agent using ask is requested on every launch and is not cached.
In the current local runtime, ask is launch-time capability consent. It does not open a separate confirmation dialog for every individual bash invocation.
allowlist
{
"bash": {
"mode": "allowlist",
"allow": ["git", "go", "grep"]
}
}
Every command in a shell expression must be listed. Zot checks commands separated by ;, &&, ||, and pipes. Paths are reduced to their base command name, so /usr/bin/git is checked as git. A leading environment assignment is skipped when identifying the command.
The allowlist rejects shell substitution, newlines, redirection, backticks, $(), <, and >. This intentionally supports simple command pipelines rather than arbitrary shell programs.
An allowlist mode with an empty allow array is invalid.
Only declare commands the agent genuinely needs. requirements.bin checks that a command exists, while permissions.bash.allow controls whether the agent may invoke it. Agents that execute a required command normally need it in both places.
Network and environment permissions
The manifest shape includes permissions.net.allow and permissions.env.read, but the local runtime does not enforce them yet. To avoid presenting unenforced declarations as security controls, it rejects manifests containing any network host or environment variable.
Use empty arrays or omit these sections:
{
"permissions": {
"net": { "allow": [] },
"env": { "read": [] }
}
}
Bundled executable extensions are rejected for the same reason. Network filtering, scrubbed extension environments, and extension confinement belong to a later runtime milestone.
Consent and persistent data
Before the first run, zot prints the agent identity and expanded filesystem and bash permissions, then asks:
Agent code-reviewer@0.1.0 wants to run.
fs read: /path/to/workspace
fs write: none
bash: none
Allow? [y/N]
For modes other than bash: ask, approval is cached for the exact artifact digest under:
$ZOT_HOME/agents/<name>/consents/<digest>.json
Any change to the packaged artifact produces a different digest and requires consent again. bash: ask always requires fresh launch consent.
Non-interactive runs refuse to bypass consent by default. For controlled automation, set:
ZOT_AGENT_CONSENT=1 zot run ./code-reviewer.zot --print "Review this repository"
This environment variable skips the consent prompt. Only use it after independently inspecting and trusting the exact artifact being run.
Persistent agent data lives under:
$ZOT_HOME/agents/<name>/data/
The directory is created for every run, but the agent can access it only when ${agent_data} appears in the relevant filesystem permission scope.
Agent-scoped sessions
Sessions created by a zotfile are isolated from ordinary zot sessions and from other agents:
$ZOT_HOME/sessions/agents/<name>/
Normal session flags still apply, including --continue, --resume, --session, and --no-session, but their default storage root is scoped to the active agent.
Commands
zot run
Run an unpackaged directory during development:
zot run ./my-agent
zot run ./my-agent "Do the task"
Run a packed artifact:
zot run ./my-agent.zot
zot run ./my-agent.zot --print "Do the task"
zot run ./my-agent.zot --json "Do the task"
Arguments after the reference use zot's normal CLI parser, so model, provider, reasoning, cwd, session, tool, and output-mode flags remain available. The manifest still imposes its permission and compatibility ceiling.
Local filesystem directories, local archive paths, short names, and public GitHub agent-directory URLs are accepted. A short name uses local-first resolution:
zot run zot-maintenance
Zot checks ./zot-maintenance and ./zot-maintenance.zot before falling back to https://github.com/patriceckhart/agents/zot-maintenance. This makes local development override the remote collection without an install or cache step.
A two-part name selects a GitHub repository under the patriceckhart organization:
zot run agents/zot-maintenance
zot run agents\zot-maintenance # also accepted on Windows
The first part is the repository and the second part is the agent directory. Both parts must use lowercase letters, digits, dots, hyphens, or underscores. Prefix a reference with ./, use an absolute path, retain the .zot suffix, or provide a complete GitHub URL when remote fallback is not wanted.
For GitHub, zot downloads the repository archive into a temporary directory, selects the requested agent subdirectory, validates it, runs it, and removes the downloaded files when the command exits:
zot run https://github.com/patriceckhart/agents/zot-maintenance --cwd /path/to/zot
Both the short subdirectory form above and a standard GitHub tree URL are supported:
zot run https://github.com/patriceckhart/agents/tree/main/zot-maintenance
The short form reads the repository's default branch through GitHub's HEAD archive. A tree URL uses the branch or tag in the URL. Private repositories and GitHub references containing / are not currently supported. The downloaded source is temporary, but normal agent data, consent receipts, and session transcripts remain under $ZOT_HOME.
Short-name fallback is a fixed GitHub mapping, not an indexed or signed registry. Installed names, arbitrary URLs, OCI references, and third-party registry configuration are not resolved yet.
zot pack
zot pack [directory] [output]
Examples:
zot pack
zot pack ./my-agent
zot pack ./my-agent ./dist/reviewer.zot
The default directory is the current directory. When output is omitted, zot uses <manifest-name>.zot. If the output has no .zot suffix, zot adds one.
Packing validates the manifest and directory, then creates a zstd-compressed tar archive. Entries are sorted and tar metadata is normalized with fixed timestamps and numeric ownership. The output archive itself is excluded when it is located inside the source directory. Zot prints the SHA-256 digest of the resulting compressed artifact.
zot inspect
zot inspect ./my-agent
zot inspect ./my-agent.zot
zot inspect https://github.com/patriceckhart/agents/zot-maintenance
Inspection validates and prints the agent's name, version, description, digest, declared permissions, and complete file list. It does not execute the agent.
For a directory, the digest is computed from its canonical uncompressed tar representation. For a .zot archive, the digest is computed from the archive bytes. Therefore a source-directory digest and its packed-archive digest are not expected to match.
zot verify
zot verify ./my-agent.zot
The local verify command validates that the archive can be safely loaded, validates the manifest and required layout, and prints its SHA-256 digest.
Despite the command name, it does not verify a publisher signature in the current runtime. Signature and namespace verification are planned for registry distribution.
Packaging and extraction limits
The archive loader applies these limits:
| Limit |
Value |
Compressed .zot file |
100 MiB |
| One extracted entry |
64 MiB |
| Total extracted content |
256 MiB |
Archive extraction rejects absolute paths and parent traversal. Unsupported tar entry types are ignored. New packages use zstd; gzip-compressed tar archives are accepted only as a compatibility fallback for earlier experiments.
Authoring guidance
- Start with the narrowest permissions possible. A reviewer usually needs repository reads, not writes or bash.
- Keep
AGENT.md focused on stable behavior. Put task-specific procedures in skills so the model loads them only when relevant.
- Declare every external command in both
requirements.bin and the bash allowlist when the agent must execute it.
- Test from a directory first with
zot inspect and zot run.
- Test denied behavior as well as allowed behavior. Ask the agent to attempt an out-of-scope read, write, and command.
- Pack the same source twice and compare behavior and output digests before distributing it.
- Inspect and verify the final archive, not only its source directory.
- Do not claim that network, environment, signatures, extensions, installation, or registry delivery are secured or supported by the local runtime.
Current scope
Implemented now:
- local directories and
.zot archives
- local-first short-name resolution to the official GitHub agent collection
- temporary execution of agent directories from public GitHub repositories
zot pack, zot inspect, zot verify, and zot run
- canonical tar creation with zstd compression
- archive digest reporting and safe extraction limits
AGENT.md append or replacement behavior
- bundled skills
- runtime, OS, and binary requirements
- model context and reasoning requirements
- filesystem scope enforcement
- bash
none, ask, and allowlist modes
- digest-scoped consent receipts
- private agent data directories
- agent-scoped sessions
Not implemented yet:
zot install, zot agents, zot use, zot update, or zot publish
- installed-name, arbitrary URL, OCI, configurable registry, or zot.sh index resolution
- network allowlist enforcement
- environment-variable filtering
- safely confined bundled executable extensions
- automatic artifact theme loading
- agent dependency composition
- per-agent Telegram, bot, or RPC selection
--no-sandbox, --trust-bash, or registry trust override flags
Treat the unsupported fields and commands in the broader zotfile proposal as forward-looking design, not as current runtime behavior.
source
1# zotfile agents
2
3A zotfile packages an agent's behavior into one portable `.zot` file. It can contain the agent's instructions, reusable skills, static assets, and metadata describing the runtime, model, operating-system, binary, and tool permissions it needs.
4
5The current implementation supports creating, inspecting, verifying, and running local directories and `.zot` archives. It can also run an agent directory directly from a public GitHub repository without keeping a clone. Short names resolve local-first and then fall back to zot's official GitHub agent collection. Indexed registry distribution, installation, signatures, bundled executable extensions, network permissions, and environment permissions are not implemented yet.
6
7## Quick start
8
9Create a directory for the agent:
10
11```text
12reviewer/
13├── manifest.json
14├── AGENT.md
15└── skills/
16 └── code-review/SKILL.md
17```
18
19Add a minimal `manifest.json`:
20
21```json
22{
23 "zotfile": 1,
24 "name": "code-reviewer",
25 "version": "0.1.0",
26 "description": "Reviews a repository and reports actionable findings.",
27 "runtime": {
28 "min_zot": "0.2.76"
29 },
30 "model": {
31 "requires": ["tools"],
32 "min_context": 64000
33 },
34 "permissions": {
35 "fs": {
36 "read": ["${workspace}"],
37 "write": []
38 },
39 "bash": {
40 "mode": "none"
41 }
42 },
43 "requirements": {
44 "os": ["darwin", "linux", "windows"]
45 },
46 "entry": {
47 "greeting": "What should I review?",
48 "default_prompt": null
49 }
50}
51```
52
53Add the agent's standing instructions to `AGENT.md`:
54
55```markdown
56# Code reviewer
57
58Review the current repository without modifying it.
59
60Prioritize correctness, security, regressions, and missing tests. Report findings
61in severity order with file and line references. Do not praise the code or
62summarize files that have no findings.
63```
64
65Test the directory directly during development:
66
67```bash
68zot inspect ./reviewer
69zot run ./reviewer
70zot run ./reviewer "Review the authentication package"
71```
72
73Package it when ready:
74
75```bash
76zot pack ./reviewer
77# wrote code-reviewer.zot
78# digest sha256:...
79
80zot verify ./code-reviewer.zot
81zot run ./code-reviewer.zot
82```
83
84The first run displays the declared permissions and asks for consent before the agent starts.
85
86## Directory layout
87
88```text
89my-agent/
90├── manifest.json # identity, requirements, and permissions, required
91├── AGENT.md # persona and standing instructions, required
92├── skills/ # SKILL.md directories, optional
93│ └── my-skill/SKILL.md
94├── assets/ # static files, optional
95└── README.md # human-facing documentation, optional
96```
97
98Only `manifest.json` and a regular `AGENT.md` file are required. Other ordinary files and directories are included in the archive, but the runtime gives no special behavior to `assets/` or `README.md` yet. Files in `assets/` are not automatically added to the model context or granted filesystem access.
99
100Do not include executable extensions in `extensions/`. The local runtime rejects any bundled extension directory containing `extension.json` because extension subprocesses cannot yet be confined to the manifest permissions. This is a deliberate fail-closed restriction.
101
102Symlinks are not supported and cause `zot pack` to fail.
103
104## `AGENT.md`
105
106By default, `AGENT.md` is appended to zot's system prompt. It should describe the agent's role, workflow, constraints, output format, and when to load bundled skills.
107
108Keep capability and security declarations out of this file. Permissions come only from `manifest.json` and are enforced independently of agent-authored prose.
109
110Set `replace_system_prompt` to `true` in the manifest to use `AGENT.md` as the replacement system prompt:
111
112```json
113{
114 "replace_system_prompt": true
115}
116```
117
118Replacement is intended for fully specialized agents. The default layering behavior is usually preferable because it retains zot's normal identity and tool-use guidance.
119
120## Bundled skills
121
122Place skills under `skills/<name>/SKILL.md` using the normal zot skill format:
123
124```text
125skills/
126└── investigate-failure/
127 └── SKILL.md
128```
129
130```markdown
131---
132name: investigate-failure
133description: Diagnose a failing command from its output and relevant source files.
134---
135
136# Investigate failure
137
1381. Reproduce the failure if permissions allow it.
1392. Identify the first meaningful error rather than downstream noise.
1403. Read the implementation and nearest tests.
1414. Propose the smallest correction and validation plan.
142```
143
144Bundled skills are added to normal skill discovery while the zotfile is running. The model sees their name and description in the skill manifest and can load the full body through the `skill` tool. See [skills.md](skills.md) for the complete skill format.
145
146## Manifest reference
147
148The current manifest shape is:
149
150```json
151{
152 "zotfile": 1,
153 "name": "code-reviewer",
154 "version": "0.1.0",
155 "description": "Reviews a repository and reports actionable findings.",
156 "license": "MIT",
157 "runtime": {
158 "min_zot": "0.2.76"
159 },
160 "model": {
161 "requires": ["tools", "reasoning"],
162 "min_context": 64000,
163 "preferred": ["claude-opus-4-5", "gpt-5.5"],
164 "min_tier": ""
165 },
166 "permissions": {
167 "fs": {
168 "read": ["${workspace}", "${agent_data}"],
169 "write": ["${agent_data}"]
170 },
171 "bash": {
172 "mode": "allowlist",
173 "allow": ["git", "go"]
174 },
175 "net": {
176 "allow": []
177 },
178 "env": {
179 "read": []
180 }
181 },
182 "requirements": {
183 "bin": ["git", "go"],
184 "os": ["darwin", "linux"]
185 },
186 "entry": {
187 "greeting": "What should I review?",
188 "default_prompt": null
189 },
190 "replace_system_prompt": false
191}
192```
193
194### Top-level fields
195
196| Field | Required | Current behavior |
197|---|---:|---|
198| `zotfile` | yes | Format version. Must be `1`. |
199| `name` | yes | Local agent identity and session/data namespace. See naming rules below. |
200| `version` | no | Displayed in consent and inspection output. Semver is recommended but not currently validated. |
201| `description` | no | Displayed by `zot inspect`. |
202| `license` | no | Package metadata. Not otherwise interpreted by the local runtime. |
203| `runtime.min_zot` | no | Minimum zot version. Older binaries refuse to run the agent. Unversioned development builds cannot satisfy a non-empty minimum. |
204| `model` | no | Model capabilities, minimum context, and preferences. |
205| `permissions` | no | Filesystem and bash permission ceiling. Omitted scopes deny access. |
206| `requirements` | no | Required operating systems and executables. |
207| `entry` | no | Initial presentation and prompt metadata. |
208| `replace_system_prompt` | no | Replaces rather than appends to the normal system prompt when `true`. Defaults to `false`. |
209
210### Name rules
211
212The local runtime currently accepts a flat lowercase name containing only:
213
214- `a` to `z`
215- `0` to `9`
216- `.`, `-`, and `_`
217
218Examples:
219
220```text
221code-reviewer
222repo_onboarder
223acme.audit
224```
225
226Names containing `/`, uppercase letters, spaces, or path-like values such as `..` are rejected. Registry-style `namespace/agent` names are reserved for the future distribution runtime and are not accepted locally yet.
227
228### Model requirements
229
230`model.requires` currently recognizes:
231
232| Capability | Behavior |
233|---|---|
234| `tools` | Accepted. Every model in the current catalog is treated as tool-capable. |
235| `reasoning` | Requires a catalog model marked as supporting reasoning. |
236| `vision` | Recognized, but currently fails closed because vision support is not represented in the model catalog. No model qualifies. |
237
238Unknown capabilities are rejected. Use `tools`, not the draft spelling `tool_calling`.
239
240`model.min_context` requires a catalog model with at least that many context tokens.
241
242`model.preferred` is an ordered list of model IDs. It is a preference, not a provider requirement. Selection proceeds as follows:
243
2441. An explicitly selected model, if present, must satisfy the requirements.
2452. The user's configured default is retained if it satisfies them.
2463. The first compatible model in `preferred` is selected.
2474. Otherwise, zot chooses a compatible active catalog model.
2485. If none qualifies, execution stops with an error.
249
250`model.min_tier` is present in the format shape but is not supported by the local runtime. Leave it empty or omit it. A non-empty value is rejected.
251
252### Runtime and host requirements
253
254Use `requirements.os` to restrict the agent to Go operating-system names:
255
256```json
257{
258 "requirements": {
259 "os": ["darwin", "linux", "windows"]
260 }
261}
262```
263
264Use `requirements.bin` for commands that must already be on `PATH`:
265
266```json
267{
268 "requirements": {
269 "bin": ["git", "python3"]
270 }
271}
272```
273
274Zot checks these requirements before requesting consent. These zotfiles do not have install or postinstall hooks, so authors must document how users can obtain missing programs.
275
276### Entry fields
277
278`entry.default_prompt` is used when the user runs the agent without a prompt. It may be a string or `null`:
279
280```json
281{
282 "entry": {
283 "default_prompt": "Review the current repository"
284 }
285}
286```
287
288A prompt supplied on the command line takes precedence.
289
290`entry.greeting` is part of the manifest, but the current local runtime does not render it yet.
291
292## Filesystem permissions
293
294Filesystem permissions are enforced by the built-in `read`, `write`, and `edit` tools. Empty or omitted scopes deny the operation.
295
296Two variables are available in filesystem scopes:
297
298| Variable | Resolves to |
299|---|---|
300| `${workspace}` | The current working directory used for the run. |
301| `${agent_data}` | The agent's persistent private data directory under `$ZOT_HOME/agents/<name>/data/`. |
302
303Relative paths are resolved beneath `${workspace}`. For example:
304
305```json
306{
307 "permissions": {
308 "fs": {
309 "read": ["src", "go.mod"],
310 "write": ["${agent_data}"]
311 }
312 }
313}
314```
315
316This allows reads under `<workspace>/src` and at `<workspace>/go.mod`, plus writes under the private agent data directory. It does not grant general workspace writes.
317
318Common permission profiles follow.
319
320Read-only repository agent:
321
322```json
323{
324 "permissions": {
325 "fs": {
326 "read": ["${workspace}"],
327 "write": []
328 },
329 "bash": { "mode": "none" }
330 }
331}
332```
333
334Repository editor with private persistent state:
335
336```json
337{
338 "permissions": {
339 "fs": {
340 "read": ["${workspace}", "${agent_data}"],
341 "write": ["${workspace}", "${agent_data}"]
342 },
343 "bash": { "mode": "none" }
344 }
345}
346```
347
348Data-only agent:
349
350```json
351{
352 "permissions": {
353 "fs": {
354 "read": ["${agent_data}"],
355 "write": ["${agent_data}"]
356 },
357 "bash": { "mode": "none" }
358 }
359}
360```
361
362Filesystem checks canonicalize existing paths, or the nearest existing parent for a new path, so symlinks cannot be used to escape a declared scope.
363
364If the working directory changes during a run, `${workspace}` permissions are expanded again for the new directory.
365
366## Bash permissions
367
368`permissions.bash.mode` supports three values.
369
370### `none`
371
372```json
373{
374 "bash": { "mode": "none" }
375}
376```
377
378All bash tool calls are denied. This is also the default when `mode` is omitted.
379
380### `ask`
381
382```json
383{
384 "bash": { "mode": "ask" }
385}
386```
387
388Bash is available after the user approves the agent at launch. Consent for an agent using `ask` is requested on every launch and is not cached.
389
390In the current local runtime, `ask` is launch-time capability consent. It does not open a separate confirmation dialog for every individual bash invocation.
391
392### `allowlist`
393
394```json
395{
396 "bash": {
397 "mode": "allowlist",
398 "allow": ["git", "go", "grep"]
399 }
400}
401```
402
403Every command in a shell expression must be listed. Zot checks commands separated by `;`, `&&`, `||`, and pipes. Paths are reduced to their base command name, so `/usr/bin/git` is checked as `git`. A leading environment assignment is skipped when identifying the command.
404
405The allowlist rejects shell substitution, newlines, redirection, backticks, `$()`, `<`, and `>`. This intentionally supports simple command pipelines rather than arbitrary shell programs.
406
407An `allowlist` mode with an empty `allow` array is invalid.
408
409Only declare commands the agent genuinely needs. `requirements.bin` checks that a command exists, while `permissions.bash.allow` controls whether the agent may invoke it. Agents that execute a required command normally need it in both places.
410
411## Network and environment permissions
412
413The manifest shape includes `permissions.net.allow` and `permissions.env.read`, but the local runtime does not enforce them yet. To avoid presenting unenforced declarations as security controls, it rejects manifests containing any network host or environment variable.
414
415Use empty arrays or omit these sections:
416
417```json
418{
419 "permissions": {
420 "net": { "allow": [] },
421 "env": { "read": [] }
422 }
423}
424```
425
426Bundled executable extensions are rejected for the same reason. Network filtering, scrubbed extension environments, and extension confinement belong to a later runtime milestone.
427
428## Consent and persistent data
429
430Before the first run, zot prints the agent identity and expanded filesystem and bash permissions, then asks:
431
432```text
433Agent code-reviewer@0.1.0 wants to run.
434
435 fs read: /path/to/workspace
436 fs write: none
437 bash: none
438
439Allow? [y/N]
440```
441
442For modes other than `bash: ask`, approval is cached for the exact artifact digest under:
443
444```text
445$ZOT_HOME/agents/<name>/consents/<digest>.json
446```
447
448Any change to the packaged artifact produces a different digest and requires consent again. `bash: ask` always requires fresh launch consent.
449
450Non-interactive runs refuse to bypass consent by default. For controlled automation, set:
451
452```bash
453ZOT_AGENT_CONSENT=1 zot run ./code-reviewer.zot --print "Review this repository"
454```
455
456This environment variable skips the consent prompt. Only use it after independently inspecting and trusting the exact artifact being run.
457
458Persistent agent data lives under:
459
460```text
461$ZOT_HOME/agents/<name>/data/
462```
463
464The directory is created for every run, but the agent can access it only when `${agent_data}` appears in the relevant filesystem permission scope.
465
466## Agent-scoped sessions
467
468Sessions created by a zotfile are isolated from ordinary zot sessions and from other agents:
469
470```text
471$ZOT_HOME/sessions/agents/<name>/
472```
473
474Normal session flags still apply, including `--continue`, `--resume`, `--session`, and `--no-session`, but their default storage root is scoped to the active agent.
475
476## Commands
477
478### `zot run`
479
480Run an unpackaged directory during development:
481
482```bash
483zot run ./my-agent
484zot run ./my-agent "Do the task"
485```
486
487Run a packed artifact:
488
489```bash
490zot run ./my-agent.zot
491zot run ./my-agent.zot --print "Do the task"
492zot run ./my-agent.zot --json "Do the task"
493```
494
495Arguments after the reference use zot's normal CLI parser, so model, provider, reasoning, cwd, session, tool, and output-mode flags remain available. The manifest still imposes its permission and compatibility ceiling.
496
497Local filesystem directories, local archive paths, short names, and public GitHub agent-directory URLs are accepted. A short name uses local-first resolution:
498
499```bash
500zot run zot-maintenance
501```
502
503Zot checks `./zot-maintenance` and `./zot-maintenance.zot` before falling back to `https://github.com/patriceckhart/agents/zot-maintenance`. This makes local development override the remote collection without an install or cache step.
504
505A two-part name selects a GitHub repository under the `patriceckhart` organization:
506
507```bash
508zot run agents/zot-maintenance
509zot run agents\zot-maintenance # also accepted on Windows
510```
511
512The first part is the repository and the second part is the agent directory. Both parts must use lowercase letters, digits, dots, hyphens, or underscores. Prefix a reference with `./`, use an absolute path, retain the `.zot` suffix, or provide a complete GitHub URL when remote fallback is not wanted.
513
514For GitHub, zot downloads the repository archive into a temporary directory, selects the requested agent subdirectory, validates it, runs it, and removes the downloaded files when the command exits:
515
516```bash
517zot run https://github.com/patriceckhart/agents/zot-maintenance --cwd /path/to/zot
518```
519
520Both the short subdirectory form above and a standard GitHub tree URL are supported:
521
522```bash
523zot run https://github.com/patriceckhart/agents/tree/main/zot-maintenance
524```
525
526The short form reads the repository's default branch through GitHub's `HEAD` archive. A tree URL uses the branch or tag in the URL. Private repositories and GitHub references containing `/` are not currently supported. The downloaded source is temporary, but normal agent data, consent receipts, and session transcripts remain under `$ZOT_HOME`.
527
528Short-name fallback is a fixed GitHub mapping, not an indexed or signed registry. Installed names, arbitrary URLs, OCI references, and third-party registry configuration are not resolved yet.
529
530### `zot pack`
531
532```bash
533zot pack [directory] [output]
534```
535
536Examples:
537
538```bash
539zot pack
540zot pack ./my-agent
541zot pack ./my-agent ./dist/reviewer.zot
542```
543
544The default directory is the current directory. When output is omitted, zot uses `<manifest-name>.zot`. If the output has no `.zot` suffix, zot adds one.
545
546Packing validates the manifest and directory, then creates a zstd-compressed tar archive. Entries are sorted and tar metadata is normalized with fixed timestamps and numeric ownership. The output archive itself is excluded when it is located inside the source directory. Zot prints the SHA-256 digest of the resulting compressed artifact.
547
548### `zot inspect`
549
550```bash
551zot inspect ./my-agent
552zot inspect ./my-agent.zot
553zot inspect https://github.com/patriceckhart/agents/zot-maintenance
554```
555
556Inspection validates and prints the agent's name, version, description, digest, declared permissions, and complete file list. It does not execute the agent.
557
558For a directory, the digest is computed from its canonical uncompressed tar representation. For a `.zot` archive, the digest is computed from the archive bytes. Therefore a source-directory digest and its packed-archive digest are not expected to match.
559
560### `zot verify`
561
562```bash
563zot verify ./my-agent.zot
564```
565
566The local `verify` command validates that the archive can be safely loaded, validates the manifest and required layout, and prints its SHA-256 digest.
567
568Despite the command name, it does **not** verify a publisher signature in the current runtime. Signature and namespace verification are planned for registry distribution.
569
570## Packaging and extraction limits
571
572The archive loader applies these limits:
573
574| Limit | Value |
575|---|---:|
576| Compressed `.zot` file | 100 MiB |
577| One extracted entry | 64 MiB |
578| Total extracted content | 256 MiB |
579
580Archive extraction rejects absolute paths and parent traversal. Unsupported tar entry types are ignored. New packages use zstd; gzip-compressed tar archives are accepted only as a compatibility fallback for earlier experiments.
581
582## Authoring guidance
583
5841. Start with the narrowest permissions possible. A reviewer usually needs repository reads, not writes or bash.
5852. Keep `AGENT.md` focused on stable behavior. Put task-specific procedures in skills so the model loads them only when relevant.
5863. Declare every external command in both `requirements.bin` and the bash allowlist when the agent must execute it.
5874. Test from a directory first with `zot inspect` and `zot run`.
5885. Test denied behavior as well as allowed behavior. Ask the agent to attempt an out-of-scope read, write, and command.
5896. Pack the same source twice and compare behavior and output digests before distributing it.
5907. Inspect and verify the final archive, not only its source directory.
5918. Do not claim that network, environment, signatures, extensions, installation, or registry delivery are secured or supported by the local runtime.
592
593## Current scope
594
595Implemented now:
596
597- local directories and `.zot` archives
598- local-first short-name resolution to the official GitHub agent collection
599- temporary execution of agent directories from public GitHub repositories
600- `zot pack`, `zot inspect`, `zot verify`, and `zot run`
601- canonical tar creation with zstd compression
602- archive digest reporting and safe extraction limits
603- `AGENT.md` append or replacement behavior
604- bundled skills
605- runtime, OS, and binary requirements
606- model context and reasoning requirements
607- filesystem scope enforcement
608- bash `none`, `ask`, and `allowlist` modes
609- digest-scoped consent receipts
610- private agent data directories
611- agent-scoped sessions
612
613Not implemented yet:
614
615- `zot install`, `zot agents`, `zot use`, `zot update`, or `zot publish`
616- installed-name, arbitrary URL, OCI, configurable registry, or zot.sh index resolution
617- network allowlist enforcement
618- environment-variable filtering
619- safely confined bundled executable extensions
620- automatic artifact theme loading
621- agent dependency composition
622- per-agent Telegram, bot, or RPC selection
623- `--no-sandbox`, `--trust-bash`, or registry trust override flags
624
625Treat the unsupported fields and commands in the broader zotfile proposal as forward-looking design, not as current runtime behavior.