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

openwren

v2026.3.11

Published

Self-hosted personal AI assistant bot with multi-channel support (Telegram, Discord, WebSocket)

Readme

Open Wren

A self-hosted personal AI assistant bot you control via messaging apps. Runs locally, connects to Anthropic Claude, and acts on your behalf — reading files, running whitelisted shell commands, maintaining persistent memory across sessions.

Multiple agents with distinct personalities (Atlas, Einstein, Wizard, Coach). Each agent gets its own bot per channel, isolated conversation history, and a plain-text soul file you can edit without touching code.


Features

  • Multi-agent — run several AI personalities simultaneously, each with its own soul file and session history
  • Multi-channel — Telegram, Discord (DM-only), and WebSocket for CLI/Web UI
  • Persistent memory — agents save facts to markdown files that survive session resets and restarts
  • Session compaction — long conversations are summarized automatically; originals are archived
  • Persistent shell approval — approve shell commands once per agent, stored in exec-approvals.json
  • CLI management — start, stop, restart, tail logs, and chat interactively from your terminal
  • Scheduled tasks — cron jobs, interval timers, and one-shot reminders. Agents can create schedules on your behalf
  • Heartbeat — periodic agent check-ins with smart suppression (silent when nothing to report)
  • Zero code changes to add agents — create a soul file and add config keys, that's it

Prerequisites


Install & Setup

npm install -g openwren
openwren init

This creates ~/.openwren/ with template config and .env files. Then:

1. Add your secrets to ~/.openwren/.env:

ANTHROPIC_API_KEY=sk-ant-...
OWNER_TELEGRAM_ID=123456789        # your Telegram numeric user ID
TELEGRAM_BOT_TOKEN=123:ABC...      # from BotFather

2. Edit ~/.openwren/openwren.json:

{
  "providers.anthropic.apiKey": "${env:ANTHROPIC_API_KEY}",
  "users.owner.displayName": "Your Name",
  "users.owner.channelIds.telegram": "${env:OWNER_TELEGRAM_ID}",
  "bindings.telegram.atlas": "${env:TELEGRAM_BOT_TOKEN}",
}

3. Start the bot:

openwren start

Message your Telegram bot — Atlas responds.


CLI Commands

| Command | What it does | |---|---| | openwren init | Create ~/.openwren/ with template config, .env, and default Atlas soul file | | openwren start | Start the bot as a background daemon | | openwren stop | Stop the daemon | | openwren restart | Stop + start | | openwren status | Show agents, channels, and uptime | | openwren logs | Tail the daemon log file | | openwren chat [agent] | Interactive terminal chat via WebSocket |

For development, run in the foreground instead:

npm run dev

Configuration

All config lives in ~/.openwren/:

~/.openwren/
├── openwren.json     # User config — safe to share publicly
├── .env              # Secrets — never share this
├── agents/
│   └── atlas/
│       ├── soul.md   # Atlas personality and instructions
│       └── skills/   # Per-agent skills (Atlas only)
├── skills/           # Global skills (all agents)
├── memory/           # Persistent memory files
└── sessions/         # Conversation history (per user, per agent)

openwren.json uses JSON5 (comments and trailing commas allowed) with flat dot-notation keys:

{
  // Model selection — "provider/model" format
  "defaultModel": "anthropic/claude-sonnet-4-6",
  "defaultFallback": "anthropic/claude-haiku-3-5",

  // Per-agent model override
  "agents.einstein.model": "anthropic/claude-opus-4-6",

  // Timezone for session timestamps
  "timezone": "America/New_York",

  // WebSocket token for CLI chat and status commands
  "gateway.wsToken": "${env:WS_TOKEN}",

  // Web search (Brave, Zenserp, SearXNG, etc.)
  "search.provider": "brave",
  "search.brave.apiKey": "${env:SEARCH_API_KEY}",
}

Secrets are never written directly into openwren.json. Use ${env:VAR_NAME} — the value is resolved from ~/.openwren/.env at startup.


Adding Agents

No code changes required. Create a soul file and add bindings:

1. Create ~/.openwren/agents/wizard/soul.md:

You are Wizard, a wise and mystical assistant who speaks with ancient wisdom.
You enjoy using metaphors and occasionally reference arcane knowledge.

2. Add to openwren.json:

{
  "bindings.telegram.wizard": "${env:WIZARD_TELEGRAM_TOKEN}",
}

3. Add WIZARD_TELEGRAM_TOKEN to .env and restart.

That's it. Wizard now has his own Telegram bot, isolated session history, and shared access to the memory and tool system.


Skills

Skills are markdown files that teach agents when and how to use capabilities. They use a two-stage loading model — the agent sees a lightweight catalog at session start and loads full instructions on demand.

Bundled skills ship with Open Wren:

| Skill | Type | Gate | |---|---|---| | memory-management | autoloaded | none | | file-operations | autoloaded | none | | web-search | on-demand | search.provider config key | | web-fetch | on-demand | none | | agent-browser | on-demand | agent-browser binary |

