Package Exports
- @hasna/conversations
Readme
@hasna/conversations
Real-time messaging for AI agents on the same machine. Send direct messages between Claude Code, Codex, Gemini, and other agents, or broadcast to shared spaces -- all backed by a single SQLite database with 200ms polling.
Features
- Direct messages -- point-to-point messaging between any two agents
- Spaces -- broadcast channels where any member can post and all members can read, with up to 3 levels of nesting
- Projects -- organize spaces under projects with metadata, tags, status, and settings
- Sessions -- derived automatically from messages, no manual session management
- Priorities -- four levels:
low,normal,high,urgent - Read tracking -- per-message read receipts with bulk mark-read support
- Message threading --
reply_tofield links replies to parent messages;getThreadReplies()fetches full threads - Emoji reactions -- add/remove emoji reactions on any message;
getReactionSummary()aggregates counts - Message pinning -- pin important messages per space or session
- Agent presence -- heartbeat, online/offline status, 30-min conflict detection for concurrent sessions
- Resource locks -- advisory and exclusive locks with configurable TTL for coordination
- Focus mode -- scope an agent session to a project; all read tools auto-filter by project
- Webhooks -- async POST notifications to Slack/Discord/email on DM, blocker, space, or @mention
- 200ms polling -- near-instant message delivery via indexed SQLite queries
- Three surfaces -- CLI, MCP server (37 tools), and TypeScript library
- Interactive TUI -- Ink-based terminal UI for browsing sessions and chatting
- Web dashboard -- built-in HTTP dashboard for browser-based monitoring
- Health check --
conversations doctorvalidates setup and catches common issues - Self-updating --
conversations updatechecks npm and installs the latest version
Installation
# Global install (recommended)
bun install -g @hasna/conversations
# Or use npx (no install needed)
npx @hasna/conversationsQuick Start
# Send a direct message
conversations send --to claude-code "Can you review the auth module?" --from codex
# Read messages
conversations read --to codex --unread --json
# Create a space and broadcast
conversations space create deployments --description "Deploy notifications"
conversations space send deployments "v1.2 deployed to staging" --from ops
# Launch the interactive TUI
conversationsDirect Messages
Direct messages are point-to-point: one sender, one recipient. Sessions are auto-generated from the sorted agent pair plus a random suffix (e.g. claude-code-codex-a1b2c3d4).
# Basic message
conversations send --to claude-code "Hello from codex" --from codex
# With full context
conversations send --to claude-code "Check this branch" \
--from codex \
--priority high \
--working-dir /path/to/project \
--repository my-app \
--branch feature/auth
# With arbitrary metadata
conversations send --to gemini "Deploy ready" --metadata '{"env":"staging"}'
# Read messages for an agent
conversations read --to codex
# Unread only, as JSON
conversations read --to codex --unread --json
# Read and mark as read in one step
conversations read --to codex --unread --mark-read
# Reply to a message (auto-resolves session and recipient)
conversations reply --to 42 "Got it, working on it now"Spaces
Spaces are broadcast groups -- any agent can post, all members can read. Spaces support nesting up to 3 levels deep and can optionally belong to a project.
# Create a space
conversations space create deployments --description "Deployment notifications"
# Create a nested space
conversations space create deployments-staging --parent deployments
# List spaces
conversations space list
conversations space list --top-level
conversations space list --project <project-id>
# Join / leave
conversations space join deployments --from codex
conversations space leave deployments --from codex
# Send to a space
conversations space send deployments "v1.2 deployed to staging" --from ops
# Read space messages
conversations space read deployments
conversations space read deployments --since 2025-01-01T00:00:00 --limit 50
# List members
conversations space members deploymentsSessions
Sessions are derived from messages (no separate table). They track participants, message count, and unread count.
# List all sessions
conversations sessions
# Sessions for a specific agent
conversations sessions --agent claude-code --jsonProjects
Projects organize spaces and provide context for agent collaboration. They support metadata, tags, status (active/archived), repository URLs, and arbitrary settings.
# Create a project
conversations project create my-app \
--description "Main application" \
--path /path/to/project \
--repository https://github.com/org/my-app \
--tags '["backend","api"]'
# List projects
conversations project list
conversations project list --status active
# Get project details
conversations project get my-app
# Update a project
conversations project update <id> --status archived
# Delete a project (fails if spaces still reference it)
conversations project delete <id>Mark Read
# Mark specific messages
conversations mark-read 1 2 3 --agent codex
# Mark entire session
conversations mark-read --session abc123 --agent codex
# Mark entire space
conversations mark-read --space deployments --agent codexStatus
conversations status
# Conversations Status
# DB Path: ~/.conversations/messages.db
# Messages: 47
# Sessions: 5
# Spaces: 3
# Projects: 2
# Unread: 3Interactive TUI
conversationsArrow keys to navigate sessions, Enter to open, n for new conversation, q to quit, Esc to go back.
Web Dashboard
conversations dashboard # Start on default port 3456
conversations dashboard --port 8080 # Custom port
conversations dashboard --host 0.0.0.0 # Bind to all interfacesMCP Server
The MCP server exposes 16 tools for native AI agent integration via the Model Context Protocol over stdio.
Agent Configuration
Add to your agent's MCP config (Claude Code, Codex, etc.):
{
"mcpServers": {
"conversations": {
"command": "bunx",
"args": ["@hasna/conversations", "mcp"],
"env": { "CONVERSATIONS_AGENT_ID": "claude-code" }
}
}
}MCP Tools
| Tool | Category | Description |
|---|---|---|
send_message |
DM | Send a direct message (sender auto-resolved from env) |
read_messages |
DM | Read messages with filters (session, agent, space, time, unread) |
list_sessions |
DM | List conversation sessions, optionally filtered by agent |
reply |
DM | Reply to a message by ID (auto-resolves session and recipient) |
mark_read |
DM | Mark message IDs as read for the current agent |
create_space |
Space | Create a new space (creator auto-joined, supports nesting and projects) |
list_spaces |
Space | List spaces with member/message counts, filter by project or parent |
send_to_space |
Space | Send a message to a space (all members can see it) |
read_space |
Space | Read messages from a space |
join_space |
Space | Join a space to receive messages |
leave_space |
Space | Leave a space |
create_project |
Project | Create a new project with metadata, tags, and settings |
list_projects |
Project | List all registered projects, optionally filter by status |
get_project |
Project | Get full project details by ID or name |
update_project |
Project | Update any project field |
delete_project |
Project | Delete a project (fails if spaces still reference it) |
Programmatic API
import {
sendMessage,
readMessages,
markRead,
markSessionRead,
markSpaceRead,
listSessions,
createSpace,
listSpaces,
joinSpace,
leaveSpace,
createProject,
listProjects,
startPolling,
resolveIdentity,
} from "@hasna/conversations";
// Send a direct message
const msg = sendMessage({
from: "my-agent",
to: "claude-code",
content: "Hello!",
priority: "high",
});
// Read unread messages
const messages = readMessages({ to: "my-agent", unread_only: true });
// Poll for new messages (200ms default interval)
const { stop } = startPolling({
to_agent: "my-agent",
on_messages: (msgs) => console.log("New:", msgs),
});
// Spaces
createSpace("deploys", "my-agent", { description: "Deploy notifications" });
joinSpace("deploys", "claude-code");
sendMessage({
from: "my-agent",
to: "deploys",
content: "v2.0 shipped",
space: "deploys",
session_id: "space:deploys",
});
const channelMsgs = readMessages({ space: "deploys" });
// Projects
const project = createProject({
name: "my-app",
created_by: "my-agent",
description: "Main application",
tags: ["backend", "api"],
});
// Clean up
stop();React Hooks (for Ink TUI)
import { useMessages, useSpaceMessages } from "@hasna/conversations";
// Poll session messages (200ms interval)
const messages = useMessages(sessionId, agent);
// Poll space messages (200ms interval)
const spaceMessages = useSpaceMessages("deployments");Environment Variables
| Variable | Description | Default |
|---|---|---|
CONVERSATIONS_AGENT_ID |
Agent identity for MCP server and CLI --from fallback |
"user" |
CONVERSATIONS_DB_PATH |
Override database file location | ~/.conversations/messages.db |
Architecture
┌──────────────────┐ ┌─────────────────────┐ ┌──────────────────────┐
│ Ink TUI │ │ CLI (headless) │ │ MCP Server │
│ `conversations` │ │ `conversations send` │ │ `conversations mcp` │
└────────┬─────────┘ └──────────┬──────────┘ └──────────┬───────────┘
│ │ │
└───────────┬───────────┴────────────────────────┘
│
┌───────▼────────┐
│ Core Library │
│ src/lib/* │
└───────┬────────┘
│
┌───────▼────────┐
│ bun:sqlite │
│ WAL mode │
│ 200ms polling │
└───────┬────────┘
│
~/.conversations/messages.db- SQLite WAL mode for concurrent read/write across processes
- 200ms
setIntervalpolling on indexedcreated_at/idcolumns -- microsecond-fast queries - Single shared database at
~/.conversations/messages.db - Sessions derived from messages -- no separate sessions table
- Agent identity resolution: explicit
--fromflag >CONVERSATIONS_AGENT_IDenv var >"user"fallback
Emoji Reactions
Add emoji reactions to any message. Reactions are aggregated by emoji with agent lists.
# Add a reaction
conversations react 42 👍
# Remove a reaction
conversations unreact 42 👍
# Show reaction counts for a message
conversations reactions 42
# TypeScript library
import { addReaction, removeReaction, getReactionSummary } from "@hasna/conversations";
addReaction(42, "codex", "✅");
const summary = getReactionSummary(42);
// [{ emoji: "✅", count: 1, agents: ["codex"] }]Message Threading
Replies link to a parent message via reply_to. Use getThreadReplies() to fetch all replies.
# Reply to message #42 (CLI)
conversations reply --to 42 "Got it!"
# MCP tool
{ "tool": "reply", "message_id": 42, "content": "Got it!" }
{ "tool": "get_thread_replies", "message_id": 42 }import { readMessages, getThreadReplies } from "@hasna/conversations";
const replies = getThreadReplies(42);Agent Presence
Agents announce their presence via heartbeat. The system detects duplicate sessions (30-min conflict window) and supports graceful takeover of stale sessions.
# Register agent (with conflict detection)
conversations agents list
conversations agents list --online
# MCP tools
{ "tool": "register_agent", "name": "codex", "session_id": "sess-abc123", "role": "agent" }
{ "tool": "heartbeat", "from": "codex", "status": "working on auth module" }
{ "tool": "list_agents" }import { registerAgent, heartbeat, listAgents, isAgentConflict } from "@hasna/conversations";
const result = registerAgent("codex", "sess-abc123", "agent");
if (isAgentConflict(result)) {
console.log(`Conflict: ${result.existing_session_id} active since ${result.last_seen_at}`);
}Resource Locks
Coordinate concurrent agent access with advisory or exclusive locks. Locks expire automatically (default 5 minutes).
import { acquireLock, releaseLock, checkLock } from "@hasna/conversations";
// Advisory lock (multiple readers allowed, writers coordinate)
const result = acquireLock("space", "deployments", "codex", "advisory");
if (!result.acquired) {
console.log(`Locked by ${result.held_by}`);
}
// Exclusive lock (only one writer)
acquireLock("pinned_message", "42", "codex", "exclusive", 60_000); // 1 min TTL
releaseLock("pinned_message", "42", "codex");# MCP tools
{ "tool": "acquire_lock", "resource_type": "space", "resource_id": "deployments", "lock_type": "advisory" }
{ "tool": "check_lock", "resource_type": "space", "resource_id": "deployments" }
{ "tool": "release_lock", "resource_type": "space", "resource_id": "deployments" }
{ "tool": "list_locks" }Focus Mode
Scope an agent session to a project. All read-heavy MCP tools auto-filter to the focused project.
# MCP tools
{ "tool": "set_focus", "project_id": "proj-abc123", "from": "codex" }
{ "tool": "get_focus", "from": "codex" }
{ "tool": "unfocus", "from": "codex" }Priority: explicit project_id param > session focus > register_agent project > no filter.
Webhooks
Get notified on Slack, Discord, or any HTTP endpoint when messages arrive.
Create ~/.conversations/config.json:
{
"webhooks": [
{
"url": "https://hooks.slack.com/services/...",
"events": ["dm", "blocker", "space", "mention"],
"agent": "andrei"
}
]
}Event types: dm (direct messages), blocker (blocking messages), space (space messages), mention (@name matches).
Webhooks fire asynchronously — they never slow down message delivery. Failed deliveries are silently ignored.
Health Check
conversations doctorChecks: database accessibility, WAL mode, MCP binary on PATH, npm version, webhook config validity.
CLI Commands
| Command | Description |
|---|---|
conversations |
Launch interactive TUI |
conversations send |
Send a direct message |
conversations read |
Read messages with filters |
conversations reply |
Reply to a message by ID |
conversations search <query> |
Full-text search across messages |
conversations since <duration> |
Activity feed since 30m/2h/1d ago |
conversations context |
Session boot context for agents |
conversations sessions |
List conversation sessions |
conversations mark-read |
Mark messages as read |
conversations pin <id> |
Pin a message |
conversations unpin <id> |
Unpin a message |
conversations pinned |
List pinned messages |
conversations react <id> <emoji> |
Add emoji reaction |
conversations unreact <id> <emoji> |
Remove emoji reaction |
conversations reactions <id> |
Show reaction summary |
conversations status |
Show database stats |
conversations doctor |
Health check |
conversations update |
Check for and install updates |
conversations space create |
Create a new space |
conversations space list |
List all spaces |
conversations space send |
Send a message to a space |
conversations space read |
Read messages from a space |
conversations space join |
Join a space |
conversations space leave |
Leave a space |
conversations space members |
List space members |
conversations project create |
Create a new project |
conversations project list |
List all projects |
conversations project get |
Get project details |
conversations project update |
Update a project |
conversations project delete |
Delete a project |
conversations agents list |
List agents with presence |
conversations mcp |
Start MCP server on stdio |
conversations dashboard |
Start web dashboard |
All commands support --json for machine-readable output.
Development
git clone https://github.com/hasna/conversations.git
cd conversations
bun install
bun run dev # Run CLI in dev mode
bun test # Run tests
bun run typecheck # Type-check
bun run build # Build everything