npm.io
0.8.8 • Published 10h agoCLI

tomo-ai

Licence
MIT
Version
0.8.8
Deps
9
Size
1.4 MB
Vulns
0
Weekly
0
Stars
5
Install scriptsThis package runs scripts during installation (preinstall/install/postinstall)

Tomo

A personal AI assistant that lives in your messaging apps.

npm version license CI

Powered by Claude Agent SDK · Personality system · Persistent memory · Scheduled tasks · Telegram · iMessage


Quick Start

npm install -g tomo-ai
tomo init       # Set up config, pick a name and personality
tomo start      # Runs in background

That's it. Open Telegram and message your bot.

Requirements

  • Node.js 22.12+
  • Claude Code installed. Direct Claude models can use a Claude subscription or an Anthropic API key; LiteLLM gateways support other backends.
  • At least one channel:
    • Telegram — bot token from @BotFather
    • iMessageBlueBubbles server running on a Mac with iMessage signed in

CLI

tomo init              # First-time setup
tomo config            # Interactive settings (authentication, model, LiteLLM, channels, identities, groups)
tomo start             # Start in background (daemon)
tomo start -f          # Start in foreground (for dev)
tomo stop              # Stop the daemon
tomo restart           # Restart the daemon
tomo status            # Show PID and uptime
tomo logs              # View logs (pretty-printed)
tomo logs -f           # Follow logs live
tomo sessions list     # Show active sessions
tomo sessions clear    # Reset all sessions

Chat Commands

Command Description
/new Start a new conversation (resets session)
/model Switch model (Claude aliases, direct model IDs, or LiteLLM provider/model names)
/restore Restore config.json from config.json.bak and restart
/login Refresh Claude login from a configured owner's private DM
/status Show session info (model, channel, message count)
/cost Show current-session cost for 1d / 7d / 1mo
/pet Check Tomo's pet's mood, growth stage, and stats

Features

Personality

Three markdown files define who your assistant is, all customizable:

File Purpose
SOUL.md Core personality, values, communication style
AGENT.md Operating rules, response format, behavior
IDENTITY.md Name, vibe, preferences, quirks

During tomo init, you choose a name, your preferred name, and a tone (chill / sharp / warm). These get baked into the templates. Edit them anytime — changes take effect on the next message, no restart needed.

Memory

File-based persistent memory at ~/.tomo/workspace/memory/. The MEMORY.md index is injected into every conversation. Tomo reads and writes memory files autonomously — it remembers who you are, your preferences, and past context across sessions.

Channels
  • Telegram — DM and group chat support
    • Typing indicators with keepalive and error backoff
    • Image/photo support (sends to Claude as vision input)
    • Group chat: defaults to mention-required (only responds when @mentioned or replied to); per-group passive listen mode opt-in via channels.telegram.passiveGroups
    • Markdown rendering with plain-text fallback
  • iMessage — via BlueBubbles
    • DM and group chat support
    • Image attachment support
    • Contact name resolution from Mac contacts
    • Group chat: observes all messages, only responds when relevant (replies NO_REPLY to stay silent)
Multi-Channel Sessions

Talk to Tomo from multiple channels using the same session. Configure identities in tomo config to bind your Telegram and iMessage accounts — Tomo replies on whichever channel you last used (or a fixed default).

  • DM sessions are unified across channels per identity
  • Group chats always get their own isolated session
  • Per-channel allowlists control who can message Tomo
  • Group chats require a secret passphrase to activate (configured in tomo config)
Tools

Tomo has access to Claude's built-in tools:

Tool Capability
Read, Write, Edit File operations
Bash Shell commands
Glob, Grep File search
WebSearch, WebFetch Web access
Agent Subagents for complex tasks
Skill Specialized workflows
TodoWrite Task tracking within a turn
NotebookEdit Edit Jupyter notebooks
send_message (MCP) Proactively send a message to another session/identity
list_sessions (MCP) List active identities and group sessions
External MCP Servers

Add remote or local MCP servers directly to ~/.tomo/config.json under mcpServers. Tomo passes them through to the Claude Agent SDK and, by default, auto-allows all tools from each configured server with mcp__<server>__*.

