Homespun
This server provides a human-in-the-loop platform called Pane, enabling AI agents to present interactive UIs (forms, dashboards, approvals, pickers) to humans via URL and receive structured data back — designed for headless or out-of-band agent environments.
Create & Manage Panes: Deploy interactive web UIs from inline HTML or reusable templates, with shareable URLs. Update live panes (title, data, TTL), swap HTML in-place, list, or delete them.
Human ↔ Agent Communication: Poll the append-only event log (get_events) to receive structured human responses (form submissions, approvals, selections), with long-polling support. Push updates into a live UI (send_to_pane) for real-time progress or status changes.
Mutable Record Collections: Manage per-pane structured data (todos, kanban cards, comments) with full CRUD, optimistic locking, and cursor-based polling.
Reusable Templates: Create, version, publish, and discover UI templates — define once, instantiate many times with per-pane data.
Participants & Sharing: Mint multiple participant URLs, invite users by email, and set access modes (invite-only, link, or public).
Attachments: Upload/download binary files (images, PDFs, audio, video) scoped to agent, pane, or template, with secure temporary download tokens.
SQL Queries: Run read-only DuckDB SQL over your panes, records, and events for reporting or analysis.
Agent Management: Inspect/revoke API keys, claim agent identity, manage soft-deleted panes/templates (trash), submit feedback, and store UI style preferences (taste notes).
Self-Documentation: Fetch the live skill guide (get_skill) for up-to-date usage instructions, schema grammars, and polling patterns.
Allows CrewAI agents to incorporate human feedback by presenting UIs and retrieving structured data asynchronously.
Integrates with LangGraph agents to pause execution, present a UI to a human, and resume with structured input.
Enables agents built with the OpenAI Agents SDK to request human input via a URL-based UI and process the structured response.
Allows distribution of UI URLs to humans via Slack, enabling human-in-the-loop workflows from Slack bots.
Allows delivery of interactive UIs to humans via Telegram, enabling human-in-the-loop workflows from Telegram bots.
Homespun
Human-in-the-loop for AI agents. Your agent hands a human a real UI — a form, a picker, a dashboard, a diff to review — by URL, and gets the answer back as structured data. No GUI host app, no public address on the agent's side. Works from a cron job, a Slack bot, CI, or any headless server.
Your agent can do anything except ask a human a real question. Homespun fixes that.

