Chisle
The coding-agent plugin that bills 52% of a bare model across 20 live tasks. Terse persona + tool-output compressor + context diet.
Terse builds durable agent infrastructure with serverless actors and workflows, strongly typed TypeScript APIs, and Rust runtimes.
Developer toolsRust · TypeScriptGitHub @TerseAIOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Open Source Alternative to Durable Objects. Build multiplayer AI + complex agent coordination systems.
Translation pending
Loading the full README.
Read the full README ↗an open-source alternative to Cloudflare Durable Objects... with no vendor lock-in, memory limits, and observability built in.
Durable Actors help you build real-time applications like chat systems (e.g. ChatGPT, Codex), collaboration tools (e.g. Notion), and agent swarms (e.g. Devin).
They provide stateful serverless functions, a foundational building block that abstracts away persistence, coordination, and infrastructure challenges in distributed systems.
Live demo · TypeScript documentation · Python documentation
Try Durable Actors on Terse Cloud at app.useterse.ai. To get started, run:
bunx terse-cli@latest install
Install Bun 1.4.2+.
bunx durable-actors init my-actors
cd my-actors
bun install
bunx durable-actors dev # Run the server locally on your machine
Define and export actors in your actor project’s src/actors.ts, the default entrypoint loaded by durable-actors dev. The runtime loads actors on demand and persists fields marked @Persisted.
For example, a chat history actor:
import { openai } from "@ai-sdk/openai"
import { streamText } from "ai"
import { Actor, type ActorSocket, Interleave, Persisted } from "durable-actors"
type Message = { role: "user" | "assistant"; content: string }
export class ChatHistory extends Actor<null, string, Message[]> {
@Persisted messages: Message[] = []
async onConnect(socket: ActorSocket<null, Message[]>) {
socket.send(this.messages)
}
@Interleave // Let other calls run during await, e.g. new connections while a reply streams.
async onMessage(_socket: ActorSocket<null, Message[]>, text: string) {
this.messages.push({ role: "user", content: text })
const result = streamText({ model: openai("gpt-5-mini"), messages: [...this.messages] })
const reply: Message = { role: "assistant", content: "" }
this.messages.push(reply)
this.broadcast(this.messages)
for await (const chunk of result.textStream) {
reply.content += chunk
this.broadcast(this.messages)
}
}
}
We make it super easy to integrate the actors into your existing tech stack. Just generate the client and you get a fully type safe contract to interact with.
bunx durable-actors generate
Create a WebSocket connection to one shared chat:
import express from "express"
import { actors } from "../generated/index.js"
export const app = express()
app.post("/api/chat/socket", async (_req, res) => {
const grant = await actors.ChatHistory.prepareWebsocket({
actorId: "lobby",
metadata: null
})
res.set("Cache-Control", "no-store").json(grant)
})
import { useEffect, useRef, useState } from "react"
import { createRoot } from "react-dom/client"
import type { actors } from "../generated/index.js"
function Chat() {
const socket = useRef<WebSocket>(null)
const [messages, setMessages] = useState<actors.ChatHistory.Outgoing>([])
useEffect(() => {
let active = true
async function connect() {
const response = await fetch("/api/chat/socket", { method: "POST" })
const { websocketUrl } = await response.json()
if (!active) return
socket.current = new WebSocket(websocketUrl)
socket.current.onmessage = event => setMessages(JSON.parse(event.data))
}
void connect()
return () => {
active = false
socket.current?.close()
}
}, [])
function send(form: FormData) {
const text = String(form.get("message")).trim()
if (!text || socket.current?.readyState !== WebSocket.OPEN) return
socket.current.send(JSON.stringify(text))
}
return (
<main>
<div role="log" aria-label="Messages">
{messages.map((message, index) => (
<p key={index}><strong>{message.role}:</strong> {message.content}</p>
))}
</div>
<form action={send}>
<input name="message" aria-label="Message" required />
<button>Send</button>
</form>
</main>
)
}
createRoot(document.getElementById("root")!).render(<Chat />)
For a complete app with error handling and retries, see the AI Chat example.
Durable Agents provides built-in observability features:
For complete sample applications, see AI Chat, Collaborative Documents, and Chatroom.
Projects created with durable-actors init already include the skill. To use it elsewhere in Claude Code, install the plugin:
/plugin install durable-actors --marketplace TerseAI/durable-actors
For Cursor, Codex, and other agents, install the skill with skills.sh:
npx skills add TerseAI/durable-actors
Then describe what you want to build, or run /durable-actors:durable-actors-quickstart in Claude Code.
Bug reports, feature requests, documentation fixes, and code contributions are welcome. See the contributing guide for repository setup and checks, and follow our code of conduct.
Use GitHub Issues for bugs, ideas, and questions. Report vulnerabilities privately using our security policy.
Follow development and release notes on GitHub Releases.
MIT © 2026 Terse