> **Independent project:** Cageforge is not affiliated with, sponsored by, or endorsed by OpenAI.
This crate is a supporting component of the [`cageforge`](https://crates.io/crates/cageforge) crate, a cross-platform Rust sandbox for AI agents and untrusted code.
# cageforge-backend-api
Read the shared [configuration guide](https://github.com/m62624/cageforge/blob/main/crates/cageforge-config/examples/CONFIGURATION_GUIDE.md) for TOML profiles, symbolic paths, local IPC, and first-launch resource rules.
`cageforge-backend-api` is the contract layer between Cageforge's portable
execution values and a native Linux, macOS, or Windows backend. It defines the
typed handoff from a composed command and sandbox policy to the operating-
system integration that will enforce and launch them.
The crate turns a backend's declared enforcement capabilities into a common
preflight contract. `BackendRequest::prepare_for` accepts a request built from
`CommandRequest` and `EffectiveSandbox`, verifies every required capability,
and returns a prepared request or a typed error that identifies the failed
requirement.
## The handoff model
`Sandbox` and `SandboxChild` define shared preparation, launch, streams, and
child lifecycle operations. Each native crate implements these traits
directly; applications can use them through this crate or through the
`cageforge` crate. The concrete child and error types remain available.
`DynSandbox` supports a runtime-selected implementation behind
`Box<dyn DynSandbox>` or a shared `Arc<dyn DynSandbox>`. Its `launch` method
prepares and spawns on the same backend instance. It returns an owned child
with the common `SandboxChild` interface. `SandboxExecutionError` preserves
the failing operation and original native error; child destruction follows
the same native cleanup path as a concrete child.
```text
CommandRequest + EffectiveSandbox
│
▼
cageforge-backend-api
capabilities + preflight
│
▼
native backend lowering/launch
```
`BackendRequest` accepts `CommandRequest` and `EffectiveSandbox`, so policy
composition and the `PolicyCeiling` intersection are completed before the
backend handoff. The command's `EnvironmentSpec` is checked against the
requested environment retained by the composed result, keeping command and
policy construction aligned.
Call `request.prepare_for(&backend, &base_context)` to run the common
capability and working-directory checks. `base_context` must include the
runtime current directory: it is checked even when the command does not set an
explicit cwd, so a child cannot silently inherit an unchecked directory from
the launching process. The backend trait only supplies its capabilities; it
cannot override this preflight with a broader set. The base context is
narrowed to the effective workspace ceiling, and an effective working
directory is rejected when the filesystem policy denies it. After preparation,
use `PreparedBackendRequest::command_spec` for the executable and argv values,
`PreparedBackendRequest::working_directory` for the resolved cwd,
`PreparedBackendRequest::path_context` to inspect the already narrowed
context, and `PreparedBackendRequest::apply_environment` with a
backend-selected `EnvironmentInput`. The filesystem decision helpers use that
same bound context and cannot be given a context from another request. A
symbolic selector is never evaluated without it. Use `filesystem_lowering` and
`network_lowering` to obtain every immutable constraint layer needed by native
lowering. Every returned layer is mandatory: the backend must enforce their
conjunction and must not lower only the requested or only the ceiling side.
Use `authorize_connection` to receive a decision that already combines the
requested and ceiling sides. Every prepared accessor takes `&backend` and
checks that it is the same instance used by `prepare_for`.
The returned `PreparedBackendRequest<'_, B>` is bound to the concrete backend
type `B` whose capabilities were checked. A native lowering method should
accept `PreparedBackendRequest<'_, Self>` so a handoff prepared for one backend
implementation cannot be passed to another backend implementation by accident.
It also carries a runtime `BackendIdentity`; every prepared accessor must be
called with the same backend instance that was passed to `prepare_for`, or it
returns `BackendContractError::BackendIdentityMismatch`. This prevents two
instances of one backend type with different enforcement state from sharing a
prepared handoff. The identity is a caller-managed token, not proof that
operating-system enforcement exists. Prepared accessors also compare the
capability snapshot captured during preflight and return
`BackendContractError::BackendCapabilitiesMismatch` if the backend changes
capabilities afterwards. The backend remains responsible for advertising only
capabilities it can actually enforce.
Capability names describe portable enforcement requirements, not a shared
operating-system mechanism. A Linux backend may advertise conventional
temporary-scope or pathname local-IPC enforcement while a Windows backend may
omit those capabilities and return the same typed unsupported-capability error
before lowering. Native path, object, and process mechanisms stay in each
backend.
Create `BackendIdentity` explicitly with `BackendIdentity::new()`. It has no
`Default` implementation because each new identity represents a distinct
backend boundary; cloning preserves an existing identity.
When a request needs an unsupported capability, preparation returns
`BackendContractError::UnsupportedCapability`. The error is matchable by its
`BackendCapability` variant and its display text names the required
enforcement, for example: `filesystem missing-path behavior (error or skip)`.
Capability checks include implicit requirements: a workspace-relative glob
needs `FilesystemScopes` so it is evaluated against the narrowed workspace
context, and every deny glob needs `FilesystemGlobScanDepth` because an absent
explicit depth means unbounded scanning. Concrete scopes also require the
matching selector capability: absolute, workspace, system-root, minimal,
temporary-directory, or the platform's conventional temporary scope. A
backend that cannot enforce any required behavior is rejected before lowering.
```rust
use cageforge_backend_api::{
BackendCapabilities, BackendRequest, SandboxBackend,
};
struct ExampleBackend {
capabilities: BackendCapabilities,
identity: cageforge_backend_api::BackendIdentity,
}
impl ExampleBackend {
fn new(capabilities: BackendCapabilities) -> Self {
Self {
capabilities,
identity: cageforge_backend_api::BackendIdentity::new(),
}
}
}
impl SandboxBackend for ExampleBackend {
fn identity(&self) -> &cageforge_backend_api::BackendIdentity {
&self.identity
}
fn capabilities(&self) -> BackendCapabilities {
self.capabilities.clone()
}
}
// A real backend constructs its capabilities from the enforcement mechanisms
// it can prove safe, then runs the common preflight before lowering the
// request to native process and filesystem APIs.
```
## Responsibilities
The crate owns:
- `BackendCapability` and `BackendCapabilities`;
- `BackendRequest` and the opaque `PreparedBackendRequest`;
- the synchronous `SandboxBackend` capability contract and common preflight;
- `Sandbox`, `DynSandbox`, and `SandboxChild` execution contracts;
- common unsupported-capability and preparation errors.
The native backend owns:
- translating the effective contract to Landlock, bubblewrap, Seatbelt,
Windows ACL/token, or another OS mechanism;
- symlink, junction, reparse-point, mount, and TOCTOU-safe enforcement;
- DNS resolution and exact `SocketAddr` connection authorization;
- platform-specific core environment selection; and
- process launch, stdio, timeout, cancellation, and lifecycle handling.
`cageforge` provides the ergonomic library API and target-specific backend
selection that connect this contract to a concrete execution flow.
## Workspace role
| `cageforge-command` | Supplies validated command and environment intent. |
| `cageforge-policy-compose` | Supplies the narrowed `EffectiveSandbox`. |
| `cageforge-policy` | Supplies portable policy values and decision types used during lowering. |
| `cageforge-path` | Supplies the shared lexical path semantics used by policy and native integrations. |
| `cageforge-config` | Produces validated TOML-backed command and policy values for the handoff. |
| `cageforge` | Re-exports this contract and exposes the common `Sandbox` launch shape. |
| `cageforge-linux`, `cageforge-macos`, `cageforge-windows` | Implement OS enforcement and process launch after preflight. |
The complete API is documented on
[docs.rs](https://docs.rs/cageforge-backend-api/latest/cageforge_backend_api/).