{
  "mcpServers": {
    "docs": {
      "type": "http",
      "url": "https://code.claude.com/docs/mcp"
    },
    "github": {
      "type": "sse",
      "url": "https://api.example.com/mcp/sse",
      "headers": {
        "Authorization": "Bearer ${GITHUB_TOKEN}"
      }
    },
    "github-copilot": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "oauth": {
        "scopes": ["read:user"],
        "tokenStoreKey": "github-copilot"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "${HOME}/Projects"]
    }
  }
}

Use type: "http" for streamable HTTP, type: "sse" for SSE, or omit type for stdio servers. Environment variables in url, headers, env, and args are expanded at runtime. To restrict auto-approval, set top-level mcpAllowedTools, for example ["mcp__github__list_issues"].

Remote HTTP/SSE servers can also use harness-managed OAuth by adding an oauth block. Tomo discovers the authorization server from the MCP server's RFC 9728 WWW-Authenticate challenge unless authorizationServer is set explicitly, uses authorization-code + PKCE, registers a dynamic client when needed, stores tokens in ~/.tomo/workspace/secrets/mcp-oauth.json with mode 0600, silently refreshes near-expiry tokens, and injects Authorization: Bearer <token> into MCP headers. The agent never sees the tokens.

If browser login is needed, Tomo forwards the authorize URL to your private chat and waits for the localhost callback before starting the agent session.

Scheduled Tasks

Tomo can create scheduled tasks on its own — just ask "remind me in 30 minutes to stretch" or "check the weather every morning at 9am." Supports one-shot reminders, recurring intervals, and cron expressions.

Sessions
  • Multi-turn conversations via Claude Agent SDK session resume
  • Persistent across restarts
  • /new in Telegram to start fresh
  • Unlinked sessions kept for 30 days before cleanup
Logging

Structured logs via pino:

  • Tool call summaries
  • Token usage and cost per message
  • Context window tracking with compaction warnings

Architecture

~/.tomo/
  config.json                 # Channels, identities, model, settings
  tomo.pid                    # PID file (when running)
  workspace/
    SOUL.md                   # Your personality config
    AGENT.md                  # Your operating rules
    IDENTITY.md               # Your identity config
    memory/                   # Persistent memory files
    .claude/skills/           # Agent skills
  data/
    cron/jobs.json            # Scheduled tasks
    sessions/                 # Transcript logs and session registry
  logs/
    tomo.log                  # Daemon logs

Configuration

Run tomo config for interactive setup, or edit ~/.tomo/config.json directly:

{
  "auth": {
    "method": "api-key",
    "apiKey": "sk-ant-..."
  },
  "channels": {
    "telegram": {
      "token": "your-bot-token",
      "allowlist": ["123456789"],
      "passiveGroups": ["-1001234567890"]
    },
    "imessage": { "url": "http://localhost:1234", "password": "...", "allowlist": ["+15551234567"] }
  },
  "identities": [
    {
      "name": "yourname",
      "channels": { "telegram": "123456789", "imessage": "+15551234567" },
      "replyPolicy": "last-active"
    }
  ],
  "model": "claude-sonnet-5[1m]",
  "litellm": {
    "mode": "chatgpt-subscription",
    "baseUrl": "http://localhost:4000",
    "apiKey": "sk-tomo-local"
  },
  "maxTurns": 50,
  "saveInboundImages": true,
  "continuity": true,
  "continuityIntervalMinutes": 55,
  "continuityScript": {
    "path": "~/bin/tomo-continuity.sh",
    "timeoutMs": 30000,
    "maxOutputChars": 8000
  },
  "groupSecret": "tomo-xxxxxxxx",
  "lcm": {
    "nudgeAtPct": 70,
    "nudgeResetPct": 60,
    "groupCompactStyle": "lcm"
  }
}

Environment variables override config file values:

