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

@mager/acp

v0.2.0

Published

Agent Context Protocol — TUI-enabled SDK for agent teams

Readme

ACP — Agent Context Protocol

Build agent teams. Not chatbot pipelines.

@mager/acp is a lightweight SDK for wiring multiple AI agents together — each with a clear domain, passing full context between them. Now with a rich TUI for interactive agent chat.

What's New: TUI Mode 🖥️

The SDK now includes a full terminal UI built with Ink (React for terminals). Watch your agents think, hand off, and collaborate in real-time.

# Run the interactive TUI
ANTHROPIC_API_KEY=your_key npx acp

# Or with specific agents
ANTHROPIC_API_KEY=your_key npx acp --agents=magerbot,genny,franklin

ACP TUI Demo

TUI Features

  • Live Agent Status — See which agent is thinking, idle, or handing off
  • Handoff Visualization — Watch context pass between agents with visual indicators
  • ACP Context Panel — Inspect the full context envelope at any handoff (press H)
  • Message Navigation — Scroll through conversation history with arrow keys
  • Session Management — Reset with Ctrl+R, quit with Esc

The Idea

One agent can't do everything well. But three specialized agents that actually talk to each other can.

┌─────────┐     ACP Context Envelope      ┌─────────┐
│         │ ─────────────────────────────→│         │
│magerbot │  identity, state, memory,     │  genny  │
│  ⚡      │  intent — nothing lost        │  🌿     │
│         │←──────────────────────────────│         │
└─────────┘                               └─────────┘
   ↓                                           ↓
code/ops                                health/life

Zero re-briefing. Zero context loss. The second agent knows everything the first one did.

Quick Start

1. Install

npm install @mager/acp

2. Run the TUI

export ANTHROPIC_API_KEY=your_key
npx acp

3. Or use the SDK programmatically

import { ACPAgent, ACPMessage } from "@mager/acp";
import Anthropic from "@anthropic-ai/sdk";

const claude = new Anthropic();

class ResearchAgent extends ACPAgent {
  constructor() {
    super({
      id: "researcher",
      capabilities: ["search", "analyze", "summarize"],
      systemPrompt: "You are a research agent. Be thorough.",
    });
  }

  async handle(ctx: ACPMessage): Promise<string> {
    const { intent, state, identity } = ctx;
    // Full context available: who sent it, session state, memory
    const response = await claude.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 500,
      system: this.systemPrompt,
      messages: [{ role: "user", content: `Research: ${intent.target}` }],
    });
    return response.content[0].type === "text" ? response.content[0].text : "";
  }
}

Wire Two Agents Together

class WriterAgent extends ACPAgent {
  constructor() {
    super({ id: "writer", capabilities: ["write", "edit"] });
  }

  async handle(ctx: ACPMessage): Promise<string> {
    const { intent, state, identity } = ctx;
    // Writer gets FULL context from researcher
    const response = await claude.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 400,
      messages: [{
        role: "user",
        content: `Write a summary about "${intent.target}".
Research: ${JSON.stringify(intent.payload)}
Confidence: ${state.metadata?.confidence}
Handed off by: ${identity.agent_id}`,
      }],
    });
    return response.content[0].type === "text" ? response.content[0].text : "";
  }
}

const writer = new WriterAgent();
const researcher = new ResearchAgent();

// Delegate with full context
const result = await researcher.delegate(writer, {
  action: "write_summary",
  target: "the Agent Context Protocol",
  payload: { key_finding: "context dies at the boundary without ACP" },
}, {
  current_task: "research_complete",
  metadata: { confidence: 0.92, sources_checked: 8 },
});

The ACP Envelope

Every handoff carries four things:

| Field | What it carries | |-------|----------------| | identity | Who sent this? What can they do? | | state | Session ID, turn count, current task, custom metadata | | memory | Long-term facts and preferences | | intent | Action, target, constraints, payload |

{
  "acp_version": "0.2.0",
  "identity": { "agent_id": "magerbot", "capabilities": ["code", "ops"] },
  "state": { 
    "session_id": "sess_abc123", 
    "turn_count": 3, 
    "current_task": "research_complete",
    "metadata": { "confidence": 0.92 } 
  },
  "memory": { "retrieved": [{ "key": "user_timezone", "value": "America/Chicago" }] },
  "intent": { 
    "action": "plan_trip_health_protocol", 
    "target": "japan_2026", 
    "payload": { "cities": ["Tokyo", "Kyoto"] }
  }
}

TUI Keyboard Shortcuts

| Key | Action | |-----|--------| | Enter | Send message | | ↑/↓ | Navigate message history | | H | Toggle ACP context panel | | ? | Show/hide help | | Ctrl+R | Reset session | | Esc | Close panel / Quit |

Real-World Example: magerbot + genny

The reference implementation — two real agents that run my personal stack:

git clone https://github.com/mager/acp
cd acp && npm install

# Run the TUI with the real agent team
ANTHROPIC_API_KEY=your_key npx acp --agents=magerbot,genny

# Or run the programmatic example
ANTHROPIC_API_KEY=your_key npx ts-node examples/magerbot-genny/index.ts

Programmatic TUI

Build your own TUI by importing the components:

import React from "react";
import { render } from "ink";
import { App, ACPAgentRunner } from "@mager/acp";

const MyApp = () => {
  const runner = new ACPAgentRunner(["researcher", "writer"]);
  
  return <App agents={["researcher", "writer"]} />;
};

render(<MyApp />);

API

new ACPAgent(options)

| Option | Type | Description | |--------|------|-------------| | id | string | Unique agent identifier | | capabilities | string[] | What this agent can do | | vendor | string? | Optional org/team name | | systemPrompt | string? | System prompt for the agent |

agent.handle(ctx: ACPMessage): Promise<string>

Override this. Receives the full ACP context. Return a string.

agent.createContext(intent, state?, memory?)

Build an ACP message to send to another agent.

agent.delegate(target, intent, state?, memory?)

Pass an ACPAgent instance or handler function. Builds context, calls target.handle(ctx) automatically.

new ACPAgentRunner(agentIds: string[])

Create a runner that orchestrates multiple agents with real-time TUI updates.

ACPAgentRunner.process(input, callbacks)

Process user input through the agent team. Callbacks receive real-time updates:

  • onAgentStart(agentId) — Agent started thinking
  • onAgentHandoff(from, to, context) — Context passed between agents
  • onAgentComplete(agentId, response, acpContext) — Agent finished

Why Not MCP?

  • MCP is for connecting agents to tools (databases, APIs, functions)
  • ACP is for connecting agents to agents (full context, state, identity, intent)
  • They're complementary — use both

Changelog

v0.2.0 — TUI Release

  • ✨ Full terminal UI with Ink/React
  • ✨ Real-time agent status visualization
  • ✨ Interactive ACP context inspector
  • ✨ Streaming Claude responses
  • ✨ CLI entry point: npx acp

v0.1.0 — Initial Release

  • Core ACPAgent class
  • Context envelope (identity, state, memory, intent)
  • Basic delegation pattern
  • magerbot + genny reference implementation

Roadmap

  • [x] TypeScript SDK
  • [x] handle() + delegate() agent pattern
  • [x] Basic two-agent example
  • [x] magerbot + genny reference implementation
  • [x] TUI with Ink/React ← You are here
  • [x] Streaming responses
  • [x] CLI entry point
  • [ ] HTTP transport helpers (call agents across services)
  • [ ] Python port
  • [ ] JSON Schema spec
  • [ ] Agent registry (discover agents by capability)

License

MIT — mager