How to Coordinate Multi-Agent Work Using Leases, Signals, and Checkpoints in AgentMemory

AgentMemory provides three core coordination primitives—leases for exclusive action locks, signals for asynchronous inter-agent messaging, and checkpoints for external condition gating—that enable safe, scalable multi-agent collaboration through a shared KV store.

Coordinating autonomous agents requires robust primitives for exclusivity, communication, and external validation beyond simple task queues. The agentmemory repository (rohitg00/agentmemory) implements exactly such an orchestration layer, persisting all coordination state in a transactional SQLite-backed KV store under the mem:* namespace. This guide explains how to coordinate multi-agent work using leases, signals, and checkpoints to build deterministic workflows that prevent duplicate execution, facilitate real-time collaboration, and gate progress on external events like CI pipelines or human approvals.

Understanding the Three Coordination Primitives

Leases: Exclusive Action Locks

Leases function as distributed locks tied to specific action IDs, ensuring that only one agent can execute a given action at any time. According to the source code in src/functions/leases.ts, a lease stores the agentId, an expiresAt timestamp, and a status field (active | released | expired). Agents acquire leases via the mem::lease-acquire function; if an active lease already exists for that action, the request fails, preventing duplicate work. A background task automatically cleans up expired leases, and agents can explicitly release locks early using mem::lease-release.

Signals: Asynchronous Agent Messaging

Signals provide a lightweight, persistent message bus that allows agents to communicate without tight coupling. Stored in the KV store under the mem:signals scope, signal entries support filtering by recipient (to), message type, and threadId. The implementation in src/functions/signals.ts exposes mem::signal-send for broadcasting updates and mem::signal-read for consuming messages. Once read, signals are automatically marked as consumed, ensuring idempotent message processing across agent pools.

Checkpoints: External Condition Gates

Checkpoints act as declarative gates that block action progress until external systems satisfy specific conditions. Defined in src/functions/checkpoints.ts, each checkpoint maintains a status (pending | passed | failed) and an array of linkedActionIds that depend on it. Workflows create checkpoints using mem::checkpoint-create, and external processes or agents resolve them via mem::checkpoint-resolve, which automatically unblocks all linked actions by updating their state in the frontier calculations.

How the Coordination Primitives Work Together

The orchestration layer combines these primitives through a unified lifecycle:

  1. Action Creation: An agent creates an action entry in the mem:actions KV scope.

  2. Lease Acquisition: Before execution, the agent calls mem::lease-acquire. If granted, the agent holds exclusive rights; otherwise, it must wait or skip.

  3. Signal Exchange: During execution, agents emit progress updates via mem::signal-send, while other agents poll mem::signal-read to coordinate sub-tasks or handoffs.

  4. Checkpoint Gating: Actions declare checkpoints that must be resolved before specific stages. The checkpoint blocks the action in the frontier until mem::checkpoint-resolve is called.

  5. Frontier Scheduling: The frontier function in src/functions/frontier.ts merges data from mem:leases, mem:signals, and mem:checkpoints to compute which actions have no active leases, no pending checkpoints, and are ready for execution.

All state changes are atomic and audited via the built-in recordAudit mechanism, ensuring reproducibility across the multi-agent system.

Code Examples

Acquire a Lease, Execute Work, and Release

// Attempt to acquire exclusive rights to action-123
const leaseRes = await sdk.trigger({
  function_id: "mem::lease-acquire",
  payload: { actionId: "action-123", agentId: "agent-A" },
});

if (!leaseRes.success) {
  throw new Error("Lease already held by another agent");
}

// Execute the critical section
await performActionWork();

// Explicitly release the lease
await sdk.trigger({
  function_id: "mem::lease-release",
  payload: { leaseId: leaseRes.lease.id, agentId: "agent-A" },
});

Source: src/functions/leases.ts

Send Progress Signals Between Agents

// Agent A notifies Agent B of completion
await sdk.trigger({
  function_id: "mem::signal-send",
  payload: {
    from: "agent-A",
    to: "agent-B",
    type: "task-complete",
    threadId: "workflow-42",
    content: "Step 1 finished successfully",
  },
});

Consume Signals with Filtering

// Agent B reads pending messages
const res = await sdk.trigger({
  function_id: "mem::signal-read",
  payload: {
    agentId: "agent-B",
    threadId: "workflow-42",
    limit: 10,
  },
});

console.log("Pending signals:", res.signals);

Source: src/functions/signals.ts

Gate Actions with External Checkpoints

// Create a checkpoint blocking action until CI passes
const cp = await sdk.trigger({
  function_id: "mem::checkpoint-create",
  payload: {
    type: "ci",
    name: "build-verified",
    status: "pending",
    linkedActionIds: ["action-123"],
  },
});

