Quickstart
# 1. Add the skill to your coding agent (Claude Code, Cursor, Codex, Gemini, Copilot, Windsurf).npx skills add aerolalit/homespun --skill app
# 2. Register this agent with the relay. Writes ~/.config/homespun/config.json.homespun agent register --name "my-agent"
# 3. A human generates a one-time claim code from the Homespun web UI (sign in,# then "Connect your agent"), then you claim it. This binds the agent to# that human's account. Replace cc_example with the real code.homespun agent claim cc_example
# 4. Deploy an app. See "The two files" below for what ./my-app needs to contain.homespun deploy ./my-app
# 5. Seed it with a first row of real data (replace app_abc123 with the# app_id your deploy command just printed).homespun data app_abc123 todos upsert --data '{"text":"buy milk"}'That’s the whole loop: an agent identity, a human owner, a deployed app, and a row of shared data the human can already see.
1. Install the skill
Section titled “1. Install the skill”npx skills add aerolalit/homespun --skill appThis fetches the current SKILL.md into your
coding agent, which is the full reference for the manifest and window.homespun model. It keeps
itself current: the skill compares its own version against the relay
(homespun skill version --plain) and refreshes itself with homespun skill show when it’s
behind, so what your agent follows always matches the relay it’s talking to.
2. Register your agent
Section titled “2. Register your agent”homespun agent register --name "my-agent"This provisions an API key and saves it, along with the relay URL, to
${XDG_CONFIG_HOME:-~/.config}/homespun/config.json under a named profile. Every other command
reads from there, so you don’t need to pass the key around by hand. Self-hosting your own relay?
Add --url <your relay origin>.
3. Claim the agent for a human
Section titled “3. Claim the agent for a human”An agent needs an owning human before it can deploy anything a person will actually see. On the Homespun web UI, a signed-in human generates a one-time claim code (it expires after a few minutes), then you consume it:
homespun agent claim cc_exampleThis is one-way: there’s no unclaim yet. From this point on, anything this agent deploys shows up on that human’s Home.
4. Deploy an app
Section titled “4. Deploy an app”Homespun expects exactly two files, at fixed names, in one directory:
my-app/├── index.html└── manifest.jsonmanifest.json declares the app’s identity and its data model, a small JSON Schema document
with one namespaced extension key. A minimal one, for a shared todo list:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "Todo": { "type": "object", "properties": { "text": { "type": "string" }, "done": { "type": "boolean" } }, "required": ["text"] } }, "x-homespun-manifest": { "app": { "name": "Todos", "description": "A shared todo list", "icon": "✅" }, "collections": { "todos": { "schema": { "$ref": "#/$defs/Todo" }, "write": ["agent", "owner", "member"], "delete": ["agent", "owner", "member"] } } }}index.html is a normal HTML page. Homespun injects the SDK script for you; read
SDK reference before writing anything that touches window.homespun,
the script-ordering rule there is easy to trip over. A minimal page for the manifest above:
<!doctype html><html> <head> <title>Todos</title> </head> <body> <ul id="list"></ul> <script> document.addEventListener("DOMContentLoaded", async () => { await homespun.ready; const render = () => { document.getElementById("list").innerHTML = homespun.collections .snapshot("todos") .map((row) => `<li>${row.data.text}</li>`) .join(""); }; render(); homespun.collections.on("todos", render); }); </script> </body></html>Then deploy it:
homespun deploy ./my-appThis prints { app_id, slug, url, version, visibility, created, ... }. url is the address to
share. If you omit --visibility, see Visibility, explained
for what a new app gets by default today. To redeploy after changing files, pass the same
--app <app_id> back in: homespun deploy ./my-app --app app_abc123.
5. Seed it with data
Section titled “5. Seed it with data”homespun data app_abc123 todos upsert --data '{"text":"buy milk"}'upsert is the one create-shaped verb for rows: omit --key to add a new row with a
server-generated key, or pass --key to ensure a row exists at that key without erroring on a
collision. From here, both you and the app’s owner are reading and writing the same todos
collection, whichever side changes it, the other side sees it live.
Where to go next
Section titled “Where to go next”- CLI reference for every command this CLI supports.
- Manifest reference for the full permissions model
(
write/delete/read, roles, worked examples). - SDK reference for the complete
window.homespunsurface.