REQ-C-011: Commands Declare Filesystem Side Effects
Tier: Command Contract | Priority: P3
Source: §30 Undeclared Filesystem Side Effects
Addresses: Severity: Medium / Token Spend: Low / Time: Low / Context: Low
Description
Command authors MUST declare all filesystem side effects in the command's registration metadata using the filesystem_side_effects array. Each entry MUST specify: path (template or glob), type (one of: cache, log, temp, credential, config, output), ttl_seconds (if applicable), and clearable_with (the framework command to clear it; neither applies to output). The framework uses this information for tool status --show-side-effects and tool cleanup.
Output paths. output is a path the command writes as its product: a generated report, a rendered dashboard, collected evidence. tool status --show-side-effects lists it like any other kind, but tool cleanup never removes it under any --scope, because the user asked for it. An output entry carries neither ttl_seconds nor clearable_with: the product does not go stale and is not the framework's to clear. Declaring a product as cache would let cleanup delete what the user asked for, and leaving it undeclared hides a write.
Output paths and --output. An output entry declares a location the command chooses itself, fixed or templated, such as {project_root}/tmp/dashboard/. A path the caller names per call with --output <path> or --output-dir <path> is declared by output_file (REQ-O-001), not here; declaring both for the same file describes one write twice. When the command writes its product to a default location in the absence of --output, that default location is an output entry.
Side effects and danger_level. cache, log, temp, and output are not state: a command whose only writes are of these kinds keeps danger_level: "safe" (REQ-C-002), and declaring them here is what lets it stay safe. credential and config change state the next invocation reads, so a command that writes them is at least mutating.
Acceptance Criteria
- A command that writes to a cache directory declares that path in
filesystem_side_effects tool status --show-side-effectslists all paths declared by registered commandstool cleanupremoves all paths declared astype: "temp"ortype: "cache"- A command that writes a generated report under a path it chooses declares that path with
type: "output" tool status --show-side-effectslistsoutputpaths with their type and sizetool cleanup, with any--scopeincludingall, removes no path declared astype: "output"- A
filesystem_side_effectsentry withtype: "output"andttl_secondsorclearable_withfails schema validation - A command whose only declared writes are
cache,log,temp, oroutputmay declaredanger_level: "safe" - A command whose result file comes only from
--output <path>declaresoutput_file, and nooutputentry for that path
Schema
Types: manifest-response.md
The filesystem_side_effects array is declared at registration and appears in the command's --schema output.
{
"filesystem_side_effects": {
"type": "array",
"items": {
"type": "object",
"required": ["path", "type"],
"properties": {
"path": { "type": "string", "description": "Template or glob for paths written by the command" },
"type": { "type": "string", "enum": ["cache", "log", "temp", "credential", "config", "output"], "description": "Category of the side effect; output is the command's product" },
"ttl_seconds": { "type": "integer", "description": "Seconds until the path is considered stale; omit if permanent" },
"clearable_with": { "type": "string", "description": "Framework command that removes this path" }
},
"if": { "properties": { "type": { "const": "output" } }, "required": ["type"] },
"then": { "not": { "anyOf": [{ "required": ["ttl_seconds"] }, { "required": ["clearable_with"] }] } }
},
"description": "All filesystem locations the command may write to"
}
}
Wire Format
$ tool fetch-schema --schema
{
"command": "fetch-schema",
"filesystem_side_effects": [
{
"path": "~/.cache/tool/schemas/",
"type": "cache",
"ttl_seconds": 3600,
"clearable_with": "tool cache clear --scope schemas"
}
]
}
A read-only command that writes a rendered dashboard as its product:
{
"command": "dashboard.build",
"danger_level": "safe",
"filesystem_side_effects": [
{ "path": "{project_root}/tmp/dashboard/", "type": "output" }
]
}
Example
A command that writes to a cache directory declares the path, type, TTL, and the command that clears it at registration.
register command "fetch-schema":
danger_level: safe
filesystem_side_effects:
- path: "~/.cache/tool/schemas/"
type: cache
ttl_seconds: 3600
clearable_with: "tool cache clear --scope schemas"
exit_codes:
SUCCESS(0): description: "Schema fetched and cached", retryable: false, side_effects: complete
register command "process":
danger_level: mutating
filesystem_side_effects:
- path: "/tmp/tool-process-{session_id}/"
type: temp
ttl_seconds: 3600
clearable_with: "tool cleanup --session {session_id}"
- path: "~/.local/share/tool/logs/{date}.log"
type: log
clearable_with: "tool cleanup --logs"
exit_codes:
SUCCESS(0): description: "Processing completed", retryable: false, side_effects: complete
register command "services.inspect":
danger_level: safe
filesystem_side_effects:
- path: "{project_root}/tmp/evidence/{service}/"
type: output
exit_codes:
SUCCESS(0): description: "Evidence collected", retryable: false, side_effects: complete
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-O-027 | O | Consumes: clearable_with commands declared here are aggregated and invoked by tool cleanup |
| REQ-O-028 | O | Consumes: filesystem_side_effects declarations are listed by tool status --show-side-effects |
| REQ-F-032 | F | Provides: framework-managed session temp directory that auto-cleans on session end |
| REQ-F-042 | F | Provides: framework log rotation for paths declared as type: "log" |
| REQ-O-041 | O | Aggregates: manifest exposes filesystem_side_effects for each command |
| REQ-C-002 | C | Composes: writes of cache, log, temp, and output paths leave a command safe |
| REQ-O-001 | O | Composes: a per-call --output path is declared by output_file, a command-chosen product path by type: "output" |