// Later, when CI system reports success
await sdk.trigger({
  function_id: "mem::checkpoint-resolve",
  payload: {
    checkpointId: cp.checkpoint.id,
    status: "passed",
    resolvedBy: "ci-service",
    result: { buildId: "2026-05-10-001" },
  },
});

Source: src/functions/checkpoints.ts

Complete Multi-Agent Coordination Workflow

// Step 1: Acquire lease to prevent duplicate execution
const lease = await sdk.trigger({
  function_id: "mem::lease-acquire",
  payload: { actionId: "action-123", agentId: "agent-A" },
});

if (!lease.success) return; // Another agent owns this action

try {
  // Step 2: Notify collaborators
  await sdk.trigger({
    function_id: "mem::signal-send",
    payload: {
      from: "agent-A",
      to: "agent-B",
      type: "task-start",
      threadId: "proj-xyz",
      content: "Processing payment",
    },
  });

  // Step 3: Create checkpoint for external validation
  await sdk.trigger({
    function_id: "mem::checkpoint-create",
    payload: {
      type: "approval",
      name: "manager-approval",
      status: "pending",
      linkedActionIds: ["action-123"],
    },
  });

  // Step 4: Wait for external resolution (simulated here)
  await waitForApproval();

  await sdk.trigger({
    function_id: "mem::checkpoint-resolve",
    payload: {
      checkpointId: "ckpt-approval-01",
      status: "passed",
      resolvedBy: "manager-01",
    },
  });

} finally {
  // Step 5: Always release the lease
  await sdk.trigger({
    function_id: "mem::lease-release",
    payload: { leaseId: lease.lease.id, agentId: "agent-A" },
  });
}

Key Source Files for Coordination

File Purpose
src/functions/leases.ts Implements mem::lease-acquire, mem::lease-release, and expiration logic
src/functions/signals.ts Implements mem::signal-send and mem::signal-read with filtering
src/functions/checkpoints.ts Implements mem::checkpoint-create and mem::checkpoint-resolve
src/functions/frontier.ts Scheduler that computes ready actions by merging lease, signal, and checkpoint state
src/state/schema.ts Defines KV namespaces (mem:leases, mem:signals, mem:checkpoints)
src/triggers/api.ts HTTP API wrappers exposing coordination functions to external callers
src/mcp/tools-registry.ts MCP tool definitions for integration with MCP clients

Summary

  • Leases guarantee exclusive execution by granting time-bounded locks on actions, preventing race conditions and duplicate work across agent pools.
  • Signals enable loose coupling through persistent, filterable messages that agents exchange via mem::signal-send and mem::signal-read.
  • Checkpoints integrate external validation by blocking actions until resolved, linking multiple actions to a single gate via linkedActionIds.
  • Frontier scheduling in src/functions/frontier.ts combines these primitives transactionally to determine which actions are safe to execute.
  • All coordination state resides in the SQLite-backed KV store with full audit logging, ensuring reproducible multi-agent workflows.

Frequently Asked Questions

How do leases prevent duplicate work in multi-agent systems?

Leases function as exclusive locks tied to specific action IDs. When an agent invokes mem::lease-acquire from src/functions/leases.ts, the system atomically checks for existing active leases in the mem:leases KV scope. If none exist, it creates an entry containing the agentId and expiresAt timestamp, granting exclusive rights. If a lease already exists, the request fails immediately, forcing other agents to wait or skip the action. Background cleanup tasks automatically expire stale leases based on the timestamp.

What distinguishes signals from checkpoints in agentmemory?

Signals provide asynchronous, non-blocking communication between agents, allowing them to broadcast updates or request assistance without halting execution. Checkpoints, conversely, are explicitly designed to block action progress until external conditions are satisfied. While signals are consumed via mem::signal-read and then marked as read, checkpoints created via mem::checkpoint-create remain in a pending state until explicitly resolved through mem::checkpoint-resolve, at which point they unblock all linkedActionIds in the frontier calculations.

How does the frontier scheduler determine which actions are ready to run?

The frontier function in src/functions/frontier.ts calculates the ready-set by filtering the mem:actions table against three criteria derived from coordination primitives. It excludes actions with active leases in mem:leases, actions blocked by unresolved checkpoints in mem:checkpoints, and actions with unsatisfied dependencies. By transactionally merging these KV tables, the frontier produces a deterministic list of actions eligible for immediate scheduling, ensuring agents only pick up work that is safe to execute.

Can a single checkpoint gate multiple actions simultaneously?

Yes, the linkedActionIds array parameter in mem::checkpoint-create supports linking one checkpoint to multiple action IDs. When the checkpoint is resolved via mem::checkpoint-resolve in src/functions/checkpoints.ts, the system automatically updates the status for all linked actions, removing blockers from the frontier for the entire batch. This pattern enables efficient approval workflows where one external event, such as a CI build completion or manager sign-off, can unblock an entire pipeline of dependent actions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →