Asset Core Docs

Deterministic world-state engine documentation and API references.

Decision Gate docs

Transactions and Operations

Transactions are the atomic unit of change in Asset Core. Each transaction contains a sequence of operations that execute together or not at all. This is the core contract that makes Asset Core deterministic and auditable.

Problem this concept solves

Complex state changes often require multiple coordinated updates. Without atomicity, systems drift because partial changes are committed and no longer match the intended state.

  • Creating a container and populating it
  • Transferring assets between locations
  • Adding an instance and placing it

Without atomic transactions, these multi-step changes could fail partway through, leaving the system in an inconsistent state. Asset Core solves this by grouping operations into transactions with all-or-nothing semantics.

Asset Core uses a fixed operation vocabulary because it defines the minimal mathematical surface for state transitions. Every caller—human, service, or agent—uses the same operations; governance determines which ones a caller may invoke. The bounded set makes auditing and tooling tractable without sacrificing expressiveness.

Core ideas

Commit Structure

A commit request contains a list of operations. The envelope is intentionally uniform so it can be validated, replayed, and audited in a consistent way across all domains.

{
  "actor_id": "lab-operator-17",
  "operations": [
    { "op": "CreateContainer", "args": { ... } },
    { "op": "AddFungible", "args": { ... } }
  ],
  "idempotency_key": "optional-unique-key",
  "metadata": { "experiment": "phase-1" }
}

Operations execute in order within the transaction. If any operation fails, the entire commit is rolled back.

Operation Envelope

Each operation has the same envelope structure:

{
  "op": "OperationName",
  "args": { ... }
}
  • op: The operation identifier (e.g., CreateContainer)
  • args: Operation-specific arguments

This uniform structure makes operations easy to compose and process programmatically.

The 24 Operations

Asset Core defines exactly 24 operations across 5 domains. This small, closed vocabulary is what makes automated policy enforcement and auditing tractable.

DomainOperations
ContainerCreateContainer, RemoveContainer
BalanceAddFungible, RemoveFungible, MoveFungible, TransferFungible, TransferMany, Distribute, MoveMany, MergeStacks, ConsolidateStacks
InstanceAddInstance, MoveInstance, RemoveInstance, BurnInstance, Attach, Detach
SlotPlaceInSlot, RemoveFromSlot, SwapSlots
SchemaRegisterClass, RegisterClassShape, RegisterClassContinuousShape1d, RegisterClassContinuousShape2d

Why exactly 24? Because that’s the minimal set that covers the operation space for spatial state systems without losing expressiveness.

Every operation fits into a 4-dimensional taxonomy: domain (what entity type), action (what kind of change), scope (single or multi-entity), and reversibility (can it be undone or is it destructive). This taxonomy isn’t decorative—it’s how you build governance.

This closed vocabulary is also critical for governance. An unbounded API (arbitrary SQL, general-purpose scripting) means callers can perform operations you didn’t anticipate and can’t audit. A fixed operation set means you can:

  • Whitelist by domain: “This agent can only modify balances, not instances”
  • Blacklist destructive ops: “This agent can move but not burn”
  • Audit exhaustively: “Show me every operation this actor performed”

The constraint is a feature. When you need higher-level behavior, you compose operations—combine multiple operations in one transaction. The common multi-operation patterns are documented in Recipes, but the list is not exhaustive. If your domain has behavior outside the model, keep that logic in your application and commit the resulting state changes through operations.

This fixed set provides:

  • Auditability: Every possible state change is known
  • Safety: No arbitrary mutations
  • Consistency: Same operations work across all environments

Tag System

Operations are categorized across four dimensions. This taxonomy isn’t documentation metadata—it’s the foundation for governance.

Why this exists: When you grant a caller permission to manipulate AssetCore state, you need granular control. “Can modify anything” is too broad. Long allowlists are brittle and hard to maintain. The tag system gives you semantic filtering: “can create and move instances, but cannot destroy” or “can only modify balances, not containers.”

The four dimensions:

Domain: What entity type is affected

  • container, balance, instance, slot, schema

Action: What kind of change

  • create, destroy, move, link, consolidate

Scope: How many entities

  • single, multi

Reversibility: Can it be undone

  • reversible, destructive, neutral

How this helps you:

  • Agent permissions: Whitelist by domain + action. “This agent can move instances but cannot burn them” = domain:instance, action:move, reversibility:reversible.

  • Audit queries: “Show me all destructive operations in the last 24 hours” = filter event log by reversibility:destructive.

  • Tooling generation: The operations manifest (JSON file) includes tags. You can generate agent tool definitions programmatically: “Create a tool for every single-scope, reversible operation.”

Example: The MCP tooling catalog uses these tags to group operations into safe tool surfaces. Agents get assetcore_move_instance (reversible, single-scope) but not assetcore_burn_instance (destructive) unless explicitly granted.

Idempotency

The optional idempotency_key enables safe retries. In production, it is a primary reliability control, not a convenience feature.

  • First request with a key executes normally
  • Subsequent requests with the same key return the cached response
  • Prevents duplicate commits from network retries

