~/as

# agentstate — conversation history that lives at the edge.

# one api. five primitives. no redis, no postgres, no glue.

~/as $ agentstate init .

import { AgentState } from "@agentstate/sdk";

const client = new AgentState({ apiKey: process.env.AS_KEY });

const conv = await client.createConversation({
  messages: [{ role: "user", content: "Summarize findings" }],
});

const { data } = await client.searchConversations({
  query: "lease",
});
'autosave' is deprecated · F8
conversations48 threads
import { AgentState, AgentStateError } from "@agentstate/sdk";

const client = new AgentState({ apiKey: process.env.AS_KEY });

try {
  const lease = await client.createStateLease("task:migrate", {
    holder_id: "worker-3",
    ttl_ms: 30_000,
  });
  await client.releaseStateLease(lease.id);
} catch (err) {
  if (err instanceof AgentStateError && err.status === 409) {
    // another worker holds the lease
  }
}
lease held by worker-1 · F8
leases4 live
{
  "mcpServers": {
    "agentstate": {
      "type": "http",
      "url": "https://agentstate.app/api/mcp",
      "headers": {
        "Authorization": "Bearer as_live_your_key"
      }
    }
  }
}
'stdio' is ignored for type http · F8
mcpcursor · claude
curl "https://agentstate.app/api/v1/analytics/summary?range=7d" \
  -H "Authorization: Bearer $AS_KEY"

curl "https://agentstate.app/api/v1/analytics/timeseries?range=7d" \
  -H "Authorization: Bearer $AS_KEY"
'range' expected 7d | 30d | 90d · F8
analytics7d · 12 agents

$ # what's inside

state
— versioned key/value with an append-only event log
leases
— exactly-one-writer locks across N concurrent agents
claims
— attach evidence to decisions so you can audit later
tokens
— scoped, revocable, time-bounded delegation
conversations
— CRUD, search, tags, bulk export, AI-generated titles
rest
— cursor-paginated snake_case JSON, bearer-token auth
sdks
— TypeScript, Python, Vercel AI SDK, LangGraph adapters
mcp
— remote streamable-HTTP for Claude, Cursor, and Windsurf
search
— project-wide full-text with snippets and tag filters
analytics
— summaries and time-series across agents and tags
keys
— SHA-256 hashed bearer keys with subset delegation
self-host
— MIT forever — same Worker + D1 stack on your account

$ # how it works

Agents talk to one edge API. Five coordination primitives share auth, projects, and durable storage — so you never wire Redis locks, custom memory tables, and chat logs separately.

AGENTSTATEstateleaseclaimtokenconversationagentSDKagentMCPagentRESTagentSDKagentREST

Agents coordinate through one hub

  1. 01
    Agent calls

    REST, TypeScript/Python SDK, or MCP — same auth, same project.

  2. 02
    Edge API

    Cloudflare Worker validates the key, scopes, and rate limits.

  3. 03
    Five primitives

    State, leases, claims, tokens, and conversations behind one API.

  4. 04
    Durable store

    D1 at the edge — versioned events, search indexes, audit trails.

  5. 05
    Observe

    Dashboard analytics, webhooks, bulk export, and SSE state watch.

$ # five primitives

state
— versioned key/value state. Append-only event log; query across all agents in a fleet. Any shape, typed.
lease
— distributed locks. Exactly-one-writer coordination across N concurrent agents — no double-writes.
claim
— verifiable assertions. Attach evidence to decisions so you can audit them later. Built-in provenance.
token
— scoped delegation. Sub-agents get only the access they need — revocable, time-bounded, auditable.
conversation
— full message history. CRUD, search, tags, bulk export, and AI-generated titles — for agents and humans.

why not just memory?[compare]

$ # install

Copy a recipe for your stack. Same API from TypeScript, Python, AI SDK, LangGraph, or raw REST.

typescript
import { AgentState } from "@agentstate/sdk";

const client = new AgentState({ apiKey: process.env.AS_KEY });

const conv = await client.createConversation({
  messages: [{ role: "user", content: "Summarize findings" }],
});

const { data } = await client.searchConversations({
  query: "summarize",
});
import { AgentState } from "@agentstate/sdk";
import { createAISDKChatStore } from "@agentstate/sdk/ai-sdk";

const client = new AgentState({ apiKey: process.env.AS_KEY });
const store = createAISDKChatStore(client);

const chatId = await store.createChat();
await store.saveChat({ chatId, messages });
const messages = await store.loadChat(chatId);
import { AgentState } from "@agentstate/sdk";
import { AgentStateCheckpointSaver } from "@agentstate/sdk/langgraph";

const client = new AgentState({ apiKey: process.env.AS_KEY });
const saver = new AgentStateCheckpointSaver(client);

const graph = workflow.compile({ checkpointer: saver });
from agentstate import AgentStateClient

client = AgentStateClient(api_key="as_live_...")

conv = client.create_conversation(
    messages=[{"role": "user", "content": "Hello!"}]
)
messages = client.get_conversation(conv.id).messages
curl -X POST https://agentstate.app/api/v1/conversations \
  -H "Authorization: Bearer as_live_..." \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Hi"}]}'

$ # examples that ship

typescript
import { AgentState } from "@agentstate/sdk";

const client = new AgentState({
  apiKey: process.env.AGENTSTATE_API_KEY!,
});

// Create with metadata + tags
const conv = await client.createConversation({
  title: "Research session",
  messages: [
    { role: "user", content: "Compare lease strategies" },
    { role: "assistant", content: "Use TTL + renew..." },
  ],
  metadata: { agent_id: "researcher-1" },
});

await client.appendMessages(conv.id, [
  { role: "user", content: "Show the recipe" },
]);

