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

agentchannels

v0.2.0

Published

Connect Claude Managed Agents to messaging channels like Slack, Discord, Teams, and more

Readme

Agent Channels

Agent Channels (ach) is a CLI that bridges your communicatino channels, such as Slack, to agents like Claude Managed Agents. Mention the bot in any channel or DM and each thread becomes a multi-turn streaming session with your agent — tools, vaults, and all.

Agent Channels is right for you if

  • ✅ You've built (or want to build) a Claude Managed Agent and need to put it in front of a team
  • ✅ You want to build agents once and provide them across multiple channels
  • ✅ You want to provide your agents to your colleagues through Slack, without building a separate app for them
  • ✅ You don't want to build messy connectors between agents and communication channels yourself
  • ✅ You want multi-turn conversations per thread, not one-shot Q&A bots
  • ✅ You want streaming responses that appear in real time, not 30-second waits for a wall of text

Quick Start

Set up a Claude Managed Agent on Slack in three commands:

# Install
brew install agentchannels/tap/ach

# Set up agent, environment, vault, and Slack app — one interactive wizard
ach init slack

# Start the bot
ach serve

That's it. ach init slack selects or creates your Claude Managed Agent and Environment, optionally links a Vault, configures your Slack app, and writes everything to .env. Then ach serve picks it all up automatically.

Prefer Claude Code? Install the plugin (see Installation below), then run /agentchannels:init-slack and /agentchannels:serve inside Claude Code. Jump to Use from Claude Code for details.

Installation

Install directly into Claude Code — no git clone needed:

claude plugin marketplace add agentchannels/agentchannels
claude plugin install agentchannels@agentchannels

Then use /agentchannels:init-slack and /agentchannels:serve inside Claude Code. See Use from Claude Code for what each skill does.

To update: claude plugin update agentchannels@agentchannels

brew install agentchannels/tap/ach
npm install -g agentchannels

Requires Node.js >= 18.

npx agentchannels init slack
npx agentchannels serve

Requires Node.js >= 18.

git clone https://github.com/anthropics/agentchannels.git
cd agentchannels
pnpm install && pnpm build
pnpm link --global

Prerequisites

  • Anthropic API key with Managed Agents access — console.anthropic.com
  • Slack workspace where you can create apps

Configuration

agentchannels splits its configuration in two:

  • .env holds secrets — your Anthropic API key and Slack tokens.
  • agentchannels.config.ts describes the agent backend — which Claude Managed Agent to talk to, or any other Backend implementation you wire up. The ach init slack wizard generates this file for you.

Environment variables (.env)

| Variable | CLI flag | Description | |---|---|---| | ANTHROPIC_API_KEY | — | Anthropic API key. Read by the generated config file. | | SLACK_BOT_TOKEN | --slack-bot-token | Slack bot token (xoxb-...) | | SLACK_APP_TOKEN | --slack-app-token | Slack app-level token (xapp-...) for Socket Mode | | SLACK_SIGNING_SECRET | --slack-signing-secret | Slack signing secret (optional under Socket Mode) |

Agent config (agentchannels.config.ts)

The wizard scaffolds something like:

import {
  defineConfig,
  ManagedAgentBackend,
  BackendRegistry,
} from "agentchannels";

const registry = new BackendRegistry();

export default defineConfig({
  resolveBackend: (ctx) =>
    registry.resolve(
      ctx.threadKey,
      () =>
        new ManagedAgentBackend({
          clientConfig: { apiKey: process.env.ANTHROPIC_API_KEY ?? "" },
          agentId: "agent_…",
          environmentId: "env_…",
        }),
    ),
});

Pass --config <path> to ach serve to point at a different file.

See Backend interface below for how to plug in a custom Backend (e.g. a local Claude CLI process) instead of ManagedAgentBackend.

CLI Reference

ach init slack

Interactive wizard that handles complete setup in one flow:

  1. Anthropic API key — validated up front; invalid keys re-prompt instead of crashing the wizard
  2. Claude Managed Agent — pick from the list, create a new one, or paste an existing agent ID
  3. Environment — pick from the list, create a new one, or paste an existing environment ID
  4. Vaults (optional) — multi-select from the list, paste comma-separated IDs, or skip (provides MCP OAuth credentials to sessions)
  5. Slack app — three modes: automatic (creates the app via the Slack API), guided (walks you through api.slack.com), or manual (paste tokens you already have)

