ActiveGraph-Inspired Runtime
yoagent-state is inspired by Yohei Nakajima’s ActiveGraph work, adapted into an idiomatic Rust runtime for yoagent and yoyo evolve.
The full concept is:
append-only event log
-> deterministic replay
-> typed graph projection
-> pattern subscriptions
-> behaviors
-> policy-gated patches
-> replay, fork, and diff
flowchart LR
log["append-only event log"]
replay["deterministic replay"]
graphNode["typed graph projection"]
patterns["pattern subscriptions"]
behaviors["behaviors"]
policies["policy gates"]
forks["replay / fork / diff"]
log --> replay --> graphNode --> patterns --> behaviors
graphNode --> policies
graphNode --> forks
behaviors --> log
policies --> log
What changed in v0.2
The core lineage path now starts from goals:
goal -> task -> run -> observation -> failure -> hypothesis -> patch -> artifact -> eval -> decision -> promotion
flowchart LR
goal["goal"]
task["task"]
run["run"]
observation["observation"]
failure["failure"]
hypothesis["hypothesis"]
patch["patch"]
artifact["artifact"]
eval["eval"]
decision["decision"]
promoted["promoted status"]
task -- serves --> goal
run -- produces --> observation
observation -- observes --> failure
hypothesis -- explains --> failure
patch -- addresses --> failure
patch -- advances --> goal
patch -- references --> artifact
patch -- validated_by --> eval
patch -- approved_by --> decision
decision -- allows --> promoted
This is the common graph spine. It is not a claim that every agent run must create every node. artifact includes diffs, logs, screenshots, files, eval output, and other external evidence. promotion is represented by the patch lifecycle status.
yoagent-state now has first-class IDs and helpers for:
- goals
- tasks
- runs
- observations
- hypotheses
- evals
- decisions
- project snapshots
- model calls
- tool calls
- frames
- forks
- behaviors
- policies
- packs
- views
Runtime layers
YoAgentState remains the simple state API: record events, apply ops, query graph, query lineage.
YoAgentRuntime adds the ActiveGraph-inspired runtime layer:
- register typed packs
- validate typed nodes and relations
- register behavior subscriptions
- enforce policy gates
- create approval requests
This keeps simple usage simple while allowing richer agent systems to use the full concept.
Extensible storage
The event log remains the source of truth.
Storage is split into traits:
EventStoreSnapshotStoreForkStoreIndexStoreArtifactStore
JSONL is implemented first because it is inspectable. SQLite, PostgreSQL, and graph-backed projections can be added later behind the same traits.
Behaviors
Behaviors subscribe to event patterns and return state ops.
They do not mutate the graph directly.
event -> matching behavior -> new events/state ops -> replayable state
flowchart LR
event["failure.observed"]
behavior["matching behavior"]
task["create investigation task"]
ops["state.ops_applied event"]
graphNode["replayed graph"]
event --> behavior --> task --> ops --> graphNode
This keeps behavior execution auditable.
Policies
Policies can allow, deny, or require approval for sensitive actions.
The current policy foundation supports approval requests for runtime operations. More policy surfaces can be added without changing the event-sourced model.
flowchart TB
action["runtime action"]
policy["policy check"]
allow["allow"]
deny["deny"]
approval["approval request node"]
action --> policy
policy --> allow
policy --> deny
policy --> approval
Replay, fork, diff
Replay rebuilds graph state from events.
Fork creates an alternate event history from a parent event cutoff.
Diff compares projected graphs so agents can inspect what changed between histories.
flowchart LR
events["events"]
cutoff["event cutoff"]
fork["fork graph"]
current["current graph"]
diff["graph diff"]
events --> cutoff --> fork
events --> current
fork --> diff
current --> diff