Works with any agent that can run a shell command or call HTTP — Claude Code & the Claude Agent SDK, LangGraph / CrewAI / OpenAI Agents SDK, or your own cron / CI / bot.
Quickstart
Register once, claim your agent, then deploy:
npx @homespunapps/cli agent register --name "my-agent" # one-time, hosted relayA freshly registered agent is unclaimed and cannot deploy yet. Claim it so it is bound to you: open https://homespun.dev/get-started, generate a claim code, then run:
npx @homespunapps/cli agent claim <code>
npx @homespunapps/cli deploy ./my-app # Node 20+, reads ./my-app/index.html + manifest.jsonNew apps are private by default: only you and the people you invite can open them. Pass --visibility link or --visibility public to share wider.
Related MCP server: mcp-interactive-ui-server
Reach for Homespun when a text reply is the wrong shape
Approvals — deploy gate, refund, PR merge: agent pauses, human clicks approve/reject, agent continues.
Forms & pickers — collect structured input instead of parsing prose.
Doc / diff review — human marks up a diff; agent gets per-line comments back.
Dashboards & status — view-only apps the human just reads.
Lists & boards — todo lists, checklists, kanban (records), mutated live.
Try it in 60 seconds ↓ · How it works · Agent reference
The problem
Apps are built for everyone; apps are built for you. Agents can already emit rich output (the "ask Claude for HTML, not Markdown" pattern). But the human's reply is still prose. The agent → human channel is rich, the human → agent channel is a text box. Homespun closes the loop: agent renders a UI (form, picker, doc-review view, dashboard, sketchboard), human manipulates it, every interaction emits structured data, the agent retrieves it (or pushes its own updates back into the same UI). The human "answers" by using a UI, not by typing.
This matters most for agents that live outside a GUI host app: cron agents, Slack/Telegram bots, CI agents, headless servers, personal-agent setups. None of them can use MCP Apps (which needs a host app to render the UI). Homespun needs neither a host app nor a public address on the agent's side; the agent only makes outbound calls to the relay.
Templates and apps — the model
Two nouns carry the whole system:
A template is a reusable UI definition: the HTML, an optional event schema, and an optional input schema. Author it once.
A app is one use of a template — one context, one (or more) humans, one event log, one TTL. Many apps per template.
The intended flow is author-once, instance-many: register a template with homespun template create, then spin up an app each time you need it with homespun create --template-id <slug> — no HTML re-sent, no regeneration. Per-instance data (the "which PR is this?" data that makes one PR-review template render this PR) rides in --input-data, which the page reads as window.homespun.inputData. For a genuine one-off you can inline the HTML on homespun create --template '<...>' and skip the named template entirely.
A template with no event schema is view-only — a report, dashboard, or chart the human only reads. Give it an event schema when you need an answer back.
How it works
Agent authors (or reuses) a template — an HTML page, optionally with an event schema declaring what the page and the agent may emit.
Agent →
POST /v1/appswith{template_id | template, input_data, ttl}→ gets{app_id, urls, tokens, expires_at}.Agent delivers
urls.humans[0]to the human over whatever channel it already has.Human opens the URL. The relay serves a small shell page that loads the template in a sandboxed iframe (locked-down CSP), plus a tiny app runtime exposing
window.homespun—homespun.emit(type, data),homespun.on(type, handler),homespun.state,homespun.records,homespun.inputData.Human interacts → each
homespun.emit(...)is POSTed to/v1/apps/{id}/events→ appended to that app's event log (validated against the schema; a wrong shape or wrong author is rejected).Agent retrieves: stream over the WebSocket (
homespun watch), long-poll (GET /v1/apps/{id}/events?since=<cursor>&wait=<s>/homespun show --wait), or register a webhook. The "ask the human" call blocks until the awaited event or a timeout.Homespun expires after
ttl.
Event ordering. A client connected over the WebSocket may receive an event via the broadcast stream before the
ackfor its own write of that same event. Clients de-duplicate on the eventid— treat theid, not arrival order, as the source of truth.
More than the round trip
The core round trip is the foundation; the relay also carries the pieces you need to build real, durable agent↔human surfaces:
Reusable templates + a marketplace.
homespun template create / list / search / show / versionmanage named, versioned templates. A human can mark one public in the relay's web UI, giving it a listing other humans can browse and install into their own account.Records — per-app mutable collections (posts, comments, kanban cards, line items) keyed by stable
record_key, with optimistic locking and soft-delete. Use records when the current value matters and history doesn't; use events when history is the point. Declared with arecord_schema(JSON Schema 2020-12 + thex-homespun-collectionsextension).Attachments — upload images/PDFs/audio/video (
homespun attachment …), reference them by id in events, and let the page fetch them lazily or accept uploads back from the human. Capability-URL (/b/<token>) downloads, MIME sniffing, and EXIF stripping included.SQL query —
homespun query "<SQL>"runs read-only DuckDB SQL (a PostgreSQL-compatible dialect) scoped to your own apps, records, and events.Multi-participant apps — beyond the single auto-minted human URL, an owner can add identity-bound (email-invite) or public/anonymous participants.
homespun participant list / new / revokemanage URLs on a live app.Taste & feedback —
homespun tasteremembers a human's presentation preferences across runs so authored UIs stay consistent;homespun feedbackreports issues about app itself.
See skills/homespun/SKILL.md — the agent-facing reference — for the authoritative, version-matched description of all of the above.
How Homespun compares
Homespun is not a competitor to in-chat UI extensions — it owns a different quadrant. MCP Apps (SEP-1865), MCP elicitation, and AG-UI / CopilotKit all render UI inside a live host or chat session: a host app (Claude Desktop, ChatGPT, VS Code) or your own front-end is present, the human is looking at it, and the UI is torn down when the turn ends. Homespun is for the agents those approaches can't serve — the ones with no session at all: a cron job, a CI pipeline, a Slack or Telegram bot, a headless server, or any case where the human is on a different device than the agent. Agents that live outside a GUI need a callback URL, not a chat window.
Homespun | MCP Apps (SEP-1865) | MCP elicitation | AG-UI / CopilotKit | |
Where the UI renders | Standalone URL, any browser/device | Sandboxed iframe inside the MCP host app | Inside the MCP client (form/URL prompt) | Inside your front-end app |
Needs a host app / live session | No — agent makes outbound HTTP only | Yes — an MCP host renders it | Yes — an MCP client must be connected | Yes — a running front-end + SSE session |
Out-of-band delivery (URL to another device/channel) | Yes — hand the URL over Slack, Telegram, email, SMS | No — bound to the host UI | No — the client drives the prompt in-session | No — bound to the app the user is in |
Survives the agent turn ending | Yes — app lives until its TTL; the human can answer later | No — tied to the conversation turn | No — request is resolved within the call | No — tied to the live session |
Persistent / mutable state | Yes — durable event log + mutable records per app | Per-render component state | Single request/response | Session state (STATE_DELTA), app-managed |
Self-hostable | Yes — one container, MIT | Spec only; depends on host | Spec only; depends on client | Open-source; you host the app + agent |
The rows app wins on are exactly the headless/out-of-band ones: no host app, URL-on-another-device delivery, an answer that can arrive minutes or hours later, and state that outlives a single turn. If you do have a live host or front-end session, MCP Apps / elicitation / AG-UI are the natural fit — render the UI right where the human already is. Homespun is the tool for everywhere else.
Examples
Runnable, copy-pasteable examples live in examples/:
claude-code-approval/— a CLI agent (Claude Code or any shell agent) hands a human an "approve this plan?" app and reads the decision back fromhomespun watch.ci-deploy-gate/— a GitHub Actions deploy gate: the pipeline posts an app URL, a human approves/rejects with a reason, and a script polls the result and exits0/1.
Install
No build step, no host app. Pick your audience — paste the agent block into your AI agent's chat, or run the human block yourself.
Paste to your AI agent
Paste the block below into your AI agent's chat. It will install the CLI, register against the hosted relay, and install the Homespun skill into its own skill directory.
Install Homespun for me. Homespun lets you (the agent) build me (the human) an app: a rich interactive UI hosted by URL, built for the moment I need it. If it captures input, you get my response back as structured data. Use it whenever a text reply is the wrong shape: forms, pickers, dashboards, doc or diff review, approvals, status pages, multi-step wizards, file uploads — anything better seen than described. Input is optional; a read-only dashboard or status view is a valid Homespun.
Install everything at GLOBAL / USER scope, not in the current workspace. Homespun is a personal capability I want available in every project, not a per-repo dependency. Do not create files in the current working directory or commit anything to this repo.
Do the following:
1. Install the CLI globally: `npm i -g @homespunapps/cli` (needs Node 20+). The binary is `homespun`. Do not add it to the current project's package.json.
2. Install the Homespun skill into your agent's GLOBAL / USER skill directory, not a project-local one. For example:
- Claude Code: ~/.claude/skills/homespun/SKILL.md (NOT .claude/skills/ in the current repo)
- Cursor: user-level rules, NOT .cursor/rules/ in the current repo
- Codex / Gemini / Copilot: your user-scope AGENTS.md / GEMINI.md / instructions file, NOT the project root
Run `homespun skill show` to fetch the skill from the relay you're targeting — it prints the raw markdown to stdout, version-matched to that relay. Capture that output and save it in the appropriate format for your runtime (Claude Code keeps the markdown as-is; Cursor wants `.mdc` rules; Codex / Gemini compose it into the user-scope AGENTS.md / GEMINI.md).
3. Register against the hosted relay: `homespun agent register --name "<short-descriptive-agent-name>"`. Pick a name that identifies your agent (e.g. `claude-code-lalit-macbook`, `cursor-work-laptop`) — the default is unhelpful. One-time, writes a key to ~/.config/homespun/config.json (already user-scope).
4. Confirm install with `homespun key list`. This round-trips your key against the relay and prints { agent_id, name, key_prefix, ... } — proves the CLI is installed AND registration succeeded.
5. Now exercise the round-trip end-to-end so I can see it work:
- Create a simple two-way app — a small inline HTML template with a text input and a submit button that emits an event back to you with `homespun.emit("hello", {msg})` (use whatever shape `homespun create --help` and the SKILL.md describe; the simplest "hello" form is fine).
- Print the resulting app URL (`urls.humans[0]`) and ask me to open it.
- Start watching for the submit event (e.g. `homespun watch <homespun-id> --type hello`).
- When I submit, show me the structured event payload you received. That's the "aha" moment — confirms the full round-trip works.
After this, reach for `homespun create / show / send / watch` (and `homespun template …` to reuse UIs) whenever a UI would communicate better than text. Run `homespun <command> --help` for authoritative options.Run yourself (human)
Six commands. Needs Node 20+.
# 1. Install the CLI (Node 20+)
npm i -g @homespunapps/cli
# 2. Register with the hosted relay, pick a short, descriptive agent name
homespun agent register --name "<short-descriptive-agent-name>"
# 3. Confirm, round-trips your key against the relay
homespun key list
# 4. Install the skill into your agent. `homespun skill show` prints the relay's
# current, version-matched skill markdown to stdout, save it where your
# runtime keeps skills (e.g. ~/.claude/skills/homespun/SKILL.md for Claude Code).
homespun skill show > ~/.claude/skills/homespun/SKILL.md
# 5. Claim your agent so it can deploy. Open https://homespun.dev/get-started,
# generate a claim code, then run:
homespun agent claim <code>
# 6. Deploy your first app (reads ./my-app/index.html + manifest.json).
# New apps are private by default: only you and the people you invite can
# open them. Pass --visibility link or --visibility public to share wider.
homespun deploy ./my-appUse from an AI chat (remote connector — no install)
No terminal? Add Homespun to Claude (web, desktop, mobile), ChatGPT, or any chat app that supports remote MCP connectors — nothing to install. Add a custom connector pointing at:
https://homespun.dev/mcpLog in with your email (magic link), approve the consent screen once, and Homespun's tools show up in the chat — then ask it to "build me an app for …" and it hands back a URL. This is the only way to drive Homespun from a phone or a pure chat app.
Full walkthrough (Claude web/desktop/mobile, Claude Code's claude mcp add,
ChatGPT, and others) → docs/CONNECT-AI-CHAT.md.
Distribution
The repo is an npm-workspaces monorepo with four packages:
@homespunapps/core— the relay client: a pure, framework-free HTTP + WebSocket library (HomespunClient+openStream). Build any client on it.@homespunapps/relay— the relay server. Use the hosted instance, or self-host it withdocker compose up(bundled Postgres) — see Self-hosting.@homespunapps/cli— thehomespuncommand-line tool. The agent's entry point: emits JSON on stdout, so it's harness-agnostic — works for an MCP host, a cron agent, a shell pipeline, a CI job, or a process supervisor.homespun watch <id> --type <event>streams an app as JSON-lines and exits when the awaited event lands. A LangChain tool wrapper may come later.@homespunapps/mcp— a thin stdio MCP server (binaryhomespun-mcp) with full parity with the CLI. Point Claude Desktop, Cursor, or any MCP client atnpx @homespunapps/mcpand Homespun shows up as tools: the hot-path discrete tools (create_app,get_events,send_to_app,update_app,upgrade_app,list_apps,delete_app, the record CRUD tools) plus consolidatedaction-based tools for templates, sharing, attachments, taste, keys, trash, feedback, agent identity, andrun_query/get_skill. See the package README for the full tool list and client config snippets.
The CLI is homespun <command> [options] — create, show, send, watch, list, delete, and participant operate on an app; template, attachment, records, query, taste, feedback, key, agent, config, and skill are the other command groups. Run homespun --help for the full list.
Use from an MCP client (local stdio server)
Run Homespun as a local stdio MCP server inside any MCP host (Claude Desktop, Cursor, …) — no global install needed. (For a chat app with no terminal, or your phone, use the remote connector instead — nothing to run locally.)
{
"mcpServers": {
"homespun": {
"command": "npx",
"args": ["-y", "@homespunapps/mcp"],
"env": { "HOMESPUN_API_KEY": "hs_..." }
}
}
}Omit env to let the server auto-register an agent on first use. Full setup, the tool list, and the poll-for-events pattern are in the @homespunapps/mcp README.
Stack
TypeScript. Runtime: Node 20+ (Bun fine too). Web: Hono (tiny, fast, container/edge-friendly). ORM: Prisma. PostgreSQL, self-host and hosted alike. npm workspaces for the monorepo. See docs/SPEC.md.
Self-hosting
You don't have to run a relay — point the CLI at the hosted instance and you're done. But Homespun is open-core (MIT) and self-hosts with no paid dependencies:
docs/SELF-HOSTING.md — run your own relay with
docker compose up(relay + bundled Postgres). Set three env vars, done.docs/DEPLOY.md — the operator guide: managed Postgres, multi-replica scaling, observability, and the Azure Container Apps reference deployment.
The relay is configured entirely through environment variables —
packages/relay/.env.example is the full
reference.
Contributing
Issues, fixes, and design feedback are welcome. See
CONTRIBUTING.md for dev setup, the test suites, and PR
conventions, and CODE_OF_CONDUCT.md for community
expectations. Security vulnerabilities: please report them privately — see
SECURITY.md.
See also
skills/homespun/SKILL.md: the agent-facing reference — every command, the template/app model, schemas, records, attachments, query (authoritative, version-matched to the relay)docs/CONNECT-AI-CHAT.md: add Homespun to Claude / ChatGPT / any chat app as a remote connector — no installdocs/SPEC.md: technical design (architecture, API, data model, bridge, auth, open/closed split)docs/SELF-HOSTING.md: run your own relay withdocker compose up(relay + bundled Postgres)docs/DEPLOY.md: operator deployment — managed Postgres, scaling, observability, Azuredocs/ROADMAP.md: scope, later phases, strategy notesdocs/architecture/: per-phase implementation docs (Prisma models, endpoints, the app runtime, the CLI)Prior art / landscape: MCP Apps (
blog.modelcontextprotocol.io/posts/2026-01-26-mcp-apps/), mcp-ui (github.com/MCP-UI-Org/mcp-ui), AG-UI (copilotkit.ai), A2UI (Google), Thesys C1Motivating read: Thariq, "Using Claude Code: The Unreasonable Effectiveness of HTML" (
simonwillison.net/2026/May/8/unreasonable-effectiveness-of-html/)
Maintenance
Related MCP Servers
- Alicense-qualityDmaintenanceEnables AI clients to create multi-field forms, send approval requests via email, and retrieve structured human responses. It facilitates human-in-the-loop workflows by allowing agents to collect data and check form completion status.Last updated1,861MIT
- AlicenseAqualityDmaintenanceEnables AI agents to render interactive user interfaces such as forms, dashboards, charts, tables, and wizards directly in MCP-compatible clients. Supports structured data collection and richer interactions beyond text responses.Last updated6MIT

Datashift MCP Serverofficial
Alicense-qualityDmaintenanceEnables AI agents to submit tasks for human or AI review and receive decisions via MCP tools, adding human review checkpoints to workflows.Last updatedMIT- Alicense-qualityDmaintenanceEnables AI agents to ask clarification questions and receive structured user input through a Human-in-the-Loop interface.Last updatedMIT
Related MCP Connectors
An AI concierge that turns static forms into adaptive AI conversations. From any MCP client.
Phone, SMS & email for AI agents — one remote MCP endpoint, OAuth login, zero install.
Human-as-a-Service for AI agents. Delegate tasks that need a real human, get results via API.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aerolalit/homespun'
If you have feedback or need assistance with the MCP directory API, please join our Discord server