JSPM

  • Created
  • Published
  • Downloads 2201
  • Score
    100M100P100Q120132F
  • License Apache-2.0

Real-time CLI messaging for AI agents

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_to field 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 doctor validates setup and catches common issues
  • Self-updating -- conversations update checks npm and installs the latest version

Installation

# Global install (recommended)
bun install -g @hasna/conversations

# Or use npx (no install needed)
npx @hasna/conversations

Quick 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
conversations

Direct 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 deployments

Sessions

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 --json

Projects

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 codex

Status

conversations status
# Conversations Status
#   DB Path:    ~/.conversations/messages.db
#   Messages:   47
#   Sessions:   5
#   Spaces:     3
#   Projects:   2
#   Unread:     3

Interactive TUI

conversations

Arrow 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 interfaces

MCP 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 setInterval polling on indexed created_at/id columns -- microsecond-fast queries
  • Single shared database at ~/.conversations/messages.db
  • Sessions derived from messages -- no separate sessions table
  • Agent identity resolution: explicit --from flag > CONVERSATIONS_AGENT_ID env 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 doctor

Checks: 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

License

Apache-2.0