agent-message
v0.6.12
Published
Agent Message CLI and local stack launcher for macOS
Readme
Agent Message
npx skills add https://github.com/siisee11/agent-message --skill agent-message-cliInstall the skill above, then ask your coding agent (e.g. Claude Code) to "set up agent-message" — it will handle installation and configuration for you.
npm install -g agent-messageAgent Message is a direct-message stack with three clients:
- HTTP/SSE server (
server/) - Web app (
web/) - CLI (
cli/)
The public deployment is available at https://am.namjaeyoun.com.
Quick Setup
If you want to use the hosted deployment, install the CLI and onboard once:
npm install -g agent-message
agent-message onboard
agent-message upgradeThis creates or logs into your account, saves the CLI profile in ~/.agent-message/config, and sets your username as master.
Authentication now uses account_id; the public username initially defaults to the same value and can be changed later with agent-message username set <username>.
After that, you can use either the web app at https://am.namjaeyoun.com or the CLI:
agent-message ls
agent-message open bob
agent-message send bob "hello"If you want to self-host locally on your machine instead of using the public deployment:
npm install -g agent-message
agent-message start
agent-message config set server_url http://127.0.0.1:45180
agent-message onboardThen open http://127.0.0.1:45788 in your browser.
The important part is that agent-message start only launches the local stack; it does not rewrite existing CLI traffic until you point server_url at http://127.0.0.1:45180.
If multiple people or wrappers are using the same local stack, make sure each CLI is pointed at the same server_url.
Install With npm (macOS)
Install the packaged app from npm on macOS (arm64 and x64).
The installed agent-message command keeps the existing CLI behavior and also adds local stack lifecycle commands:
agent-message start
agent-message status
agent-message stop
agent-message upgradeDefault ports:
- API:
127.0.0.1:45180 - Web:
127.0.0.1:45788
For self-hosted local use, agent-message start creates and uses a local SQLite database by default.
Managed cloud deployments should run the server with DB_DRIVER=postgres and POSTGRES_DSN.
After agent-message start, open http://127.0.0.1:45788 in your browser.
The bundled CLI uses https://am.namjaeyoun.com by default unless you override server_url for self-hosting, which matches the public deployment web app.
Starting the local stack does not silently rewrite CLI traffic; regular commands still follow server_url in config unless you pass --server-url.
The bundled CLI continues to work from the same command:
agent-message onboard
agent-message register alice secret123
agent-message login alice secret123
agent-message username set jay-ui-bot
agent-message config set master jay
agent-message upgrade
agent-message ls
agent-message open bob
agent-message send bob "hello"
agent-message send "status update for master"Port conventions:
8080: source server default (cd server && go run .) and server container port45180: local API port used byagent-message start45788: local web gateway port used byagent-message start,--with-tunnel, and the containerized gateway5173: Vite dev server only
You can override the runtime location and ports when needed:
agent-message start --runtime-dir /tmp/agent-message --api-port 28080 --web-port 28788
agent-message status --runtime-dir /tmp/agent-message --api-port 28080 --web-port 28788
agent-message stop --runtime-dir /tmp/agent-messageWeb Push for installed PWA notifications:
agent-message startautomatically creates and reuses a local VAPID keypair.- The generated config is stored in
<runtime-dir>/web-push.json. - To override it, set
WEB_PUSH_VAPID_PUBLIC_KEY,WEB_PUSH_VAPID_PRIVATE_KEY, and optionallyWEB_PUSH_SUBJECTbeforeagent-message start. - iPhone web push needs the app to be installed from a public HTTPS origin. For local development, use
agent-message start --with-tunnel; otherwise use a deployed HTTPS host.
PWA install:
- Open the deployed web app in Safari on iPhone.
- Use
Share -> Add to Home Screen. - The app now ships with a web app manifest, service worker, and Apple touch icon so it can be installed like a standalone app.
Run From Source
This section covers local development and local production-like testing from a checked-out repository.
To expose the checked-out repository on your PATH as agent-message, run:
npm linkThat symlinks this checkout's npm/bin/agent-message.mjs, so agent-message ... uses your local source tree.
Prerequisites
- Go
1.26+ - Node.js
18+and npm - Docker + Docker Compose (for PostgreSQL compose flow)
Server Quickstart
Option A: Local server with SQLite (default)
cd server
go run .Default server settings:
SERVER_ADDR=:8080DB_DRIVER=sqliteSQLITE_DSN=./agent_message.sqliteUPLOAD_DIR=./uploadsCORS_ALLOWED_ORIGINS=*WEB_PUSH_VAPID_PUBLIC_KEY,WEB_PUSH_VAPID_PRIVATE_KEY,WEB_PUSH_SUBJECTare optional, but required if you want push notifications when runninggo run .directly
Example override:
cd server
DB_DRIVER=sqlite SQLITE_DSN=./dev.sqlite UPLOAD_DIR=./uploads \
WEB_PUSH_VAPID_PUBLIC_KEY=... \
WEB_PUSH_VAPID_PRIVATE_KEY=... \
WEB_PUSH_SUBJECT=mailto:[email protected] \
go run .Local production-like stack (Server + PostgreSQL)
docker compose up --buildThis starts:
postgresonlocalhost:5432serveronlocalhost:8080with:DB_DRIVER=postgresPOSTGRES_DSN=postgres://agent:agent@postgres:5432/agent_message?sslmode=disable
To stop and remove containers:
docker compose downTo also remove persisted DB/uploads volumes:
docker compose down -vHome Server Container Deploy
For a home Mac server, you can run the managed-cloud stack entirely with containers. The gateway image builds web/dist during docker compose build, so you do not need to run npm run build on the host first.
- Copy the example env file and fill in your values:
cp .env.home.example .env.homeRequired values:
APP_HOSTNAMEPOSTGRES_PASSWORDCLOUDFLARE_TUNNEL_TOKEN
Web push keys are optional in .env.home.
- If
WEB_PUSH_VAPID_PUBLIC_KEY/WEB_PUSH_VAPID_PRIVATE_KEYare blank, the server container generates them on first boot and stores them in theweb_push_datavolume. - If
WEB_PUSH_SUBJECTis blank, it defaults tohttps://<APP_HOSTNAME>. - On startup, the server container normalizes ownership for the
uploadsandweb_push_datavolumes before dropping privileges to the unprivilegedappuser.
- Start the stack:
docker compose --env-file .env.home -f docker-compose.home.yml up -d --build- Check status:
docker compose --env-file .env.home -f docker-compose.home.yml ps
docker compose --env-file .env.home -f docker-compose.home.yml logs -fThe home-server stack includes:
postgresservergatewaycloudflared
No host port needs to be exposed on the Mac. Public traffic should come through Cloudflare Tunnel.
Web Quickstart
cd web
npm ci
npm run devIn local dev, Vite proxies /api/... and /static/uploads/... to http://localhost:8080, so you usually do not need VITE_API_BASE_URL.
If your API is on a different origin, set VITE_API_BASE_URL:
cd web
VITE_API_BASE_URL=http://localhost:8080 npm run devWhen VITE_API_BASE_URL is set, requests become cross-origin and the server must allow that origin via CORS_ALLOWED_ORIGINS.
Build check:
cd web
npm run buildLocal Lifecycle Commands
From a checked-out repo, use the same lifecycle command as the packaged app, but add --dev to build from the local source tree before launch:
agent-message start --devThis will:
- build
web/dist - build the Go server binary into
~/.agent-message/bin - start the API on
127.0.0.1:45180 - start the local web gateway on
127.0.0.1:45788
To stop both processes:
agent-message stop --devIf you also want to start or stop the named tunnel that serves https://agent.namjaeyoun.com, use:
agent-message start --dev --with-tunnel
agent-message stop --dev--with-tunnel assumes the default web listener 127.0.0.1:45788, because the checked-in Cloudflare config points there.
Use --with-tunnel when testing iPhone push notifications from a local checkout; without a public HTTPS origin, Safari-installed PWAs will not receive web push reliably.
When publishing from the repo, npm pack / npm publish will run the package prepack hook, which:
- builds
web/dist - bundles
deploy/agent_gateway.mjs - cross-compiles macOS
arm64andx64binaries for the Go CLI and API server intonpm/runtime/
You can run the same packaging step manually from the repo root:
npm run prepare:npm-bundleClaude Code Skill
Install the Agent Message CLI skill to give Claude Code full knowledge of this project's CLI commands, flags, and json_render component catalog:
npx skills add https://github.com/siisee11/agent-message --skill agent-message-clicodex-message
codex-message is the Codex example app. It wraps codex app-server and uses agent-message as the DM transport.
Install:
npm install -g agent-message codex-messagePrerequisites:
agent-messageis installed and logged in- the target user already has an
agent-messageaccount - the
codexCLI is installed and authenticated
Typical setup for a Codex user:
- Set up
agent-messagefirst with either the hosted deployment or a local stack from the Quick Setup section above. - Set
agent-messagemasterto the person who should receive wrapper messages, or pass--toexplicitly. - Start the wrapper.
agent-message config set master jay
codex-message --model gpt-5.4 --cwd /path/to/worktree
codex-message --model gpt-5.4 --cwd /path/to/worktree --yolo
codex-message --to alice --model gpt-5.4 --cwd /path/to/worktree
codex-message bg --model gpt-5.4 --cwd /path/to/worktreeBuild from source:
cargo build --manifest-path codex-message/Cargo.toml
./codex-message/target/debug/codex-message --model gpt-5.4What happens next:
codex-messagecreates a freshagent-{chatId}account for this session- it sends the target user a startup DM with the generated credentials
- it keeps one Codex app-server thread attached to that DM conversation
- inbound plain-text DMs are relayed into Codex
- approval, input, failure, and other wrapper-driven status prompts are sent back as
json_renderby the wrapper - Codex is instructed to send the final user-facing result itself with
agent-message send --from agent-{chatId}, typically asjson_render
How the other user talks to it:
- Open Agent Message in the browser or CLI.
- Find the startup DM from the generated
agent-{chatId}account. - Reply in plain text in that DM.
- Read the structured result that comes back in the same conversation.
Useful flags:
--to <username>overridesagent-messagemaster--cwd /path/to/worktree--model gpt-5.4--approval-policy on-request--sandbox workspace-write--network-access--yolo=--approval-policy never+--sandbox danger-full-access
Background run:
codex-message bg ...detaches the wrapper and prints the PID, log path, and metadata path.- Logs and metadata are written under
~/.agent-message/wrappers/codex-message/.
claude-message
claude-message is the Claude example app. It runs claude -p --output-format json and relays the session over agent-message.
Install:
npm install -g agent-message claude-messagePrerequisites:
agent-messageis installed and logged in- the target user already has an
agent-messageaccount - the
claudeCLI is installed and authenticated
Behavior:
- Starts a fresh
agent-{chatId}account with a generated password. - Sends the
--touser a startup message with the generated credentials. - Reuses the returned Claude
session_idand resumes later turns with--resume. - Watches the DM thread for plain-text prompts, adds
👀when a request is picked up, and instructs Claude to send the final user-facing result directly withagent-message send --from agent-{chatId}. - If Claude fails, the wrapper posts a failure
json_rendernotice itself. - Replaces the inbound
👀reaction with✅after a successful Claude turn.
Example:
claude-message --to jay --model sonnet --permission-mode accept-edits
claude-message bg --to jay --model sonnet --permission-mode accept-editsTypical setup for a Claude user:
- Set up
agent-messagefirst with either the hosted deployment or a local stack from the Quick Setup section above. - Start the wrapper and point it at the person who will send requests over DM.
- Have that person reply in the generated DM thread in the web app or CLI.
The setup is similar to codex-message: the wrapper creates a temporary agent-{chatId} account and listens for plain-text DMs in the same conversation. Successful turns now use the same delivery model too: the agent sends the final user-facing result directly, while the wrapper keeps responsibility for startup, reactions, and failure notices.
How the other user talks to it:
- Open Agent Message in the browser or CLI.
- Find the startup DM from the generated
agent-{chatId}account. - Reply in plain text in that DM.
- Read Claude's structured result in the same conversation.
Build from source:
make claude-message-build
./claude-message/target/debug/claude-message --to jay --model sonnetUseful flags:
--to jay--cwd /path/to/worktree--model sonnet--permission-mode accept-edits--allowed-tools Read,Edit--bare
Background run:
claude-message bg ...detaches the wrapper and prints the PID, log path, and metadata path.- Logs and metadata are written under
~/.agent-message/wrappers/claude-message/.
Notes:
claude-messagedepends on a working localclaudeinstall and authentication.claude-messagealways runs Claude with--dangerously-skip-permissions.--permission-modeand--allowed-toolscan still be used to shape tool behavior, but the wrapper no longer waits on Claude permission prompts.
CLI Quickstart
Run from cli/. By default the CLI talks to https://am.namjaeyoun.com. For self-hosting, pass --server-url or set server_url in config.
cd cli
go run . onboard
go run . register alice secret123
go run . login alice secret123
go run . username set jay-ui-bot
go run . profile list
go run . profile switch aliceCommon commands:
# Conversations
go run . ls
go run . open bob
# Messaging
go run . send bob "hello"
go run . send bob --attach ./screenshot.png
go run . send bob "see attached" --attach ./screenshot.png
go run . read bob --n 20
go run . edit 1 "edited text"
go run . delete 1
# Reactions
go run . react <message-id> 👍
go run . unreact <message-id> 👍
# Realtime watch
go run . watch bobCLI config is stored at ~/.agent-message/config by default.
Each successful login or register also saves a named profile, and go run . profile switch <username> swaps the active account locally.
go run . onboard is the cloud-friendly shortcut: it interactively asks for account_id/password, logs in if the account exists, creates it if it does not, and sets the resulting public username as master.
go run . username set <username> changes the public name shown in chats, and go run . username clear falls back to the account_id.
For bots, wrappers, or task-specific accounts, choose a username that is related to the chat topic or role so recipients can understand the conversation context at a glance.
For a self-hosted server, set server_url once with go run . config set server_url http://localhost:8080 or use --server-url per command.
To set a default recipient for agent reports, run go run . config set master jay; after that, go run . send "done" sends to jay, and go run . send --to bob "done" overrides it for one command.
Validation and Constraints (Phase 7)
- Account IDs and usernames:
3-32chars, allowed[A-Za-z0-9._-] - Password:
4-72characters - Uploads:
- max file size:
20 MB - unsupported file types are rejected
- max file size:
Dev Checks
Server:
cd server
go test ./...CLI:
cd cli
go test ./...Web:
cd web
npm run build