Autoloaded skills inject into every prompt automatically. On-demand skills appear in a catalog — the agent calls load_skill to activate them when relevant.

Custom skills

Create a SKILL.md in any of these locations:

~/.openwren/skills/my-skill/SKILL.md              # global — all agents see it
~/.openwren/agents/atlas/skills/my-skill/SKILL.md  # per-agent — only Atlas

SKILL.md format:

---
name: my-skill
description: What this skill does and when to use it.
---

Instructions the agent receives when it activates this skill.

Optional frontmatter fields: autoload: true (inject into every prompt), requires.env: [VAR_NAME, ...] (env vars that must be set), requires.bins: [binary, ...] (binaries that must be on PATH), requires.config: [key.path, ...] (config keys that must be set), requires.os: darwin|linux|win32, enabled: false.

Skills config

{
  // Only allow specific bundled skills (omit to allow all):
  "skills.allowBundled": ["memory-management", "file-operations"],

  // Disable a specific skill:
  "skills.entries.web-fetch.enabled": false,

  // Load skills from additional directories:
  "skills.load.extraDirs": ["~/my-shared-skills"],
}

Per-agent skills override global skills with the same name. Global skills override bundled skills.


Web Research

Agents can search the web and fetch URLs. Search uses a provider abstraction — swap backends via config without changing code.

Search setup (Brave)

  1. Get a free API key at brave.com/search/api (2,000 queries/month free)
  2. Add the key to ~/.openwren/.env:
    SEARCH_API_KEY=your_key_here
  3. Enable in ~/.openwren/openwren.json:
    {
      "search.provider": "brave",
      "search.brave.apiKey": "${env:SEARCH_API_KEY}",
    }

The web-search skill activates automatically when search.provider is set. Agents get a search_web tool for live web searches.

Fetch

The fetch_url tool is always available — no config needed. Agents can fetch any URL, and the content is extracted using readability (navigation, ads, and sidebars are stripped). Results are truncated to ~40K characters to prevent context window overflow.

Browser (optional)

For pages that need JavaScript rendering, install agent-browser and it becomes available via the agent-browser skill. Agents control it through shell commands (agent-browser open, snapshot, click, fill, scroll).


Scheduled Tasks

Agents can run tasks on a schedule — morning briefings, recurring reminders, one-shot alerts. Three schedule types:

  • Cron0 8 * * 1-5 (weekdays at 8am), 0 */2 * * * (every 2 hours)
  • Interval30m, 2h, 1d (simple repeating timer)
  • One-shot2026-03-15T09:00:00 (fires once, auto-disables)

Create schedules three ways:

  • Ask your agent — "remind me to drink water every 2 hours"
  • CLIopenwren schedule create (interactive prompts)
  • REST APIPOST /api/schedules (for automation)

Manage via CLI: openwren schedule list, enable, disable, delete, run, history.

Heartbeat

A periodic check-in where agents read a checklist and only message you if something matters. Create ~/.openwren/agents/atlas/heartbeat.md with your checklist, then enable in config:

{
  "heartbeat.enabled": true,
  "heartbeat.every": "30m",
  "heartbeat.activeHours.start": "08:00",
  "heartbeat.activeHours.end": "22:00",
}

If the agent has nothing to report, it stays silent (HEARTBEAT_OK suppression).


Security

Open Wren treats all inbound web content as potentially adversarial. Three layers of defense protect agents from prompt injection:

  1. Pattern detection — known jailbreak phrases ("ignore previous instructions", "you are now a", etc.) are detected and blocked before reaching the LLM. Suspicious but ambiguous patterns are logged for review but not blocked.

  2. Untrusted content delimiters — all web content (fetched pages, search snippets) is wrapped in [BEGIN UNTRUSTED WEB CONTENT]...[END UNTRUSTED WEB CONTENT] markers, priming the LLM to treat embedded instructions with skepticism.

  3. LLM judgment — Claude is trained to recognize injection attempts. Combined with the untrusted delimiters, even novel injection attempts that bypass pattern detection are reliably rejected.

Additional security measures:

  • Gateway binds to 127.0.0.1 only — not exposed to the network
  • WebSocket auth via constant-time token comparison
  • File operations sandboxed to the workspace directory
  • Shell commands restricted to a whitelist (agents can call list_shell_commands to see what's allowed)
  • All secrets stay in ~/.openwren/.env, never in config files

Discord Setup

Before running a Discord bot, enable Message Content Intent in the Discord Developer Portal:

  1. Go to discord.com/developers/applications
  2. Select your app → Bot
  3. Under Privileged Gateway Intents, enable Message Content Intent
  4. Save

Without this, the bot receives no message text.

Add the bot token to your config:

{
  "bindings.discord.atlas": "${env:DISCORD_BOT_TOKEN}",
}

Discord bots respond to DMs only.


License

MIT © Nermin Bajagilovic / Reimagined Works AB