Skip to content

Contexts

A context is an isolated instance of an application running on the Calimero network. Each context has its own state, members, and access controls. Think of it as a “workspace” or “room” where a specific application instance operates.

Contexts provide:

  • State Isolation: Each context maintains its own CRDT-backed state, completely separate from other contexts
  • Member Management: Invite-only access control with cryptographic identities
  • Multi-Chain Support: Each context can be associated with a blockchain protocol (NEAR, Ethereum, ICP, etc.)
  • Lifecycle Management: Create, invite members, join, and manage contexts independently
flowchart LR
    START[Start] --> CREATED[Created<br/>WASM installed]
    CREATED --> INVITED[Invited<br/>Invitation sent]
    INVITED --> JOINED[Joined<br/>Accept invitation]
    JOINED --> ACTIVE[Active<br/>Members can call]
    ACTIVE --> END[End<br/>Delete context]
    
    style START fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff
    style CREATED fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff
    style INVITED fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff
    style JOINED fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff
    style ACTIVE fill:#000000,stroke:#00ff00,stroke-width:4px,color:#ffffff
    style END fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff

A context is created when an application is installed and initialized. See core/crates/meroctl/README.md for CLI details or visit getting started page.

What happens:

  • Application WASM is installed on the node
  • Initial context state is created (via #[app::init] method)
  • Context creator becomes the first member
  • Context ID is generated (unique identifier)

Multi-node participation uses namespaces — root groups that combine an application with its member network. The namespace create command creates both the namespace and its associated context.

Terminal window
# ── Node 1: Create a namespace with the application ──
$: meroctl --node node1 namespace create --application-id <APP_ID>
> ╭──────────────────────┬──────────────────────────────────────────────╮
> │ Namespace ID │ FfHXVWRqbSc2wrU2tEeuLQxFcmcpcfZd8Qk9yQFkm7W7 │
> ╰──────────────────────┴──────────────────────────────────────────────╯
# ── Node 1: Generate invitation JSON for another node ──
$: meroctl --node node1 namespace invite FfHXVWRqbSc2wrU2tEeuLQxFcmcpcfZd8Qk9yQFkm7W7
> {
> "invitation": { ... }
> }
# ── Node 2: Join using the invitation payload ──
$: meroctl --node node2 namespace join FfHXVWRqbSc2wrU2tEeuLQxFcmcpcfZd8Qk9yQFkm7W7 '<INVITATION_JSON>'
> ╭───────────────────────────────╮
> │ Successfully joined namespace │
> ╰───────────────────────────────╯
# ── Node 2: Join a specific context within the namespace ──
$: meroctl --node node2 group join-context <CONTEXT_ID>

What happens after joining:

  • Member is added to namespace membership
  • Member receives current state snapshot
  • Member can now call methods and receive updates

Context members have different permission levels:

  • Creator: Full control, can invite/revoke members
  • Member: Can call methods, read state, receive events
  • Read-only: Can query state but cannot mutate
flowchart LR
    CTX1[Context A<br/>Shared State] --> PRIVATE1[Private<br/>Storage]
    CTX2[Context B<br/>Shared State] --> PRIVATE2[Private<br/>Storage]
    CTX1 -.->|isolated| CTX2
    
    style CTX1 fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff
    style CTX2 fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff
    style PRIVATE1 fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff
    style PRIVATE2 fill:#1a1a1a,stroke:#00ff00,stroke-width:3px,color:#ffffff

Key points:

  • Shared CRDT State: Replicated across all member nodes, automatically synchronized
  • Private Storage: Node-local data that never leaves the executing node
  • Complete Isolation: Context A cannot access Context B’s state

See core/crates/storage/README.md for CRDT implementation details.

Contexts can be associated with blockchain protocols:

ProtocolUse CaseIdentity Source
NEARNEAR-based applicationsNEAR account IDs
EthereumEthereum dAppsEthereum addresses
ICPInternet Computer appsICP principals
StellarStellar-based appsStellar accounts

Each protocol provides:

  • Identity verification: Cryptographic proof of ownership
  • Cross-chain attestations: Verifiable claims about on-chain state
  • Relayer integration: Bridge between Calimero and blockchain

Query state:

Terminal window
$: meroctl --node <NODE_ID> call <QUERY_METHOD_NAME> \
--context <CONTEXT_ID> \
--args <ARGS_IN_JSON>

Mutate state:

Terminal window
$: meroctl --node <NODE_ID> call <MUTATE_METHOD_NAME> \
--context <CONTEXT_ID> \
--args <ARGS_IN_JSON>

Subscribe to events:

  • WebSocket: Connect to ws://localhost:2528/ws
  • Use subscribe method with context_id and event_type
  • See API Reference for details

See core/crates/meroctl/README.md for complete CLI documentation.

List contexts:

Terminal window
$: meroctl --node <NODE_ID> context ls

Manage member capabilities:

Terminal window
meroctl --node <NODE_ID> group members set-caps <GROUP_ID> <MEMBER_IDENTITY> <CAPABILITIES>

Revoking access removes the member but preserves state history.

  1. One Context Per Use Case: Create separate contexts for different purposes (e.g., one per team, one per project)
  2. Minimize Members: Only invite necessary members to reduce sync overhead
  3. Use Private Storage: Store secrets and node-local data in private storage, not CRDT state
  4. Context Naming: Use descriptive context IDs or metadata for easier management

For detailed context documentation: