Expand description
§agentplane
A durable, replayable, policy-governed runtime for agents whose steps invoke non-deterministic models and mutate real systems.
One sentence carries the rest:
The journal is the plan of record. Orchestration is deterministic and replayable; every non-deterministic act — inference, tool call, clock, RNG, deadline resolution — is an
Effectperformed at most once, journaled, and read back on replay.
§The determinism boundary
┌──────────────── DETERMINISTIC ZONE ────────────────┐
│ plan traversal · guards · retry decisions · budget │
│ policy evaluation · label joins · record upcasting │
│ │
│ Replay re-executes this and MUST reproduce the │
│ identical sequence of effect keys. │
└───────────────────────┬─────────────────────────────┘
│ cx.effect(…)
┌───────────────────────▼─────────────────────────────┐
│ NON-DETERMINISTIC ZONE │
│ inference · tools · clock · RNG · network · humans │
│ │
│ Executed at most once. Journaled. Replay reads. │
└──────────────────────────────────────────────────────┘Two layers enforce it, because convention is not enforcement:
- Lint gating —
clippy.tomldeniesSystemTime::now,Instant::now,OffsetDateTime::now_utc,rand::random,rand::rngandUlid::generatecrate-wide. It covers this crate, not a skill compiled in yours. - Effect-key verification — on replay, a recomputed key that differs
from the journaled one quarantines the run rather than diverging silently
(
core::StepError::NonDeterminism).
§Example
use agentplane::core::{Outcome, Skill, SkillDescriptor, Tainted};
use agentplane::journal::JournalStore;
use agentplane::runtime::{Mode, RunStatus, Runtime, StepCtx};
use std::sync::Arc;
#[derive(Debug)]
struct Greet;
#[async_trait::async_trait]
impl Skill for Greet {
fn descriptor(&self) -> SkillDescriptor {
SkillDescriptor::new("greet").provides("demo.greet")
}
async fn invoke(
&self,
cx: &mut StepCtx<'_>,
input: Tainted<serde_json::Value>,
) -> Result<Outcome, agentplane::core::SkillError> {
// `now()` is a journaled effect: on replay it returns the recorded
// instant rather than reading the clock again.
let at = cx.now().await?;
Ok(Outcome::done(input.map(|v| serde_json::json!({
"greeted": v, "at": at.to_string(),
}))))
}
}
// With the default features, `agentplane::store::RedbStore` is one.
let runtime = Runtime::builder(store).skill(Greet).build();
// Runs are asked for by capability — what the skill `provides`.
let outcome = runtime.run("demo.greet", Tainted::trusted(serde_json::json!({"name": "world"}))).await?;
assert!(matches!(outcome.status, RunStatus::Succeeded), "{:?}", outcome.status);
// Replaying re-executes the deterministic zone and reads every effect back
// from the journal. No clock is read; no tool is called twice. `Strict`
// additionally fails if this build wants an effect the journal lacks.
runtime.replay(outcome.run_id, Mode::Strict).await?;Re-exports§
pub use crate::core::Capability;pub use crate::core::CaseId;pub use crate::core::Digest;pub use crate::core::EffectKey;pub use crate::core::Label;pub use crate::core::Outcome;pub use crate::core::Recovery;pub use crate::core::RunId;pub use crate::core::RuntimeError;pub use crate::core::Sensitivity;pub use crate::core::Seq;pub use crate::core::Skill;pub use crate::core::SkillDescriptor;pub use crate::core::SourceId;pub use crate::core::StepId;pub use crate::core::Tainted;pub use crate::core::Trust;pub use crate::journal::JournalStore;pub use crate::journal::Record;pub use crate::journal::RecordKind;pub use crate::runtime::Runtime;pub use crate::runtime::StepCtx;pub use rand;pub use schemars;
Modules§
- api
- An HTTP surface for the people who have to look after a plane.
- audit
- Checking a plane’s history without trusting the plane.
- authority
- Standing authority: a ceiling that outlives a run and is narrower than a tenant.
- batch
- Batch runs — one plan, many items, per-item durability.
- blob
- Content-addressed bytes, kept out of the chain.
- case
- Case storage: correlation, state, obligations, and inbound events.
- content
- Content rules: deterministic predicates a manifest declares over a value’s strings, applied at the boundaries the plane already owns.
- core
- Domain-agnostic types and traits. No I/O lives here.
- disclosure
- A matter leaving the plane: the disclosure act, the register that holds it, and the one function that writes a package only once the act is recorded.
- drill
- The live half of the case-layer drill: the questions no exported file can answer.
- export
- Getting the record out, in a form nothing here has to be present to read.
- grader_
verdict - A grader’s verdict, bound to the records it was reached from.
- grants
- The grants an agent never used, read from an export.
- journal
- The journal: append-only, hash-chained run history.
- keyring
- Envelope encryption, and the erasure it makes provable.
- manifest
- The declaration an agent is built from.
- media
- Governed remote-media ingestion.
- memory
- Memory an agent keeps between runs, and the rules that keep it survivable.
- model
- Calling a model.
- netguard
- What an outbound call may do to this process.
- observe
- Keeping a record beside an agent this plane does not execute.
- peers
- Calling other agents.
- plan
- The plan contract.
- policy
- Authorization engines, the requests the runtime asks them, and the offline re-derivation of those requests from an export.
- prelude
- The names every program needs, so the first one is one
useline. - push
- Push notifications: telling a peer’s webhook that its task moved.
- quota
- Per-tenant ceilings on concurrent work and spend.
- retention
- Time-windowed erasure: the retention verb, and what it honestly cannot do.
- runtime
- Execution: the step context, the effect protocol, and the executor.
- store
- Persistence backends.
- subject
- Where a subject’s data went.
- testkit
- Test facilities for embedders, and for this crate’s own assurance layers.
- tools
- Calling tools on other people’s servers.
Macros§
- manifests
- Embed a directory of single-agent manifests, keyed by declared name.