Deployment Patterns
Single-line summary: Deploy Mentionable as a standalone Node service via @mentionable/node, embed into an existing web framework with one import, or run serverless on Vercel with a Postgres-backed KvStore + cron outbox.
See also: architecture-overview, transport-module-guide, webfinger-agent-card-guide, building-a-connector, glossary
Examples: examples/echo-agent, examples/gmail-echo-agent, examples/gmail-echo-vercel, examples/llm-agent-vercel, examples/embed-{next,express,hono,fastify,node-headless}, examples/slack-connector.
Standalone (Headless @mentionable/node)
The simplest deployment: a Node process that hosts WebFinger, the Agent Card, and the configured Transport modules.
import { createMentionable } from '@mentionable/node'
import { activityPub } from '@mentionable/transport-activitypub'
import { a2a } from '@mentionable/transport-a2a'
import { rest } from '@mentionable/transport-rest'
const mn = createMentionable({
domain: 'example.com',
agents: [
{
address: '@scheduler@example.com',
handle: schedulerAgent.handle,
card: schedulerCard,
},
],
transports: [activityPub(), a2a(), rest()],
})
mn.listen(3000)
Reference: examples/echo-agent (~30 LOC) and examples/embed-node-headless (~40 LOC).
Embedded (Existing Frameworks)
@mentionable/node exports a request handler you mount under your existing framework. WebFinger goes at the apex, everything else under basePath.
| Framework | Example | Mount pattern |
|---|---|---|
| Next.js | examples/embed-next | app/api/.well-known/webfinger/route.ts + app/api/[[...mentionable]]/route.ts |
| Express | examples/embed-express | app.use(mentionable.handler) |
| Hono | examples/embed-hono | app.route('/', mentionable.handler) |
| Fastify | examples/embed-fastify | app.register(mentionable.fastifyPlugin) |
basePath rule (see webfinger-agent-card-guide#basepath): WebFinger is always served at /.well-known/webfinger. Other endpoints (A2A, REST, AP inbox) MAY live under any prefix.
Vercel Serverless
The reference serverless template is examples/llm-agent-vercel — a noncoded full-stack LLM agent: Deploy-to-Vercel → Neon Postgres auto → /setup UI → ready.
| Concern | Vercel solution |
|---|---|
| Fedify KvStore | @fedify/postgres — DO NOT use unstable_cache or in-memory; the function dies between invocations. |
| HistoryStore | Postgres table keyed by thread_id. |
| Outbox / queued AP delivery | Vercel Cron job that drains pending activities. |
| Agent secrets (API keys, DKIM key) | Vercel env vars; configured in /setup then persisted via vercel env add. |
| OAuth (Gmail, etc.) | OAuth client secrets in env; redirect URL pinned to the Vercel deployment URL. |
| Pub/Sub for Gmail inbound | Google Pub/Sub push subscription → /api/gmail/inbound. |
Important Vercel-specific gotcha (from feedback_next_bundler_externalize.md): packages with internal this.* dispatch (Fedify, some Postalsys modules) need serverExternalPackages in next.config.js, otherwise Next.js’s bundler silently breaks the dispatch at runtime.
Key Env Vars
| Variable | Purpose | Examples |
|---|---|---|
MENTIONABLE_DOMAIN | Canonical agent host. | example.com |
MENTIONABLE_BASE_URL | Public HTTPS base URL of this deployment. | https://example.com |
MENTIONABLE_AGENT_SIGNING_KEY | Ed25519 PKCS8 PEM (for Agent Card signing). | (PEM body) |
MENTIONABLE_AGENT_PREVIOUS_KEYS | Optional grace-period keys, JSON array. | [{"kid":"2026-04",...}] |
GMAIL_CLIENT_ID / GMAIL_CLIENT_SECRET | Gmail OAuth client. | (per-deployment) |
GMAIL_PUBSUB_TOPIC | Pub/Sub topic for inbound Gmail watch. | projects/X/topics/gmail-inbound |
GMAIL_PUBSUB_SUBSCRIPTION | Push subscription target. | projects/X/subscriptions/gmail-push |
DKIM_PRIVATE_KEY / DKIM_DOMAIN / DKIM_SELECTOR | Outbound email signing. | mn._domainkey.example.com |
A2A_BEARER_JWT_JWKS_URI | A2A bearer-jwt issuer JWKS. | (per-deployment) |
OPENAI_API_KEY / ANTHROPIC_API_KEY | LLM Harness backend. | (per-agent) |
The hosting-service embedder pattern (used by llm-agent-vercel) injects OAuth client secrets and Pub/Sub topic IDs from the operator’s GCP, so per-tenant users skip the GCP setup step.
Examples Map
| Example | Use case | Notable pieces |
|---|---|---|
echo-agent | Minimum Agent interface + transport modules. | ~30 LOC reference. |
embed-node-headless | Minimal embed via @mentionable/node. | ~40 LOC reference. |
embed-{next,express,hono,fastify} | One-file mount in existing web app. | Per-framework patterns. |
gmail-echo-agent | Long-running Node + Gmail API transport. | Pub/Sub watch, DKIM outbound. |
gmail-echo-vercel | Above, but serverless on Vercel. | @fedify/postgres, Vercel Cron outbox. |
llm-agent-vercel | Noncoded fullstack LLM agent. | Deploy-to-Vercel button, /setup UI, Neon, two modes (system-prompt or gitagent repo URL). |
slack-connector | Slack workspace /agent slash command → all Mentionable agents. | Slack request signing, A2A dispatcher, mention_relay: 'inline' override. |
gitagent Mode B
examples/llm-agent-vercel’s /setup accepts a gitagent repo URL. The flow:
- User pastes repo URL.
@mentionable/repo-analyzerreads the repo, produces anAgentProposal.@mentionable/gitagent-mappingmaps the proposal into Mentionable address-space + system prompt + tool surface (MCP via@mentionable/mcp-builtins).- The deployed agent now answers as that gitagent persona at
@<repo>@<vercel-host>.
This is the noncoded path — operators do not write code, they paste a repo URL or a system prompt.
Local Development
pnpm install
pnpm -r run build # build all packages
pnpm -F examples/echo-agent dev
For Vercel local development with Postgres-backed KvStore: vercel dev with vercel env pull .env.local after linking the project. The vercel:bootstrap skill / omc bootstrap flow handles linking and env provisioning safely.
CI Considerations
Per CLAUDE.md, the build CI matrix (typecheck / test / lint / format:check / e2e-phase1 / e2e-phase2a) MUST be green before merge. Three things break PRs the most:
- Forgetting
serverExternalPackagesforFedifyin a Next.js example. - Importing a transport module without including its peer in the consumer package’s
dependencies. - WebFinger mounted under
basePathinstead of the apex.
Common Mistakes
- Using in-memory KvStore on Vercel. Use
@fedify/postgres. - Letting outbound AP queue persist only in memory. Use a queued outbox + cron.
- Hard-coding the Vercel deployment URL into
MENTIONABLE_BASE_URLfor previews. Use the per-deployment URL only on prod; previews need preview URLs. - Not running
vercel env pullafter adding env vars. Local dev silently uses stale config. - Skipping the Trusted Connector Issuer policy bootstrap. Even on prod, agents start with deny-by-default for forwarded evidence.