From b681a538a846da561d31db4672a9415878e0689a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 21 Jun 2026 01:39:34 +0800 Subject: [PATCH] docs: document filesystem-first agents + neutralize product-name wording - README: new "Filesystem-First Agents" section (agent-dir convention, serve daemon, tools mcp/script, rehydrate-on-boot) + docs link. - Node + Python SDK READMEs: add a Filesystem-First Agents section (serveAgentDir / serve_agent_dir). - Neutralize internal product-name references to role-based wording in agent_dir.rs, AGENT_DIR_TOOLS_DESIGN.md, and CHANGELOG; rename the integration test to test_agent_dir_convention.rs. --- CHANGELOG.md | 2 +- README.md | 54 +++++++++++++++++++ core/src/config/agent_dir.rs | 8 +-- ...ir_eve.rs => test_agent_dir_convention.rs} | 2 +- manual/AGENT_DIR_TOOLS_DESIGN.md | 4 +- sdk/node/README.md | 19 +++++++ sdk/python/README.md | 20 +++++++ 7 files changed, 101 insertions(+), 8 deletions(-) rename core/tests/{test_agent_dir_eve.rs => test_agent_dir_convention.rs} (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index eab8ccb..e814107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [4.0.0] - 2026-06-21 -Milestone release: **filesystem-first agents** ("eve parity"). A single directory +Milestone release: **filesystem-first agents**. A single directory now defines a durable agent by convention — `instructions.md` (role slot), `agent.acl` (config), `skills/`, `schedules/` (cron), and `tools/` — served by a `serve` daemon that runs each schedule as a full harness turn. No breaking changes diff --git a/README.md b/README.md index 32f7eed..79acb4c 100644 --- a/README.md +++ b/README.md @@ -1593,6 +1593,59 @@ await session.addMcp({ --- +## Filesystem-First Agents + +A durable agent can be defined entirely by a **directory** — no code — and run by +the built-in `serve` daemon. One folder holds the agent's role, config, skills, +cron schedules, and tools: + +```text +my-agent/ +├── instructions.md (required) Role/guidelines — injected as a prompt SLOT. +├── agent.acl (optional) Model, providers, queue. +├── skills/ (optional) *.md skills. +├── schedules/ (optional) *.md cron jobs (frontmatter `cron:` + body prompt). +└── tools/ (optional) *.md tools: `kind: mcp` (MCP server) or + `kind: script` (sandboxed QuickJS over `program`). +``` + +`AgentDir::load` synthesizes the existing config objects from that folder — it adds +no new runtime or prompt system. `serve_agent_dir` then runs each enabled schedule +on its own durable session, and every fire is a FULL harness turn (context, tool +visibility, safety gate, verification), never a raw model call. `instructions.md` +is a prompt *slot*, so the harness keeps `BOUNDARIES`, the response contract, and +verification authoritative. + +```rust +use a3s_code_core::{Agent, config::AgentDir, serve::serve_agent_dir}; +use tokio_util::sync::CancellationToken; + +let agent_dir = AgentDir::load("./my-agent")?; +let agent = Agent::from_config(agent_dir.config.clone()).await?; +serve_agent_dir(&agent, &agent_dir, "./workspace", None, CancellationToken::new()).await?; +``` + +From the SDKs: + +```js +const handle = await agent.serveAgentDir('./my-agent', './workspace') +// ... runs in the background until: +await handle.stop() +``` + +- **`tools/`** — `kind: mcp` registers an MCP server (namespaced + `mcp____`); `kind: script` exposes a sandboxed QuickJS tool over the + `program` path, with a fail-closed `allowed_tools` allow-list (an omitted list + grants no tools). +- **Rehydrate-on-boot** — pass a `SessionStore` and each schedule session resumes + its accumulated context across daemon restarts (history is restored; the current + `instructions.md` / `skills/` / `tools/` are re-applied each boot). +- Gated behind the `serve` Cargo feature; library-only embedders pay nothing. + +See [Filesystem-First Agents](https://a3s-lab.github.io/a3s/docs/code/agent-dir) for the full guide. + +--- + ## Slash Commands Sessions support slash commands: @@ -1683,6 +1736,7 @@ Full reference and guides: [a3s-lab.github.io/a3s/docs/code](https://a3s-lab.git - [Tools & Structured Output](https://a3s-lab.github.io/a3s/docs/code/tools) - [AHP Protocol](https://a3s-lab.github.io/a3s/docs/code/ahp-integration) - [Skills](https://a3s-lab.github.io/a3s/docs/code/skills) +- [Filesystem-First Agents](https://a3s-lab.github.io/a3s/docs/code/agent-dir) - [Memory](https://a3s-lab.github.io/a3s/docs/code/memory) - [Security](https://a3s-lab.github.io/a3s/docs/code/security) - [Hooks](https://a3s-lab.github.io/a3s/docs/code/hooks) diff --git a/core/src/config/agent_dir.rs b/core/src/config/agent_dir.rs index 9e2af15..e98f541 100644 --- a/core/src/config/agent_dir.rs +++ b/core/src/config/agent_dir.rs @@ -1,4 +1,4 @@ -//! Filesystem-first agent directory convention (eve-style, harness-respecting). +//! Filesystem-first agent directory convention (harness-respecting). //! //! A single directory defines a durable agent by convention: //! @@ -19,7 +19,7 @@ //! [`AgentDir::load`] SYNTHESIZES existing config objects rather than adding a new //! runtime: `instructions.md` → [`SystemPromptSlots`], `agent.acl` → [`CodeConfig`], //! `skills/` → `skill_dirs`. Tool definition, visibility, and safety stay -//! harness-owned (the deliberate divergence from eve's user-defined-tools model). +//! harness-owned (the deliberate divergence from user-defined-tools models). use std::path::{Path, PathBuf}; @@ -44,7 +44,7 @@ pub struct ScheduleSpec { /// A tool definition parsed from `tools/.md`, dispatched by `kind`. /// /// Tool *definition* may come from the directory, but visibility and safety stay -/// harness-owned (the deliberate divergence from eve): an `mcp` spec is registered +/// harness-owned (a deliberate divergence from user-defined-tools models): an `mcp` spec is registered /// through the normal [`add_mcp_server`](crate::AgentSession) path, so its tools /// are namespaced `mcp____` and gated by the session's permission /// policy like any other tool. @@ -121,7 +121,7 @@ pub struct ScriptToolLimits { /// /// Distinct from [`CodeConfig::agent_dirs`](crate::config::CodeConfig) / /// `register_agent_dir`, which scan a directory for **worker/subagent** -/// definitions. An `AgentDir` is the eve-style *primary* agent — the directory +/// definitions. An `AgentDir` is the filesystem-first *primary* agent — the directory /// that defines this agent's prompt, skills, schedules, and tools. #[derive(Debug, Clone)] pub struct AgentDir { diff --git a/core/tests/test_agent_dir_eve.rs b/core/tests/test_agent_dir_convention.rs similarity index 98% rename from core/tests/test_agent_dir_eve.rs rename to core/tests/test_agent_dir_convention.rs index e6a3d81..ef2b10f 100644 --- a/core/tests/test_agent_dir_eve.rs +++ b/core/tests/test_agent_dir_convention.rs @@ -1,4 +1,4 @@ -//! End-to-end integration test for the eve-style filesystem-first agent directory +//! End-to-end integration test for the filesystem-first agent directory //! convention: a single on-disk directory with EVERY supported sub-convention //! (instructions, agent.acl, skills/, schedules/, tools/) loads into a //! fully-populated [`AgentDir`]. Hermetic — no provider, no network. diff --git a/manual/AGENT_DIR_TOOLS_DESIGN.md b/manual/AGENT_DIR_TOOLS_DESIGN.md index 57ea414..6d33407 100644 --- a/manual/AGENT_DIR_TOOLS_DESIGN.md +++ b/manual/AGENT_DIR_TOOLS_DESIGN.md @@ -6,7 +6,7 @@ The loader (`load_tools` in `core/src/config/agent_dir.rs`) parses both into session build — MCP via `add_mcp_server`, script via the new `AgentDirScriptTool` (`core/src/tools/agent_dir_script_tool.rs`), a thin facade over the existing `program` QuickJS path. Scope: how the optional `tools/` -subdirectory of an eve-style agent directory becomes *executable* tools in +subdirectory of a filesystem-first agent directory becomes *executable* tools in A3S Code without ever running arbitrary host JavaScript or arbitrary host processes. @@ -15,7 +15,7 @@ processes. > NEVER turned into a free-running host JS/native process, and it NEVER gets to > define its own tool-visibility or safety policy. Tool *definition* is allowed > from the directory; tool *visibility* and *safety* remain harness-owned. This -> is the deliberate divergence from eve's user-defined-tools model, documented in +> is the deliberate divergence from user-defined-tools models, documented in > the `core/src/config/agent_dir.rs` module header, and is why the directory > selects between two harness-owned backends rather than running arbitrary code. diff --git a/sdk/node/README.md b/sdk/node/README.md index d8a605a..b846dd5 100644 --- a/sdk/node/README.md +++ b/sdk/node/README.md @@ -320,6 +320,25 @@ console.log(await session.mcps()) The positional `addMcpServer(...)` overload and longer `addMcpServerConfig(...)` alias remain for compatibility. +## Filesystem-First Agents + +Define a durable agent as a **directory** — `instructions.md` (required) plus +optional `agent.acl`, `skills/`, `schedules/` (cron), and `tools/` (`kind: mcp` or +`kind: script` sandboxed QuickJS) — and serve its schedules. Each fire is a full +harness turn (context, tool visibility, safety gate, verification). Returns a +handle you must keep and stop explicitly. + +```js +const handle = await agent.serveAgentDir('./my-agent', './workspace', { + // Optional: pass a sessionStore so each schedule resumes its accumulated + // context across daemon restarts. + sessionStore: new FileSessionStore('./sessions'), +}) +// ... runs in the background until: +await handle.stop() +console.log(handle.isStopped()) // true +``` + ## HITL Confirmations Use `permissionPolicy` to decide which tools ask, then `confirmationPolicy` to diff --git a/sdk/python/README.md b/sdk/python/README.md index 86d3470..87d4069 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -311,6 +311,26 @@ or `session.tool("task", {...})` when you need raw access. The old standalone lifecycle control-plane API is intentionally removed from the 2.0 SDK surface. +## Filesystem-First Agents + +Define a durable agent as a **directory** — `instructions.md` (required) plus +optional `agent.acl`, `skills/`, `schedules/` (cron), and `tools/` (`kind: mcp` or +`kind: script` sandboxed QuickJS) — and serve its schedules. Each fire is a full +harness turn (context, tool visibility, safety gate, verification). Returns a +handle you keep and stop explicitly. + +```python +opts = SessionOptions() +# Optional: pass a session_store so each schedule resumes its accumulated +# context across daemon restarts. +opts.session_store = FileSessionStore("./sessions") + +handle = agent.serve_agent_dir("./my-agent", "./workspace", opts) +# ... runs in the background until: +handle.stop() +print(handle.is_stopped()) # True +``` + ## License MIT