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

@choonkeat/agent-chat

v0.12.0

Published

A "less intimidating" chat UI for any agent

Readme

Agent Chat

An MCP server that gives your AI agent a rich chat interface. Instead of reading raw tool calls in a terminal, your users get a rendered conversation with markdown, code blocks, quick reply buttons, and voice support.

This is the MCP that powers the Agent Chat tab in swe-swe.

Same conversation, two views. The terminal shows MCP tool calls and code diffs. Agent Chat renders the same content as a rich, interactive chat.

Features

  • Rich markdown — messages render with full markdown, syntax-highlighted code blocks, and blockquotes
  • File drag & drop — drop files into the chat to share them with the agent
  • Images in messages — agents can include screenshots and images inline
  • Voice conversation — speak to your agent and hear responses via text-to-speech
  • Quick replies — agents can offer clickable response buttons for common actions
  • Permission prompts in chat — when Claude Code is launched with --dangerously-load-development-channels server:swe-swe-agent-chat, tool-use permission prompts are intercepted from stdin and surfaced as Allow/Deny quick replies in the chat UI (and spoken aloud in voice mode), instead of blocking on a TUI prompt

How it works

Agent Chat runs as an MCP server alongside your AI agent. The agent calls tools like send_message, send_progress, and check_messages to communicate with the user through a browser-based chat UI.

Agent (Claude, etc.)
  │
  ├─ send_message("Here's what I found...")  →  Chat UI shows rich message
  ├─ send_progress("Working on it...")       →  Chat UI shows progress indicator
  └─ check_messages()                        ←  Chat UI returns user's reply

MCP Tools

| Tool | Description | |------|-------------| | send_message | Send a message and wait for user response. Supports quick reply buttons. | | send_verbal_reply | Send a spoken reply in voice mode (text-to-speech). | | send_progress | Send a non-blocking progress update. | | send_verbal_progress | Send a non-blocking spoken progress update. | | check_messages | Non-blocking check for queued user messages. | | set_chat_title | Name the streaming chat-log export (see below): renames the auto-written …-untitled.md to …-{slugified-title}.md and rewrites its header. Call again anytime to rename; also re-enables the export after chatlog_optout. | | chatlog_close | Close out the streaming chat-log export for a clean git commit: freezes this session's .md (kept, unlike chatlog_optout), regenerates index.html, and returns the exact paths to git add. Requires a title while the file is still untitled; never renames an already-titled file. set_chat_title re-opens with a full-history backfill. | | chatlog_optout | Stop the streaming chat-log export for this session and delete its .md (assets are left — content-sha names may be shared; index.html regenerated). | | export_chat_md | Manually export the current chat as a markdown file (script-style **USER** / **AGENT** markers that render as iMessage-style left/right bubbles via a sibling index.html and as a normal markdown doc on GitHub/GitLab). Writes ./agent-chats/YYYY-MM-DD-NN-{title}.md, copies attachments to ./agent-chats/assets/, refreshes viewer.css / viewer.js, and regenerates the chat-archive index.html. The manual escape hatch when the streaming export (below) is enabled. |

Chat commands

Typed by the user in the chat input, handled by the browser — these never reach the agent as messages. They need agent-chat to be running inside a host that owns the agent's terminal (swe-swe); standalone, they report that and do nothing.

| Command | Effect | |---------|--------| | stop (also wait, cancel, hold on, abort, halt, pause) | Interrupts the agent's current turn and nudges it to check_messages. | | /clear-and-then <instruction> | Resets the agent's context, then hands it <instruction>. The message is recorded as typed — command and all — in the chat and the streaming chat log, so a log read later shows where the agent was reset; the agent itself is handed only <instruction>, from the message queue. It comes back with a line naming the log file as its context, so the conversation survives the reset even though the agent's own memory does not. A bare /clear resets with no follow-up instruction, and is recorded too. Requires the streaming export (below); without it the reset still happens but the earlier conversation is gone. See docs/adr/2026-08-02-clear-prefix-context-reset.md. | | /compact-and-then <instruction> | Same sequence as /clear-and-then, but the agent summarises its context instead of losing it. Recorded the same way; the agent is woken with the ordinary nudge once the summary has had time to finish — there is no chat-log resume line, because the summary is the context. A bare /compact summarises with no follow-up instruction. | | / at the start of a message | Offers the four commands above, ahead of whatever the / autocomplete provider (if any) returns. Elsewhere in a message / means whatever the provider says, or nothing. | | clear contextyes | The older confirm-then-reset flow. Resets only; nothing is handed back. |

