Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
058a57f
feat(agent): integrate tool plugins and effects
fffonion Oct 18, 2026
fb610b1
fix(plugins): backtrack resolver choices within fixed work limits
fffonion Oct 18, 2026
d83dbaf
test(auth): fence TLS fixture admission on native pump teardown
fffonion Oct 18, 2026
5f3f72f
fix(gateway): synchronize persistence gate predicates
fffonion Oct 18, 2026
ad9e470
feat(effects): complete managed synchronous publication and recovery
fffonion Oct 18, 2026
e699c73
fix(effects): honor directory durability and invocation/startup budgets
fffonion Oct 18, 2026
3f66a5b
test: make managed workspace Native fixtures explicitly private
fffonion Oct 19, 2026
9b9812d
docs: document managed workspace configuration
fffonion Oct 19, 2026
ac947e3
test: derive managed gateway scratch env from assigned root
fffonion Oct 19, 2026
fce6111
Enforce captured managed authority at Native boundaries
fffonion Oct 19, 2026
d702239
test: pin the published SQLite SDK and cover legal triggers
fffonion Oct 19, 2026
007da8b
fix: validate managed documents without an identity map_err
fffonion Oct 19, 2026
ec81c25
test: compile lease_existing_for_test only with its caller
fffonion Oct 19, 2026
2f2a14e
test: expect the reviewed SDK pin b5066dd92fcd7c07df57e3ec2c29dbcf8c1…
fffonion Oct 19, 2026
49679c4
docs: align deployment guide with the reviewed SDK pin
fffonion Oct 19, 2026
3938fe5
fix: refuse provider calls cancelled after the request commit
fffonion Oct 19, 2026
0a8db1c
feat(effects): publish reviewed graph and managed workspace slices
fffonion Nov 2, 2026
c926734
feat(plugins): add reviewed versioned state lifecycle
fffonion Nov 2, 2026
3aabb9b
feat(plugins): link pure tool libraries with fresh effect authorization
fffonion Nov 3, 2026
8d3f30e
docs(config): document host plugin control environment
fffonion Nov 3, 2026
41f0ba6
fix(gateway): retain sealed replay proofs across storage outages
fffonion Nov 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ hyper = { version = "1", features = ["client", "http1"] }
hyper-util = { version = "0.1", features = ["client-legacy", "http1", "tokio"] }
parking_lot = "0.12"
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
rustscript-vm = { package = "pd-vm", git = "https://github.com/rustscript-lang/rustscript.git", rev = "d9387f98df78dd88d2d1c04eebac4415f844efaf", default-features = false, features = ["runtime", "http-client", "sqlite"] }
pd-host-function = { git = "https://github.com/rustscript-lang/rustscript.git", rev = "d9387f98df78dd88d2d1c04eebac4415f844efaf" }
rustscript-vm = { package = "pd-vm", git = "https://github.com/rustscript-lang/rustscript.git", rev = "b5066dd92fcd7c07df57e3ec2c29dbcf8c19c390", default-features = false, features = ["runtime", "http-client", "sqlite"] }
pd-host-function = { git = "https://github.com/rustscript-lang/rustscript.git", rev = "b5066dd92fcd7c07df57e3ec2c29dbcf8c19c390" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
semver = "1.0.28"
yaml-rust2 = { version = "0.12", default-features = false }
# Meta-schema validation only; resolver features stay disabled.
jsonschema = { version = "0.52.1", default-features = false }
Expand All @@ -51,6 +52,8 @@ tracing-core = "0.1"
[features]
default = []
config-fixture = []
# Test-only one-shot simulated I/O faults. Unarmed production builds do not include it.
workspace-io-fault = []

# Optimize the embedded compiler while retaining development checks.
[profile.dev.package.pd-vm]
Expand Down
64 changes: 64 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,60 @@ the library's `state.db` path, but the gateway's SQLite selection remains
separate: `RUSTSCRIPT_AGENT_STATE_DB` chooses the gateway state file and an
unset value keeps gateway state in memory.

### Managed workspace (primary-only)

`RUSTSCRIPT_AGENT_MANAGED_WORKSPACE` is an OS filesystem path, read only by
`rustscript-agent-gateway` and passed to `ManagedWorkspaceConfig::for_workspace`.
It has **no deprecated alias** and is not a boolean flag. Unset means
`managed_workspace = None` (direct mode). When set, it must name an existing,
non-root directory using a non-empty absolute UTF-8 path with no NUL or
parent-directory components; invalid configuration fails startup.

Managed mode requires `RUSTSCRIPT_AGENT_STATE_DB` to name an **absolute,
persistent database**; in-memory state is rejected. The runtime derives its
private object root as `<database-parent>/.<database-filename>.effects`.
The source must not overlap the database, that object root, or the sibling
`.<database-filename>.tool-packages` directory in either direction.

The setting alone grants no workspace authority. Import and queries require a
current Native workspace grant admitting the configured source through
`workspaces.allowed_roots`. For the gateway binary, explicitly set
`RUSTSCRIPT_AGENT_HOME` to enable the workspace host, with loadable config/auth
files in a private, process-owned agent home (Unix mode `0700`). A managed run's
admitted canonical workspace must match the configured source. Embeddings
supply this authority through `with_workspace_home` or their trusted workspace
host factory.

The source is imported as a seed; managed filesystem mutations use private
working trees without writing changes back to the source. This mechanism
covers managed synchronous local filesystem effects, not OS permission
isolation or rollback of external effects. Tree quotas and retained-object
limits are described with the native field below.

### Host plugin control (primary-only)

The gateway reads these four primary-only variables directly; they have no
`PD_EDGE_AGENT_*` aliases. They configure the host plugin-control binding,
not ordinary run-token authority.

- `RUSTSCRIPT_AGENT_PLUGIN_SOURCE_ROOT`: filesystem path for the controlled
plugin source root passed to the host binding. Default: unset. If it is
unset, this binding is skipped and the other three settings below are not
read by that binding.
- `RUSTSCRIPT_AGENT_PLUGIN_DEPLOYMENT_SPACE`: deployment-space string passed
to the host plugin control. There is no default; it is required when the
source root is set. A missing or non-UTF-8 value fails startup.
- `RUSTSCRIPT_AGENT_PLUGIN_PUBLISHER_DIR`: optional directory of accepted
publisher verification keys. Default: unset, so no keys are loaded from a
directory. Each entry's filename is the publisher ID and its file contents
must be a raw 32-byte verification key, not a hexadecimal or PEM encoding.
An unavailable directory, unreadable entry, invalid filename, or wrong key
length fails startup. No filename extension is stripped.
- `RUSTSCRIPT_AGENT_PLUGIN_UNSIGNED_DEV`: optional filesystem path forwarded
as `InstallAuthorization::unsigned_dev_space`. Default: unset (`None`).
This is a development-space path, not a boolean flag; setting it does not
bypass the install, trust, or effect-policy checks.

### Gateway variables and deprecated aliases

Every gateway `RUSTSCRIPT_AGENT_*` variable in the table has a deprecated
Expand Down Expand Up @@ -184,6 +238,16 @@ above; every other field is set by embedding code.
| `sqlite` | `SqlitePolicy` | core defaults, `max_statements = 1024` | — |
| `approvals` | `ApprovalSettings` | `read = "allow"`, `write = "ask"`, `process = "ask"`; reviewer/model/fallback/required overrides unset (`None`) | Validated by `ApprovalSettings::validate`: `reviewer` must be `guardian` or `user` when set; `reviewer_model` must be non-empty, at most 128 characters, with no control characters or surrounding whitespace; `read = "ask"` is unsupported. |
| `fuel` | `Option<u64>` | `Some(10_000_000)` | VM fuel budget; `None` disables the fuel cap. |
| `managed_workspace` | `Option<ManagedWorkspaceConfig>` | `None` (direct mode) | Trusted native startup opt-in for persistent synchronous managed effects. `ManagedWorkspaceConfig::for_workspace(source_root)` supplies default quotas and validates the source; `AgentGatewayConfig::validate` revalidates it. Gateway construction requires an absolute persistent database, and the runtime rejects a root source or overlap with persistent state. Import and queries still require current Native workspace authority; see the primary-only environment setting above. |

`ManagedWorkspaceConfig` contains `source_root: PathBuf`, `quota: ResourceQuota`,
and `retention: ManagedRetentionLimits`. `for_workspace` defaults to at most
1 000 000 tree entries, 64 MiB per tree, and depth 32. Native embeddings may
choose smaller positive bounds through `ResourceQuota::new`; these defaults
are also its hard ceilings. Retention defaults to 128 objects and 512 MiB;
both bounds must be positive and cannot exceed those ceilings. Retained
evidence is not evicted to admit a call. These are native configuration
fields, not additional environment variables or `config.yaml` settings.

`RateLimitConfig` bounds: `enabled` (master switch), `ip_burst`, `account_burst`,
`window`, `max_buckets`. `TelegramConfig` bounds: `bot_token` (redacted in
Expand Down
6 changes: 3 additions & 3 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ treated as available.
## 1. Delivery constraint: the core dependency is not released

`rustscript-agent` depends on the RustScript VM through a **pinned Git
dependency**: `rustscript-vm = { package = "pd-vm", git = "https://github.com/rustscript-lang/rustscript.git", rev = "d9387f98df78dd88d2d1c04eebac4415f844efaf", ... }` in `Cargo.toml`.
dependency**: `rustscript-vm = { package = "pd-vm", git = "https://github.com/rustscript-lang/rustscript.git", rev = "b5066dd92fcd7c07df57e3ec2c29dbcf8c19c390", ... }` in `Cargo.toml`.
Consequences, stated plainly:

- A build fetches the exact pinned core revision from the canonical HTTPS
Expand All @@ -18,7 +18,7 @@ Consequences, stated plainly:
- `cargo build/test --locked` resolves the core source from `Cargo.lock`,
which records the canonical git source for both `pd-vm` and
`pd-host-function`:
`git+https://github.com/rustscript-lang/rustscript.git?rev=d9387f98df78dd88d2d1c04eebac4415f844efaf#d9387f98df78dd88d2d1c04eebac4415f844efaf`.
`git+https://github.com/rustscript-lang/rustscript.git?rev=b5066dd92fcd7c07df57e3ec2c29dbcf8c19c390#b5066dd92fcd7c07df57e3ec2c29dbcf8c19c390`.
A build therefore needs network access to github.com (or a pre-warmed
Cargo git cache); it never reads the state of a local core checkout.
- **There is no crates.io release of this crate, and none can be made until
Expand Down Expand Up @@ -46,7 +46,7 @@ before deploying:
```bash
# The lockfile records the exact git source for pd-vm and pd-host-function:
grep -A3 'name = "pd-vm"' Cargo.lock
# source = "git+https://github.com/rustscript-lang/rustscript.git?rev=d9387f9…#d9387f9…"
# source = "git+https://github.com/rustscript-lang/rustscript.git?rev=b5066dd…#b5066dd…"
# The resolved dependency graph shows the same source:
cargo tree --locked -p rustscript-vm
```
Expand Down
33 changes: 33 additions & 0 deletions examples/plugin_schema_sync.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! Regenerate or check canonical JSON projections of the public YAML schemas.
//!
//! The YAML files are the contract. This tool does not invent a second schema
//! and does not fetch anything. `--check` fails if `schemas/canonical` drifted.

fn main() {
let command = std::env::args()
.nth(1)
.unwrap_or_else(|| "--check".to_string());
let dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("schemas/canonical");
match command.as_str() {
"--check" => match rustscript_agent::plugins::schema_snapshot_drift(&dir) {
Ok(()) => println!("schema snapshots match {}", dir.display()),
Err(err) => {
eprintln!("{err}");
std::process::exit(1);
}
},
"--write" => {
let docs =
rustscript_agent::plugins::canonical_schema_documents().expect("bundled schemas");
std::fs::create_dir_all(&dir).expect("canonical dir");
for (name, json) in docs {
std::fs::write(dir.join(name), json).expect(name);
}
println!("wrote {}", dir.display());
}
_ => {
eprintln!("usage: plugin_schema_sync --check|--write");
std::process::exit(2);
}
}
}
Loading