Always use idempotency keys for production workloads.

How it fits into the system

Execution Flow

  1. Client sends commit request
  2. Write daemon parses and validates
  3. Operations execute in sequence (container-kind validation happens here; see Containers and Assets)
  4. Events are recorded for each operation
  5. Events are sealed into a batch
  6. Batch is appended to the commit log backend (see Runtime Model)
  7. Client receives success response

Rollback on Failure

If any operation fails:

  1. Execution stops at the failing operation
  2. Undo log is applied in reverse order
  3. State is restored to pre-transaction
  4. Client receives error response

No partial commits are visible to readers.

Event Generation

Each operation generates events that:

  • Describe the state change
  • Carry post-state for replay
  • Are grouped into the transaction batch

Events are the authoritative record (durability depends on backend); operations are the request format.

Key invariants and guarantees

Atomicity

All operations in a transaction succeed or fail together. This is the guarantee that prevents partial state corruption.

Without atomicity, a failure in operation 5 of 10 leaves operations 1-4 committed and 6-10 unexecuted. Your state is now internally inconsistent—a container created but never populated, a transfer half-executed, an instance moved but its parent reference stale. Debugging requires reconstructing “what should have happened,” which is often impossible. Users see corrupt state, operations fail unexpectedly, and trust erodes.

AssetCore enforces atomicity through an undo log (see Runtime Model):

  • No partial execution visible (queries never see intermediate states)
  • Rollback restores exact prior state (replay undo log in reverse)
  • Error responses use RFC 9457 Problem Details with stable codes (tells you WHICH operation failed and why)

The error response tells you which operation failed and why, but the state remains clean. What you gain: confidence that failed transactions leave no trace, no need for manual cleanup after failures, internal consistency is a guarantee not a best-effort. What you give up: you can’t “commit what succeeded and skip what failed.” That’s not a bug, it’s the design. If you need partial progress, break the transaction into smaller commits with explicit checkpoints.

Order Preservation

Operations execute in the order they appear in the array. This seems obvious but has subtle implications for correctness.

Later operations see the effects of earlier ones within the same transaction. This is how you can CreateContainer in operation 1 and AddFungible to that container in operation 2—the container ID from operation 1’s result is visible immediately. Without order preservation, you’d need to split these into separate transactions with manual coordination.

AssetCore guarantees sequential execution:

  • Later operations see effects of earlier ones (dependencies satisfied in sequence)
  • Dependencies are satisfied sequentially (no parallel execution within a transaction)
  • No reordering or optimization that changes semantics (runtime doesn’t reorganize for performance)

This is critical for determinism: if the runtime reordered operations for performance, two identical transactions could produce different event sequences depending on runtime heuristics. Order preservation makes transaction execution a pure function of the input array. What you gain: predictable execution, ability to compose operations with dependencies, deterministic replay. What you give up: the runtime can’t automatically parallelize independent operations within a transaction, but most transactions are small enough that this doesn’t matter.

Determinism

Given identical state and an identical operation sequence, execution produces byte-identical events. This is what makes replay possible.

Determinism at the transaction level builds on the runtime’s determinism guarantees (see Runtime Model). Operations must not depend on external state: no system clock reads, no random number generation, no external API calls. Everything that affects execution flows through the operation arguments or the current state.

AssetCore ensures deterministic execution:

  • Given identical state and operations (same world state, same operation array)
  • Events will be byte-identical (same sequence, same payloads)
  • Enables replay and verification (rebuild state from log, prove what happened when)

What this enables: time-travel debugging (replay to any point and inspect), disaster recovery (rebuild projections from commit log), forensic audit (prove what happened when). What you give up: you can’t call external APIs or use timestamps from operations—everything must be deterministic. If you need wall-clock time or external data, include it as operation arguments (captured at commit time) rather than fetching it during execution.

Fixed Vocabulary

The 24 operations are the complete set. You cannot define custom operations or extend the vocabulary at runtime.

This seems like a limitation until you realize it’s the foundation for auditability and agent safety. Every possible state change fits into one of 24 semantic categories. That’s a tractable space for policy enforcement. Without this constraint, an AI agent could construct arbitrary state transitions you’ve never considered. With it, you can enumerate every possible operation type, attach policies to each, and audit exhaustively.

AssetCore enforces a fixed vocabulary:

  • The 24 operations are complete (no custom operations, no runtime extension)
  • Complex changes compose multiple operations in one transaction (see Recipes for common patterns)
  • This constraint is a feature: it makes governance possible

What you gain: auditable operation space (know every possible change type), agent safety (bounded vocabulary = no surprises), consistent semantics across environments (same operations everywhere). What you give up: flexibility to define domain-specific operations. If some behavior does not map directly, keep that logic outside the runtime and use Asset Core for the state transitions that do. This is the same trade-off as using SQL (fixed query language) vs. arbitrary code—the constraint enables tooling and guarantees.

See also