Skip to main content

Crate agentplane

Crate agentplane 

Source
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 Effect performed 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.      │
└──────────────────────────────────────────────────────┘

Three layers enforce it, because convention is not enforcement:

  1. Lint gating — clippy.toml denies SystemTime::now, rand::random, Ulid::new and friends crate-wide.
  2. Effect-key verification — on replay, a recomputed key that differs from the journaled one quarantines the run rather than diverging silently (core::StepError::NonDeterminism).
  3. Storage constraints — the journal’s unique index makes “an effect is started at most once per run” a database invariant, not a code path.

§Example

use agentplane::core::{Outcome, Skill, SkillDescriptor, Tainted};
use agentplane::journal::JournalStore;
use agentplane::runtime::{Mode, 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();
let outcome = runtime.run("greet", Tainted::trusted(serde_json::json!({"name": "world"}))).await?;

// 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::AgentRef;
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;

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.
core
Domain-agnostic types and traits. No I/O lives here.
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.
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.
peers
Calling other agents.
plan
The plan contract.
policy
Authorization engines.
prelude
The names every program needs, so the first one is one use line.
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.
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.