const hits = await client.searchConversations({
  query: "lease",
  limit: 10,
});
// → docs: /docs#conversations
from agentstate import AgentStateClient

client = AgentStateClient(api_key="as_live_...")

conv = client.create_conversation(
    title="Research session",
    messages=[
        {"role": "user", "content": "Compare lease strategies"},
        {"role": "assistant", "content": "Use TTL + renew..."},
    ],
    metadata={"agent_id": "researcher-1"},
)

client.append_messages(conv.id, [
    {"role": "user", "content": "Show the recipe"},
])

hits = client.search_conversations(query="lease", limit=10)
# → pip install agentstate  |  docs: /docs#quickstart
import { AgentState } from "@agentstate/sdk";
import { createAISDKChatStore } from "@agentstate/sdk/ai-sdk";

const client = new AgentState({ apiKey: process.env.AS_KEY! });
const store = createAISDKChatStore(client, {
  // optional: namespace chats under a project prefix
});

const chatId = await store.createChat();
await store.saveChat({
  chatId,
  messages: [
    { role: "user", content: "Plan the migration" },
    { role: "assistant", content: "Step 1..." },
  ],
});

const history = await store.loadChat(chatId);
// → examples/ai-sdk-ui  |  docs: /docs#ai-sdk
import { AgentState } from "@agentstate/sdk";
import { AgentStateCheckpointSaver } from "@agentstate/sdk/langgraph";

const client = new AgentState({ apiKey: process.env.AS_KEY! });
const checkpointer = new AgentStateCheckpointSaver(client);

const graph = workflow.compile({ checkpointer });

const result = await graph.invoke(
  { messages: [{ role: "user", content: "Start" }] },
  { configurable: { thread_id: "thread-42" } },
);
// → examples/langgraph-js  |  @agentstate/sdk/langgraph
from agentstate import AgentStateClient
from agentstate.langgraph import AgentStateCheckpointSaver

client = AgentStateClient(api_key="as_live_...")
saver = AgentStateCheckpointSaver(client)

config = {"configurable": {"thread_id": "thread-42"}}
saver.put(
    config,
    {"id": "ckpt-1", "values": {"phase": "start"}},
    {"note": "first checkpoint"},
    {},
)
# → pip install agentstate[langgraph]
# → examples/langgraph-python
import { AgentState, AgentStateError } from "@agentstate/sdk";

const client = new AgentState({ apiKey: process.env.AS_KEY! });
const stateKey = "task:migrate-db";

try {
  const lease = await client.createStateLease(stateKey, {
    holder_id: "worker-3",
    ttl_ms: 30_000,
  });
  // ... do exclusive work ...
  await client.releaseStateLease(lease.id);
} catch (err) {
  if (err instanceof AgentStateError && err.status === 409) {
    // another worker holds the lease — skip
  }
}
// → examples/fleet-leases  |  recipes/leases
{
  "mcpServers": {
    "agentstate": {
      "type": "http",
      "url": "https://agentstate.app/api/mcp",
      "headers": {
        "Authorization": "Bearer as_live_your_key"
      }
    }
  }
}
# Create
curl -X POST https://agentstate.app/api/v1/conversations \
  -H "Authorization: Bearer as_live_..." \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Hi"}]}'

# Search
curl "https://agentstate.app/api/v1/conversations/search?q=lease" \
  -H "Authorization: Bearer as_live_..."

# OpenAPI
curl https://agentstate.app/openapi.json

full guides in [docs]· runnable samples on[github/examples]

$ # packages

Install the client for your language, wire MCP into your IDE, or call the REST API directly.

TypeScript · npm

@agentstate/sdk

Typed client for all primitives, plus Vercel AI SDK and LangGraph adapters.

npm i @agentstate/sdk
  • @agentstate/sdk/ai-sdk
  • @agentstate/sdk/langgraph
Python · PyPI

agentstate

HTTPX client with LangGraph checkpointer extras for Python agent fleets.

pip install agentstate
  • pip install agentstate[langgraph]
MCP · local stdio

@agentstate/mcp

Run AgentState tools in Cursor, Claude Desktop, or Windsurf over stdio.

npx @agentstate/mcp
Remote · streamable HTTP

Hosted MCP

Point any MCP client at the hosted endpoint — OAuth 2.1 or bearer key.

https://agentstate.app/api/mcp
Any language

REST API

Snake_case JSON, bearer auth, cursor pagination — small enough for agent context.

curl https://agentstate.app/api/v1/...
  • /llms.txt
  • /agents.md

$ # also

rest api
— Cursor-paginated, snake_case JSON, bearer-token auth. Small enough to keep in an agent's context window.
sdks for ts & python
— First-class clients plus adapters for Vercel AI SDK, LangGraph, and Cloudflare Workers AI.
mcp server
— Remote streamable-HTTP MCP endpoint at /api/mcp — works with Claude, Cursor, and Windsurf out of the box.
full-text search
— Search across every message in a project, with match snippets and tag/external-ID filters.
usage analytics
— Summaries and time-series across agents and tags, so you can see what your fleet is actually doing.
scoped api keys
— SHA-256-hashed bearer keys with subset delegation — issue a key that can only do what a sub-agent needs.

$ # pricing

AgentState is free. No paid tier. Use the hosted cloud without a credit card, or run the full MIT-licensed stack on your own Cloudflare account forever.

cloud
$0

all five primitives · dashboard · sdks · remote mcp

self-host
$0

mit forever · your d1 · your limits

[see pricing]

# ship the agent, not the backend.

Spin up a project, grab a key, and persist your first conversation in two minutes. no credit card.

~/as $ agentstate start