npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tomo-ai

v0.8.4

Published

Personal assistant powered by Claude Agent SDK

Readme


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. Authenticate Claude Code for direct Claude models, or configure a LiteLLM gateway for non-Claude 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 (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 or LiteLLM provider/model names) | | /restore | Restore config.json from config.json.bak and restart | | /status | Show session info (model, channel, message count) | | /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:

{
  "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-4-6[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 | |----------|-------------| | 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) |

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