Variable Description
ANTHROPIC_API_KEY Use Anthropic API-key authentication; overrides the authentication stored in config.json
TELEGRAM_BOT_TOKEN Override Telegram token
IMESSAGE_URL Override BlueBubbles URL
IMESSAGE_TYPING_START_DELAY_MS Delay before showing iMessage typing for ordinary turns (default: 1200)
IMESSAGE_PASSIVE_TYPING_START_DELAY_MS Delay before showing iMessage typing for passive iMessage group turns (default: 4000)
CLAUDE_MODEL Override model
TOMO_LITELLM_BASE_URL Route Claude Agent SDK model calls through a LiteLLM proxy
TOMO_LITELLM_API_KEY API key sent to the LiteLLM proxy as ANTHROPIC_API_KEY
TOMO_LITELLM_MODE Optional LiteLLM mode: anthropic-compatible or chatgpt-subscription
TOMO_WORKSPACE Override workspace directory
TOMO_MAX_TURNS Override per-turn tool-use ceiling (default: 50)
TOMO_STEERING Override message steering. Defaults to true; set false to keep mid-turn messages queued.
TOMO_CONTINUITY_INTERVAL_MINUTES Override scheduled continuity heartbeat interval (default: 55, minimum: 1)
TOMO_CONTINUITY_SCRIPT Override the optional continuity script path
TOMO_CONTINUITY_SCRIPT_TIMEOUT_MS Override continuity script timeout (default: 30000)
TOMO_CONTINUITY_SCRIPT_MAX_OUTPUT_CHARS Override continuity script stdout/stderr cap (default: 8000)
LOG_LEVEL Log level (default: debug)
Anthropic Authentication

Direct Claude models use your existing Claude Code subscription login by default. To use Anthropic API billing instead, run tomo config, choose Anthropic authentication, and enter an API key. Tomo stores the selected method under auth in ~/.tomo/config.json and passes the key only to direct Claude Agent SDK child processes. ANTHROPIC_API_KEY remains supported and takes precedence over the saved setting.

Because the config contains channel credentials and may now contain an Anthropic API key, Tomo writes both config.json and config.json.bak with owner-only (0600) permissions.

continuityScript can also be a simple path string, e.g. "continuityScript": "~/bin/tomo-continuity.sh". Relative paths resolve under ~/.tomo; the script runs once per scheduled heartbeat and manual tomo continuity trigger, and its stdout/stderr or failure status is appended to the normal continuity prompt.

Steering

By default, messages you send while Tomo is mid-task are steered into the in-flight turn at the next tool-call boundary — so "stop", "wait", or extra context reaches the model immediately instead of waiting for the current turn to finish. If the turn has no tool calls left, the message runs as its own follow-up turn right after. iMessage fragment settling still applies before injection; system-originated turns (cron, continuity) keep their normal queued behavior. Set "steering": false or TOMO_STEERING=false to keep mid-turn messages queued behind the active turn.

LiteLLM / ChatGPT Subscription Models

Tomo still runs through Claude Agent SDK, but you can point the SDK at a local LiteLLM proxy and select a LiteLLM model name such as chatgpt/gpt-5.5. This keeps Tomo's Claude SDK sessions, memory, workspace, MCP tools, and LCM behavior while LiteLLM translates Anthropic /v1/messages streaming calls to the ChatGPT subscription backend.

# ~/litellm-chatgpt.yaml
environment_variables:
  CHATGPT_DEFAULT_INSTRUCTIONS: >-
    Follow the instructions supplied in this request.

model_list:
  - model_name: chatgpt/gpt-5.5
    model_info:
      mode: responses
    litellm_params:
      model: chatgpt/gpt-5.5

litellm_settings:
  drop_params: true

general_settings:
  master_key: sk-tomo-local
litellm --config ~/litellm-chatgpt.yaml
tomo config   # LiteLLM gateway -> ChatGPT subscription

Then set the default model to chatgpt/gpt-5.5 from tomo config, or use /model chatgpt/gpt-5.5 in a chat. LiteLLM owns the ChatGPT OAuth device flow and token storage; Tomo only sends Anthropic-compatible requests to the local proxy.

If LiteLLM returns System messages are not allowed, use a LiteLLM build that includes ChatGPT system-role normalization. If non-streaming curl checks fail while streaming /v1/messages works, that is still compatible with Tomo because Claude Agent SDK uses streaming.

Development

git clone https://github.com/shuaiyuan17/tomo.git && cd tomo
npm install
npm run dev    # Foreground with hot reload

Contributing

Issues and pull requests welcome at github.com/shuaiyuan17/tomo.

License

MIT

Keywords