This document answers the Phase 1 readiness questions in AGENTFS_DEVELOPMENT_READINESS.md.
It is the development contract for the first implementation slice:
Agent / Installation / FS / SourceProfile / Grant / Share / Credential / Commit / Event
Hooks, proposal/approval workflows, path-scoped grants, and AGENTS.md enforcement are out of scope for this contract.
正式产品的跨机 / 多 agent sharing 依赖 Section Control Service。服务端是 agent identity、installation、grant、share、source profile、credential 的权威。
IDs are stable, opaque strings. Display names are metadata and can change.
| Term | Format | Notes |
|---|---|---|
agent_id |
agt_ + 32 lowercase hex chars |
Issued by Section Control Service and cached locally |
installation_id |
ins_ + 32 lowercase hex chars |
One local machine/runtime for an agent |
fs_id |
fs_ + 32 lowercase hex chars |
Generated at FS creation; independent from source profile name |
source_profile_id |
srcp_ + 32 lowercase hex chars |
Server-side backing source profile |
share_id |
shr_ + 32 lowercase hex chars |
Server-side share record |
credential_binding_id |
cred_ + 32 lowercase hex chars |
Short-lived sync credential audit record |
mount_id |
derived from fs_id + canonical_local_root in MVP |
One active local root per FS per local installation store |
commit_id |
cmt_ + 32 lowercase hex chars |
Generated before commit metadata is written |
event_id |
evt_ + 13 digit epoch-ms + _ + 16 lowercase hex chars |
Event identity only; ordering uses seq |
event_seq |
per-FS integer, starts at 1 | Strictly increases inside one FS |
grant_id |
grt_ + 32 lowercase hex chars |
Generated when a grant is created |
All timestamps are Unix epoch milliseconds in UTC stored as integers.
Path strings are UTF-8, slash-separated, source-root-relative paths:
- no leading slash
- no
..segments - no empty segment except the root path represented as
"" .section/**is reserved Section metadata
The truth hierarchy is:
Section Control Service = identity, grant, share, source profile, credential authority
accepted commit log = governance truth
backing source = materialized filesystem state
local mount = working copy
A commit is accepted when:
- Section Control Service confirms the committing agent has an active
commitcapability, - the local base commit equals the current shared head,
- the commit does not include reserved metadata paths,
- the commit record is written under
.section/agentfs/commits/, heads/current.jsonpoints to that commit.
The backing source can lag behind the accepted commit log.
If commit metadata succeeds but file materialization fails:
- the commit remains the governance truth,
heads/current.jsonremains pointed at the accepted commit,- commit materialization state becomes
failed_to_materialize, - FS state is
error, - further commits are blocked until materialization is repaired.
Watchers can rely on accepted commit records and AgentFS events as governance authority. Service-side events are authoritative for grant/revoke governance. Backing-source events are a mirror and commit/materialization audit surface. File reads rely on the materialized backing source and may lag while FS state is syncing or error.
External edits to the backing source are not governed commits. They are detected by source/path comparison and should surface as drift or conflict, using the existing stale-overwrite protection.
Service-owned records:
agents
installations
source_profiles
grants
shares
credential_bindings
events
AgentFS metadata may be mirrored under the backing source:
.section/
agentfs/
fs.json
heads/
current.json
grants/
<grant_id>.json
commits/
<commit_id>.json
events/
<event_id>.json
Rules:
.section/**is reserved.- Normal commits cannot modify reserved metadata paths.
- The local mount may expose
.section/root.jsonfor discovery. - The local mount should not expose
.section/**as normal user content when it can avoid it. - If reserved metadata appears in a working copy,
commit applymust ignore it for dirty detection and reject explicit attempts to commit it.
Metadata files are rewritten as whole JSON documents. The MVP does not use JSONL append files because object backends do not provide portable append semantics.
Authority rules:
- Section Control Service is authoritative for identity, grant, share, source profile, and credential decisions.
- Section Control Service is authoritative for grant/revoke events.
- The backing-source metadata namespace is a mirror for materialization, audit, repair, and diagnosis.
fs eventsandwatch --agentfsreturn a merged event view from Section Control Service and backing-source metadata.- If grant/revoke mirror writes fail, the service-side governance mutation and service-side event still stand.
- Normal commits cannot modify mirrored metadata paths.
fs list,fs status,fs events, andwatch --agentfsonly expose FS metadata to agents withreadcapability.
AgentFS 用锁记录保护 head 更新和 commit 接受。
新的锁记录写在:
.section/agentfs/locks/head/<lock_token>.json
Lock fields:
{
"schema_version": 1,
"fs_id": "fs_...",
"lock_token": "lck_...",
"owner_agent_id": "agt_...",
"created_at_ms": 1780000000000,
"expires_at_ms": 1780000030000
}Rules:
- The lock protects head updates and commit acceptance.
- Grant, share, source profile, and credential changes are protected by Section Control Service.
- 申请锁时必须用 backing source 的 create-if-absent /
if_not_exists能力创建自己的锁记录。 - 同一个 FS 里,未过期锁记录按
created_at_ms、lock_token排序,排第一的记录持有锁。 - 没拿到锁的命令必须删除自己的锁记录,并返回
metadata_write_conflict。 expires_at_ms之后的锁记录会被忽略。- 释放锁只删除自己的
<lock_token>.json。 - 旧版本的
.section/agentfs/locks/head.json如果还存在且未过期,会继续阻塞写入;新版本不再写这个单文件锁。 - AgentFS 不做无条件覆盖 fallback。backing source 必须支持 metadata 条件创建和锁目录一致列举;不支持时命令失败。
All records include schema_version: 1.
Readers must reject shared metadata with the wrong schema version, invalid IDs,
invalid AgentFS paths, inconsistent grant capabilities, or cross-record links
that point at another FS. The JSON error code is malformed_shared_metadata.
{
"schema_version": 1,
"fs_id": "fs_...",
"name": "project",
"owner_agent_id": "agt_...",
"source_profile_id": "srcp_...",
"created_at_ms": 1780000000000
}{
"schema_version": 1,
"grant_id": "grt_...",
"fs_id": "fs_...",
"agent_id": "agt_...",
"role": "writer",
"capabilities": ["read", "commit"],
"granted_by": "agt_...",
"created_at_ms": 1780000000000,
"revoked_at_ms": null,
"revoked_by": null
}revoked_at_ms != null makes the grant inactive.
{
"schema_version": 1,
"commit_id": "cmt_...",
"fs_id": "fs_...",
"parent_commit_id": "cmt_...",
"base_commit_id": "cmt_...",
"agent_id": "agt_...",
"summary": "Update docs",
"authorized_by": {
"type": "grant",
"grant_id": "grt_...",
"role": "writer",
"capabilities": ["read", "commit"]
},
"paths": [
{
"path": "docs/readme.md",
"kind": "file",
"op": "update",
"local_version": "sha256:...",
"previous_version": "sha256:..."
}
],
"staging_snapshot": {
"manifest_path": "agentfs/staging/fs_.../cmt_.../manifest.json",
"manifest_hash": "sha256:..."
},
"created_at_ms": 1780000000000,
"materialization_state": "pending",
"materialized_at_ms": null,
"error": null
}Allowed op values:
createupdatedelete
Allowed materialization_state values:
pendingmaterializedfailed_to_materialize
authorized_by.type is either owner or grant.
Owner commit:
{
"type": "owner",
"agent_id": "agt_..."
}Grant commit:
{
"type": "grant",
"grant_id": "grt_...",
"role": "writer",
"capabilities": ["read", "commit"]
}The commit record keeps this audit even if the grant is revoked later.
{
"schema_version": 1,
"fs_id": "fs_...",
"commit_id": "cmt_...",
"updated_at_ms": 1780000000000
}For a newly created empty FS, commit_id is null.
{
"schema_version": 1,
"event_id": "evt_1780000000000_0123456789abcdef",
"seq": 42,
"fs_id": "fs_...",
"kind": "commit.accepted",
"actor_agent_id": "agt_...",
"subject_id": "cmt_...",
"path": null,
"created_at_ms": 1780000000000,
"data": {}
}Event path is optional. FS-level events use null.
MVP roles are FS-wide.
| Role | Capabilities |
|---|---|
owner |
read, commit, manage |
reader |
read |
writer |
read, commit |
manager |
read, manage |
Rules:
- The creating agent receives an owner grant.
- Owner cannot be revoked.
- Ownership transfer is deferred.
managercannot grantowner.managercan create, revoke, or replacereader,writer, andmanagergrants.managercan create server-side shares for agents that already have readable grants.- Revoked agents cannot attach or commit after revocation is observed.
- Existing raw local files remain on disk after revocation, but they cannot become shared truth through AgentFS commit.
commit apply commits all dirty paths under the attached root in MVP.
Partial path commits are deferred.
Dirty paths are discovered by comparing the local tree against the last known mounted base state and current path sync state.
Freshness base:
- the trusted local mount store records
base_commit_idfor the attached working copy. .section/root.jsonhelps discover the mount identity, but it is not trusted for freshness.heads/current.jsonrecords current shared head.- commit is rejected with
stale_basewhen the trusted local mount base and current shared head differ.
Rules:
- summary is required and must be non-empty after trimming whitespace.
- empty commits are rejected.
- commits containing
.section/**are rejected. - reserved metadata paths are ignored in dirty detection.
- external backing-source drift is treated as conflict or stale state before commit acceptance.
提交输入规则:
commit apply先把本次 dirty paths 复制到本地 staging snapshot。paths[*].local_version从 staging snapshot 计算。- commit record 里的 paths 必须来自 staging manifest。
- materialization 只能读取 staging snapshot,不能再读 live working tree。
- 如果 staging snapshot 创建失败,commit 不写 metadata。
- 如果 live working tree 在 commit 过程中继续变化,这些变化属于下一次 dirty work。
Commit acceptance writes governance metadata first:
- create staging snapshot,
- acquire head lock,
- verify grant and freshness,
- write commit record with
materialization_state: "pending", - update
heads/current.json, - write
commit.acceptedevent, - release head lock,
- materialize file changes from staging snapshot to backing source,
- update commit materialization state,
- write
commit.materialized, or write bothcommit.materialization_failedandfs.error, - update local mount store and root marker as a local finalization step.
If step 11 fails after accepted metadata and backing-source materialization have succeeded, the command still succeeds and returns a local warning. The accepted commit remains the governance truth.
If materialization fails:
- commit remains accepted,
- FS state becomes
error, commit applyis blocked for that FS,- attach reports materialization error,
- repair is required before further accepted commits.
Retry behavior:
- retry is safe only for commits in
pendingorfailed_to_materialize. - retry must use the existing
commit_id. - retry must not create a second accepted commit.
MVP event kinds:
fs.created
fs.attached
grant.created
grant.revoked
commit.accepted
commit.materialized
commit.materialization_failed
fs.error
Event records are immutable.
Event files are written with backing source create-if-absent / if_not_exists.
If .section/agentfs/events/<event_id>.json already exists, the command returns
metadata_write_conflict and keeps the old event content unchanged. AgentFS
does not fall back to read-then-write overwrite behavior.
Replay:
- event files are listed under
.section/agentfs/events/, - clients sort by
seq, - clients can resume from the last seen
seqorevent_id.
Ordering:
seqis allocated while holding the FS head lock,- events emitted under the head lock are ordered relative to commit/grant head mutations.
- materialization events happen after the accepted commit event.
- source/path events and AgentFS events may be merged in
watch, but each output event must include a stream or kind that identifies its origin.
fs attach creates a local working copy.
Attach behavior:
- checks
readcapability with Section Control Service, - obtains or refreshes a short-lived sync credential,
- creates or updates the source local-root binding,
- writes
.section/root.json, - syncs current materialized backing-source state into the local root,
- records
base_commit_idin the trusted local mount store and mirrors it into.section/root.json.
MVP local root rule:
- one accepted FS has one active local root per local installation store,
- attaching the same FS to another local root moves the active root,
- the old root marker is removed when reattach succeeds.
root.json fields:
{
"schema_version": 1,
"fs_id": "fs_...",
"source_profile_id": "srcp_...",
"agent_id": "agt_...",
"installation_id": "ins_...",
"local_root": "/abs/path/project",
"base_commit_id": "cmt_...",
"control_plane_endpoint": "section-control-service"
}Rules:
- 一个本地安装 store 里,同一个 FS 只有一个 active local root。
- 同一个 FS 重新 attach 到另一个 local root,会移动 active root,并移除旧 root marker。
- reader mounts can be edited locally by the OS, but reader commits are denied.
- attach should fail or report non-ready state when current head is not materialized.
MVP FS binds exactly one server-side SourceProfile.
Rules:
fs createasks Section Control Service to bind a SourceProfile.- Section Control Service makes the final SourceProfile decision.
- AgentFS commands that read or write the backing source must refresh a service-issued read credential before constructing the internal source operator.
- The local cached source config is not authority; it is refreshed from Section Control Service after credential issuance.
fs create必须完整初始化 shared metadata;不能留下半个 FS。- 如果 shared metadata 初始化失败,必须回滚 Control Service 的 FS/grant/event 记录。
- 如果 shared metadata 初始化失败,必须清理本地 AgentFS source cache。
- 如果 shared metadata 初始化失败,必须尽量清理远端
.section/**初始化残留。 - 初始化失败后的同名创建必须可以重试。
- upgrading an existing source into an FS is deferred.
- low-level
sourcecommands remain sync infrastructure, not the AgentFS product surface. - AgentFS-backed sources must be guarded from ordinary source mutation commands.
source syncmust not become the official way to bypass AgentFS governance.- AgentFS commands are the governance surface; source commands are infrastructure.
- MVP does not provide a low-level force flag to mutate AgentFS-backed sources.
Documentation must not imply that low-level source commands preserve AgentFS governance.
Errors must have stable codes for JSON output.
| Code | Meaning | Retry |
|---|---|---|
unknown_agent |
Agent identity is missing or not logged in | no, login first |
unknown_fs |
FS metadata cannot be found | no, check name/id |
grant_denied |
Agent lacks required capability | no, request grant |
stale_base |
local base_commit_id differs from current head |
yes, sync/refresh first |
reserved_metadata_path |
operation attempts to commit .section/** |
no |
materialization_failed |
accepted commit could not update backing source | yes, repair/retry materialization |
malformed_shared_metadata |
shared metadata failed schema validation | no, repair metadata |
metadata_write_conflict |
metadata lock, head update, or immutable event conflict | yes |
JSON shape:
{
"error": {
"code": "grant_denied",
"message": "agent agt_... does not have commit access to fs fs_...",
"retryable": false,
"details": {
"fs_id": "fs_...",
"agent_id": "agt_..."
}
}
}Rules:
codeis stable.messageis for humans.retryableis for Agent decisions.detailsis always present in JSON output. It can be{}.
section fs status <fs-or-root> --json 是 Agent 判断能不能行动的主要入口。
输出:
{
"fs": {
"fs_id": "fs_...",
"name": "project",
"head_commit_id": "cmt_...",
"materialization_state": "materialized"
},
"agent": {
"agent_id": "agt_...",
"role": "writer",
"capabilities": ["read", "commit"]
},
"mount": {
"attached": true,
"mount_id": "hash(fs_id + canonical_local_root)",
"local_root": "/abs/path/project",
"base_commit_id": "cmt_..."
},
"worktree": {
"dirty": true,
"dirty_count": 2,
"stale": false
},
"events": {
"last_seq": 42
},
"warnings": [],
"next_actions": ["commit"]
}规则:
status可以解析 FS id、FS name、source name、local root。- 非本地路径 ref 的解析顺序是:精确 FS id,精确 source name,精确 FS name。
- 如果 source name 或 FS name 命中多个候选,返回
ambiguous_fs_ref。 - local root 解析必须看本地 mount store,不能只看
.section/root.json。 status不修改共享状态。- 如果 Agent 现在不能行动,
next_actions说明下一步安全动作,例如login、accept、attach、sync、repair、request_grant。
staging snapshot 路径:
<local-data-dir>/agentfs/staging/<fs_id>/<commit_id>/
manifest.json
files/<hash-or-safe-path>
manifest.json 内容:
{
"schema_version": 1,
"fs_id": "fs_...",
"commit_id": "cmt_...",
"base_commit_id": "cmt_...",
"created_at_ms": 1780000000000,
"paths": [
{
"path": "docs/readme.md",
"op": "update",
"kind": "file",
"hash": "sha256:...",
"size": 123,
"staged_path": "files/sha256-..."
}
]
}规则:
commit apply写 commit metadata 前先创建 staging snapshot。- commit metadata 记录 staging manifest hash。
- materialization 只能读 staging snapshot。
- staging 至少保留到 commit 已物化,并且 repair 不再需要它。
section commit repair <fs-or-root> [--commit <commit_id>] 规则:
- repair 只处理
pending或failed_to_materializecommit。 - repair 使用原来的 staging snapshot。
- repair 不创建新 commit。
- repair 不移动 head。
- repair 成功写
commit.materialized。 - repair 失败写
commit.materialization_failed和fs.error。 - 如果 staging snapshot 不存在,返回
missing_commit_snapshot。
MVP 不提供兜底修复路径。
AgentFS 支持两种 Control Service 接入方式:
control_service.endpoint:通过sectiond serve提供的 HTTP Control Service。control_service.path:本地 file-backed Control Service,主要用于开发和单机测试。
跨机 / 多 agent 分享必须使用 control_service.endpoint。客户端只配置 endpoint,不配置 SourceProfile 或 backing source 密钥。
服务端负责:
- agent login
- installation registration
- FS create/list/status metadata
- grant create/revoke/check
- share create/list/accept/revoke
- source profile selection
- short-lived credential issuance
- AgentFS event replay
- audit records
当前 MVP 暴露一个 HTTP RPC 入口:
POST /v1/rpc
规则:
- 跨机 sharing 必须走服务端。
- HTTP Control Service 请求必须携带当前 agent 的 auth token 和 installation id;服务端不能只信客户端传来的
agent_id。 - SourceProfile 由服务端决定。
- 远程服务端默认不允许自注册 agent 使用任意 SourceProfile 创建 FS;SourceProfile 必须显式允许创建者。
fs create的 backing source 空目录检查和 AgentFS metadata 初始化由服务端完成。- 普通 FS resolve/list/status 不能返回 backing source options。
- backing source options 只能通过
accept share或issue credential这种会记录 credential binding 的路径返回给已授权 agent。 - source 长期密钥不能出现在 share record、local root marker、CLI JSON 输出里。
- 本地 CLI 可以缓存 identity、accepted FS、mount state、短期 credential binding。
- 本地 CLI 不能自己发明 grant、share、source profile、长期 credential。
- 服务端拒绝时,本地 CLI 必须失败关闭。
The complete implementation test plan lives in AGENTFS_TEST_PLAN.md.
Minimum behavior tests:
- owner creates FS and receives owner authority
- writer can discover, accept, and attach after server-side share
- reader cannot commit
- writer can commit a clean local change
- stale commit is rejected
- accepted commit emits
commit.accepted - materialized commit emits
commit.materialized - second mount observes accepted commit after sync/watch
- metadata files cannot be committed as normal paths
- materialization failure produces non-ready state
- further commits are blocked while head materialization is failed
The first implementation should prove this flow:
agent-a logs in
agent-a creates fs project with a SourceProfile
agent-a grants writer to agent-b
agent-a shares fs project with agent-b
agent-b logs in
agent-b sees fs project in fs available
agent-b accepts the share
agent-b attaches project
agent-b edits a normal file
agent-b commit apply --message "update file"
agent-a watch sees commit.accepted
agent-a sync/attach sees the materialized file
That is the minimum product proof for AgentFS governance.