Skip to content

Commit 03c0882

Browse files
authored
chore(release): v4.0.0 — filesystem-first agents (#74)
1 parent 6e33653 commit 03c0882

31 files changed

Lines changed: 1245 additions & 649 deletions

CHANGELOG.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,64 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [4.0.0] - 2026-06-21
9+
10+
Milestone release: **filesystem-first agents** ("eve parity"). A single directory
11+
now defines a durable agent by convention — `instructions.md` (role slot),
12+
`agent.acl` (config), `skills/`, `schedules/` (cron), and `tools/` — served by a
13+
`serve` daemon that runs each schedule as a full harness turn. No breaking changes
14+
to existing APIs; the new surface is additive and gated behind the `serve` feature.
15+
16+
### Added
17+
18+
- **Filesystem-first agent directories (`AgentDir`) + the `serve` daemon.** A
19+
directory with a required `instructions.md` (injected as a prompt *slot*, so the
20+
harness keeps `BOUNDARIES`/response-format/verification authoritative) plus
21+
optional `agent.acl`, `skills/`, `schedules/`, and `tools/` loads via
22+
`AgentDir::load` into existing config objects — no new runtime, no new prompt
23+
system. `serve_agent_dir` runs each enabled cron schedule on its own durable
24+
`schedule:<name>` session; every fire is a FULL `AgentSession::send` turn
25+
(context, tool visibility, safety gate, verification), never a raw model call.
26+
Cron accepts 5- and 6-field expressions (UTC). Exposed in the Node and Python
27+
SDKs (`serveAgentDir` / `serve_agent_dir`) returning a `ServeHandle`. Gated
28+
behind the `serve` Cargo feature.
29+
- **`tools/` declarative tools — `kind: mcp`.** A `tools/<name>.md` with
30+
`kind: mcp` registers an MCP server into each schedule session through the
31+
normal `add_mcp_server` path (namespaced `mcp__<server>__<tool>`, gated by the
32+
session permission policy). Duplicate names and unknown kinds fail closed at load.
33+
- **Rehydrate-on-boot for the serve daemon.** When a `SessionStore` is configured
34+
(e.g. via `SessionOptions::with_file_session_store`), `serve_agent_dir` now
35+
*resumes* any schedule whose `schedule:<name>` session already exists in the
36+
store instead of starting it fresh, so a daemon restart keeps the accumulated
37+
conversation context. Resume restores history only — the current
38+
`instructions.md` / `skills/` / `tools/` are re-applied each boot, so editing
39+
the agent dir still takes effect. With no store configured, every boot starts
40+
fresh (unchanged). Reuses the existing `Agent::resume_session` path; no new
41+
persistence machinery.
42+
- **Sandboxed `script` tools for filesystem-first agents (`tools/ kind: script`).**
43+
A `tools/<name>.md` with `kind: script` now becomes a model-visible tool backed
44+
by the existing sandboxed QuickJS `program` path — no new sandbox. The spec pins
45+
the workspace-relative `.js`/`.mjs` `path`, the `allowed_tools` allow-list, and
46+
the `limits` (timeout / tool-calls / output); the model supplies only `inputs`.
47+
- New `AgentDirScriptTool` registers through the same non-shadowing
48+
`register_dynamic_tool` path as builtins/MCP, so a `tools/` entry can add a
49+
name but never replace a builtin. The model's call to the script tool is
50+
permission-gated like any tool; the script's *inner* `ctx.tool` calls are
51+
bounded by the pinned `allowed_tools` list + the QuickJS sandbox (no
52+
fs/net/proc/env), but are NOT re-checked against the session permission policy.
53+
The complement to `kind: mcp` (both now ship).
54+
- The `allowed_tools` list is the security boundary for a directory script, so
55+
the loader **fails it closed**: an omitted list grants NO tools (not all of
56+
them); list only the minimum, and avoid high-authority tools unless the
57+
directory is fully trusted.
58+
- Fails closed at load (not at first call): a non-`.js`/`.mjs` `path`, a path
59+
that escapes the workspace (absolute / `..`), an out-of-range sandbox limit
60+
(zero, or an effectively-unbounded `timeoutMs`), an unknown `kind`, or a
61+
duplicate tool name is a directory-load error. A `tools/` file is semi-trusted,
62+
so limits are bounded (≤10 min / ≤1000 calls / ≤16 MiB).
63+
- The serve daemon installs the agent dir's `tools/` into every schedule
64+
session, so scheduled turns can call them.
65+
866
## [3.6.2] - 2026-06-14
967

1068
Release-engineering fix for 3.6.0/3.6.1 (no library code changes). Both prior

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "a3s-code-core"
3-
version = "3.6.2"
3+
version = "4.0.0"
44
edition = "2021"
55
authors = ["A3S Lab Team"]
66
license = "MIT"
@@ -139,8 +139,8 @@ s3 = [
139139
"dep:aws-smithy-types",
140140
"dep:aws-smithy-runtime-api",
141141
]
142-
# Enable the durable serve layer: cron schedules + (later) channels + serve daemon
143-
# for filesystem-first agents. Library-only embedders pay nothing without it.
142+
# Enable the durable serve layer: cron schedules + serve daemon for
143+
# filesystem-first agents. Library-only embedders pay nothing without it.
144144
serve = ["dep:cron"]
145145

146146
[dev-dependencies]

core/src/agent_api.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,13 @@ impl Agent {
414414
///
415415
/// The `options` must include a `session_store` (or `with_file_session_store`)
416416
/// that contains the saved session.
417+
///
418+
/// The resumed session uses the **workspace stored in the snapshot**, not a
419+
/// workspace from `options`. The store is therefore a trust boundary: its
420+
/// contents drive the resumed workspace and the persisted runtime policies.
421+
///
422+
/// Runtime: this loads the snapshot via `block_in_place`, so it must be called
423+
/// on a multi-threaded Tokio runtime (it panics on a current-thread runtime).
417424
pub fn resume_session(
418425
&self,
419426
session_id: &str,
@@ -1311,6 +1318,15 @@ impl AgentSession {
13111318
.await
13121319
}
13131320

1321+
/// The session's tool executor, for installing agent-dir `tools/` entries
1322+
/// (e.g. a `kind = "script"` tool) into the live registry. Internal seam used
1323+
/// by [`serve::install_agent_dir_tools`](crate::serve::install_agent_dir_tools)
1324+
/// (the only caller, hence the `serve` gate).
1325+
#[cfg(feature = "serve")]
1326+
pub(crate) fn tool_executor(&self) -> &Arc<crate::tools::ToolExecutor> {
1327+
&self.tool_executor
1328+
}
1329+
13141330
/// Remove an MCP server from this session.
13151331
///
13161332
/// Disconnects the server and unregisters all its tools from the executor.

0 commit comments

Comments
 (0)