Smart about existing state: if .env still contains legacy CLAUDE_AGENT_ID / CLAUDE_ENVIRONMENT_ID / CLAUDE_VAULT_IDS keys (from older versions), each is validated against the API and offered for reuse. Stale IDs (agent deleted since last run, invalid vault) are flagged and you're re-prompted only for the affected slots. When your account has no agents or environments yet, the wizard jumps straight to the create flow.

The wizard writes Slack tokens and ANTHROPIC_API_KEY to .env, and the chosen agent / environment / vault IDs to agentchannels.config.ts. After running this command, ach serve needs no flags.

Non-interactive mode (CI / scripting):

ach init slack --non-interactive \
  --anthropic-api-key sk-ant-... \
  --claude-agent-id agent_... \
  --claude-environment-id env_... \
  --claude-vault-ids vault_a,vault_b \
  --slack-bot-token xoxb-... \
  --slack-app-token xapp-... \
  --slack-signing-secret ...

Every ID is validated silently. If any required value is missing or invalid, the command exits non-zero and names the failing field.

ach serve

Starts the bot. Loads agentchannels.config.ts (override with --config <path>), connects to Slack via Socket Mode (no public URL needed), listens for @mentions and DMs, calls your resolveBackend(ctx) hook per thread, and streams responses back. Press Ctrl+C to stop.

Use from Claude Code

Once the Claude Code plugin is installed, two slash commands are available. They wrap the CLI but let Claude gather your credentials conversationally — no terminal takeover, no remembering flags.

/agentchannels:init-slack

Walks you through complete setup — agent, environment, vault, and Slack app — in one conversation. The wizard:

  1. Validates your ANTHROPIC_API_KEY first so Slack setup never happens against a broken agent.
  2. Lists your Claude Managed Agents; lets you pick one or create a new one.
  3. Lists your Claude Environments; lets you pick one or create a new one.
  4. Optionally selects a Vault for MCP OAuth credentials.
  5. Handles Slack app creation — Claude asks which path you want:
    • Automatic — you paste a Slack Refresh Token (xoxe-...); Claude runs ach init slack --non-interactive --slack-refresh-token ..., which creates the app via the Slack API and opens your browser for workspace install.
    • Manual — you already have bot token, app token, and signing secret; Claude passes them as inline env vars to ach init slack --non-interactive so they don't appear in ps.

Writes all IDs and credentials to .env on success.

/agentchannels:serve

Verifies CLAUDE_AGENT_ID and CLAUDE_ENVIRONMENT_ID are set, then launches ach serve in the background so the bridge keeps running while you keep using Claude Code. Claude can check whether the process is still alive via ps.

Prereq: Make sure you've run /agentchannels:init-slack first — it creates your Claude Managed Agent, Environment, and Slack credentials in one flow and writes all IDs to .env.

How the skills work under the hood

The plugin ships two SKILL.md files that instruct Claude to (1) gather credentials using AskUserQuestion, then (2) invoke the existing CLI via Bash with --non-interactive. There is no MCP server — the skills are thin glue over the CLI, so every CLI flag and env var is usable from Claude Code too.

Deploy

Railway

ach deploy railway

Interactive wizard that creates a project, pushes your env vars, and deploys the Docker image. Requires a Railway API token.

Docker

docker run -d \
  --env-file .env \
  ghcr.io/agentchannels/agentchannels:latest

Other platforms

agentchannels uses Socket Mode (WebSocket), so it works anywhere that runs persistent processes — Fly.io, Render, any VPS. Not recommended for serverless (Lambda, Vercel) since agent responses can take 30+ seconds.

Backend interface

agentchannels is library-firstach serve is a thin wrapper around an extension point you can target from your own code. The core abstraction is Backend: one instance per thread, streaming agent responses as AgentStreamEvents.

interface Backend {
  sendMessage(text: string, opts?: { signal?: AbortSignal }): AsyncIterable<AgentStreamEvent>;
  abort(): void;
  dispose?(): Promise<void> | void;
  isTransient?(error: unknown): boolean;
}

Required vs. optional events