Streaming chat-log export

Set AGENT_CHAT_EXPORT_DIR (e.g. agent-chats, resolved relative to the working directory — it cannot escape it) and the markdown archive writes itself, no export_chat_md call needed:

  • Every chat bubble is appended to {date}-{NN}-untitled.md the moment it happens ({date}-{NN}-untitled-{SESSION_UUID}.md when a SESSION_UUID env var identifies the host session), and its attachments are copied into the assets/ directory beside it at that same moment (content-sha filenames), while the upload files still exist.

  • Month directories are understood everywhere, and written only on request. A chat can live flat in the archive root, or one directory per month:

    agent-chats/
      index.html                     ← landing page, always at the root
      assets/viewer.css, viewer.js   ← one copy for the whole archive
      2026-08-15-01-some-title.md    ← flat (the default)
      assets/2026-08-15-01-1-{sha}.png
      2026-08/                       ← month layout
        15-01-another-title.md
        assets/2026-08-15-01-2-{sha}.png

    Listing, session resume and daily NN numbering all read both shapes, so a mixed archive is correct. New exports go flat unless you pass -chatlog-layout=month (or set AGENT_CHAT_CHATLOG_LAYOUT=month) — the default flips to month in a later release, once installed copies have caught up: an older copy regenerating index.html drops every file it cannot see, and it cannot see month directories.

  • agent-chat migrate-chatlogs files an existing flat archive by month — it prints the git mv lines, and -apply runs them and regenerates index.html. Attachments keep their full-date basenames and are routed by what the markdown links to, so migrating rewrites no file content and a chat's ./assets/… links resolve identically on GitHub and in the viewer.

  • The agent names the file via set_chat_title (renames + header rewrite; callable again to rename). chatlog_optout stops the export for the session and deletes its .md.

  • To commit the archive without it going dirty on the next reply, the agent calls chatlog_close (optionally titling in the same call), which freezes the .md and returns the exact paths to git add. Freezing loses nothing: the JSONL event log keeps recording, and set_chat_title re-opens the export with a full-history rewrite that backfills anything that arrived while frozen.

  • index.html — the archive landing page — is regenerated from the .md files on disk, never patched incrementally. That makes it merge-friendly: on a git conflict in index.html, accept either side (or delete the file); the next export regenerates it correctly. Duplicate daily NNs from parallel branches are fine — the regenerated index lists both, and content-sha asset names never clobber.

  • index.html is a tracked file, so it is only rewritten when the export set changes in a committable way: chatlog_close, chatlog_optout, export_chat_md, or a set_chat_title that renames an export already in the manifest. Streaming appends never touch it, and still-untitled exports are never listed — otherwise every live session would leave the working tree dirty with links to untracked files that set_chat_title is about to rename.

  • The header comment carries a session: line, so a restarted process (same AGENT_CHAT_EVENT_LOG) resumes appending to its own file instead of minting a new one.

  • Nothing is ever auto-committed — the export sits in the working tree.

Installation

Add as an MCP server to Claude Code:

claude mcp add agent-chat -- npx -y @choonkeat/agent-chat

Or run standalone (HTTP-only mode):

npx -y @choonkeat/agent-chat --no-stdio-mcp

The chat UI opens automatically in your browser.

Environment variables

| Variable | Description | |----------|-------------| | AGENT_CHAT_PORT | Fixed port for the HTTP server (default: random) | | AGENT_CHAT_EVENT_LOG | Path to a JSONL file for event persistence across restarts | | AGENT_CHAT_EXPORT_DIR | Directory (relative to cwd) for the streaming markdown chat-log export; unset = disabled | | AGENT_CHAT_DISABLE | Set to any value to disable tools and HTTP server |

License

MIT