Summary
Add filesystem-state attestation to the audit store: compute a cryptographic commitment over the run's writable paths before the agent starts and again after it exits, so a run can prove what changed on disk — or prove that nothing did.
Moat's audit today is an event log (hash-chained console/network/credential events). It records what happened over the wire and at the boundary, but not what the agent did to the filesystem. This adds the complementary axis: a verifiable, after-the-fact answer to "which files did this run actually modify?"
Motivation
- Provable blast radius. For a tool whose pitch is full observability of untrusted agents, being able to attest "this run provably touched only these N files" (or "provably changed nothing in the tracked paths") is high-value for review, compliance, and incident response.
- Tamper-evidence for disk changes. The audit store already gives tamper-evident events; this extends the same guarantee to filesystem state.
- Cheap to add on existing machinery. Moat already has a hash-chained audit store and exportable proof bundles to anchor the roots into.
Proposed mechanism
Compute a Merkle root over the writable/tracked paths at two points:
- Pre-root — before the agent starts, walk the tracked paths and hash
(relative_path, file_content_hash) leaves into a Merkle tree; record the root.
- Post-root — after the agent exits, recompute the root.
Properties:
- If
pre_root == post_root, it is cryptographically provable nothing in the tracked paths changed.
- If they differ, the filesystem changed; the per-file leaf hashes let a verifier enumerate exactly which paths differ (added/removed/modified).
- Use SHA-256 with domain separation (distinct prefixes for leaf vs. internal-node hashes) so a leaf hash can't be confused with an internal node.
- Record both roots in the run's session metadata and fold the post-root into the existing audit chain / export bundle so it's covered by the same signature.
Scope of tracked paths
- Default: the run's writable mount(s) / workspace.
- Exclusion patterns for regenerable or huge trees (
.git, node_modules, target, dist, .next, etc.) and a size guard (skip directories above a configurable file-count threshold) so large repos don't make pre/post walks pathologically slow. Surface skipped paths in the metadata so the attestation's scope is explicit and honest.
Configuration sketch
# moat.yaml
audit:
filesystem_attestation:
enabled: true
paths: [./] # defaults to writable mounts
exclude: [.git, node_modules, target]
max_files_per_dir: 10000 # skip + record dirs larger than this
Verification
Extend the audit verify/export flow so a reviewer can:
Open questions
- Walk cost on large monorepos — is a pre-run walk acceptable, or do we need an opt-in / incremental approach (e.g., watch-based) for big workspaces?
- Should leaf content hashes be stored (enables exact per-file diff but larger metadata) or only the root (smaller, but diff requires re-walking the pre-state)?
- Symlinks and out-of-tree writes: define behavior for symlinks pointing outside tracked paths and for writes to paths outside the writable set.
- How does this compose with the per-run export proof bundle — separate artifact or additional fields in the existing bundle?
Out of scope (for this issue)
- Snapshot/rollback of the changes (separate feature — this issue only attests to changes, it does not capture or restore content).
- Executable-identity binding in the audit trail (related provenance improvement; tracked separately).
Summary
Add filesystem-state attestation to the audit store: compute a cryptographic commitment over the run's writable paths before the agent starts and again after it exits, so a run can prove what changed on disk — or prove that nothing did.
Moat's audit today is an event log (hash-chained console/network/credential events). It records what happened over the wire and at the boundary, but not what the agent did to the filesystem. This adds the complementary axis: a verifiable, after-the-fact answer to "which files did this run actually modify?"
Motivation
Proposed mechanism
Compute a Merkle root over the writable/tracked paths at two points:
(relative_path, file_content_hash)leaves into a Merkle tree; record the root.Properties:
pre_root == post_root, it is cryptographically provable nothing in the tracked paths changed.Scope of tracked paths
.git,node_modules,target,dist,.next, etc.) and a size guard (skip directories above a configurable file-count threshold) so large repos don't make pre/post walks pathologically slow. Surface skipped paths in the metadata so the attestation's scope is explicit and honest.Configuration sketch
Verification
Extend the audit verify/export flow so a reviewer can:
Open questions
Out of scope (for this issue)