The streaming bridge consumes a discriminated union of events. Only three are required; the rest unlock richer Slack UI when your backend can produce them:

| Event | Required? | What it drives | |---|---|---| | text_delta | ✅ | Streamed message body | | done | ✅ | Closes the streaming response | | error | ✅ | Surfaces a user-visible error | | thinking | optional | "Thinking…" task indicator | | tool_use | optional | Plan-mode task entry per tool call | | tool_result | optional | Marks the matching task complete | | status | optional | Observability only |

A text-only backend works on day one; you can add tool tracking later without touching agentchannels.

Worked example: a custom Backend

This sketch is what a sibling project (e.g. aweek) might ship to bridge a Slack thread to a local Claude CLI session:

// my-cli-backend.ts
import type { Backend, AgentStreamEvent } from "agentchannels";
import { spawn, type ChildProcess } from "node:child_process";

export interface MyCliBackendOptions {
  cwd: string;
  agentSlug: string;
}

export class MyCliBackend implements Backend {
  private current?: ChildProcess;

  constructor(private readonly opts: MyCliBackendOptions) {}

  async *sendMessage(text: string, { signal }: { signal?: AbortSignal } = {}): AsyncIterable<AgentStreamEvent> {
    const proc = spawn("claude", ["--cwd", this.opts.cwd, "--agent", this.opts.agentSlug], {
      stdio: ["pipe", "pipe", "pipe"],
    });
    this.current = proc;
    signal?.addEventListener("abort", () => proc.kill("SIGTERM"));

    proc.stdin.end(text);

    for await (const chunk of proc.stdout) {
      yield { type: "text_delta", text: String(chunk) };
    }
    yield { type: "done" };
  }

  abort(): void {
    this.current?.kill("SIGTERM");
  }

  isTransient(err: unknown): boolean {
    return /ECONNRESET|EPIPE/.test(String(err));
  }
}

Wire it into agentchannels.config.ts:

import { defineConfig, BackendRegistry } from "agentchannels";
import { MyCliBackend } from "./my-cli-backend.js";

const registry = new BackendRegistry({ ttlMs: 30 * 60_000 });

export default defineConfig({
  resolveBackend: (ctx) =>
    registry.resolve(ctx.threadKey, () =>
      new MyCliBackend({
        cwd: process.cwd(),
        agentSlug: ctx.channelId, // or whatever your routing logic decides
      }),
    ),
});

Run ach serve against this config and every Slack thread streams from your CLI process instead of a managed agent — no agentchannels code changes required.

BackendRegistry and withRetry

agentchannels stays stateless across messages: every inbound message calls resolveBackend again, so consumers own the per-thread cache. BackendRegistry is a small reference helper for the common case (Map<threadKey, Backend> with optional TTL eviction). For transient-error retries before the first event lands, the bridge wraps your backend with withRetry, which respects Backend.isTransient(err) to decide what to retry.

How It Works

     ┌─────────────────┐      ┌──────────────────────┐      ┌────────────────────┐
     │                 │      │                      │      │                    │
     │   Slack thread  │◀────▶│   ach serve (you)    │◀────▶│   Backend (any     │
     │                 │      │                      │      │    impl you wire)  │
     │  @mention       │      │  Socket Mode         │      │                    │
     │  reply in       │─────▶│  listener +          │─────▶│  ManagedAgentBackend
     │    thread       │      │  streaming bridge    │      │  | LocalCliBackend │
     │                 │◀─────│                      │◀─────│  | …               │
     │  user @mention  │      │  channel-agnostic    │      │                    │
     │                 │      │  adapter             │      │                    │
     └─────────────────┘      └──────────────────────┘      └────────────────────┘
        WebSocket                 long-lived Node                 your agent of choice
        (no public URL)           process (your host)             (managed, CLI, etc.)
  1. A teammate @mentions the bot in Slack — Slack pushes the event over the Socket Mode WebSocket.
  2. ach serve calls your resolveBackend(ctx) hook; a BackendRegistry returns the cached Backend for that thread (or creates one).
  3. The bridge iterates backend.sendMessage(text) — each text_delta/tool_use/tool_result event becomes a Slack stream update.
  4. done closes the response; error surfaces with the formatter from your config.

License

Apache 2.0