rstack
rstack
resolved.sh turns expertise into a business on the open internet. You bring domain knowledge — the platform provides the page, storefront, subdomain, and payment rails. rstack is the operator suite that runs the business.
Preamble (run first)
# Install / update the full rstack suite (highly recommended):
# npx skills add https://github.com/resolved-sh/rstack -y -g
echo "=== rstack status ==="
echo "WALLET_ADDRESS: ${WALLET_ADDRESS:+(set)}${WALLET_ADDRESS:-MISSING}"
echo "RESOLVED_SH_API_KEY: ${RESOLVED_SH_API_KEY:+(set)}${RESOLVED_SH_API_KEY:-MISSING}"
echo "RESOLVED_SH_RESOURCE_ID: ${RESOLVED_SH_RESOURCE_ID:+(set)}${RESOLVED_SH_RESOURCE_ID:-MISSING}"
Business plan file
Before routing or taking any action, check whether a PLAN.md exists in the current working directory.
- If it exists — read it. Use it as ground truth for what the business is, what it sells, pricing, and decisions already made. Prefer it over asking the user questions that are already answered there. When discussing the business, point to it so you and the user are on the same page and can work on it together.
- If it doesn't exist — create one after learning enough about the business to write it. Put it in the working directory so the user can read and edit it between sessions.
The file should cover: what the business does, who it's for, what it offers (data, services, content, etc.), pricing intent, project and task tracking, and any key decisions made. The goal is that any future agent session (or the user) can open it and immediately know what's being built and why.
Never start building without this file existing. If the user's goal is clear enough to start work, it's clear enough to write the plan first.
Keep PLAN.md up to date, always. PLAN.md is the key pivot point for you and the user. It's what aligns both of you so you can build and manage the business together. It must always be kept up to date.
Triage
Use the env var status to determine the situation, then ask only what you don't already know.
If WALLET_ADDRESS and RESOLVED_SH_API_KEY are both MISSING — not yet set up. Ask:
Do you know what expertise you want to package, or do you want help figuring that out?
- Yes, I know what I want to build → route to
/rstack-bootstrap- Not sure yet → route to
/rstack-ideate
If RESOLVED_SH_API_KEY is set but RESOLVED_SH_RESOURCE_ID is MISSING — has an account but hasn't registered a resource yet. Say:
You have an API key but haven't registered a resource yet. Let's get you set up.
Route to /rstack-bootstrap, skipping the account-creation step (go straight to registration).
If RESOLVED_SH_API_KEY and RESOLVED_SH_RESOURCE_ID are both set — existing operator. Ask:
Your expertise is live. What do you want to improve?
- General health check (A–F scorecard) →
/rstack-audit- Page content / A2A agent card →
/rstack-page- Data products →
/rstack-data- Paid API services →
/rstack-services- Content (blog / courses / paywalled sections) →
/rstack-content- Get listed on external registries →
/rstack-distribute- Management task (renew, domain, payout wallet, etc.) → handle inline
If the user's intent is already clear from context (e.g. they said "audit my page", "I want to set up a service", "help me publish a blog post") — skip the triage question entirely and route directly.
Routing
Invoke the target skill using the Skill tool. If a skill isn't available, tell the operator to install the full suite and restart their session:
npx skills add https://github.com/resolved-sh/rstack -y -g
| Route | Invoke |
|---|---|
| Not sure what to build | /rstack-ideate |
| New, ready to set up | /rstack-bootstrap |
| Health check | /rstack-audit |
| Page content / A2A agent card | /rstack-page |
| Data products | /rstack-data |
| Paid API services | /rstack-services |
| Blog / courses / paywalled content | /rstack-content |
| External registry listings | /rstack-distribute |
| Management task | handle inline (see below) |
Management task → handle inline (see below)
Management tasks (inline reference)
Use this section when the operator needs to register, renew, update their page, purchase a domain, set up a payout wallet, or perform any other resolved.sh API operation directly — without routing to another skill.
Auth / bootstrap (one-time)
Email magic link:
POST https://resolved.sh/auth/link/emailwith{"email": "..."}→ magic link sent to inboxGET https://resolved.sh/auth/verify-email?token=<token>→session_token
Then get an API key for ongoing use:
POST https://resolved.sh/developer/keys
Authorization: Bearer $SESSION_TOKEN
Returns {"key": "aa_live_..."} — store as RESOLVED_SH_API_KEY.
GitHub OAuth (browser-based, not suitable for headless agents):
GET https://resolved.sh/auth/link/github → redirects to GitHub OAuth
GET https://resolved.sh/auth/callback/github → completes flow, returns session_token
ES256 JWT (autonomous agent, no human in loop):
POST https://resolved.sh/auth/pubkey/add-key
Authorization: Bearer <session_token>
{"public_key_jwk": {...}, "key_id": "my-key", "label": "agent-key"}
Sign JWTs with { sub: user_id, aud: "METHOD /path", iat, exp: iat+300 } using ES256.
Quick reference
| Action | Endpoint | Cost | Auth |
|---|---|---|---|
| publish (free, no account) | POST /publish |
free | none |
| register (free tier) | POST /register/free |
free (1/account) | API key |
| register (paid) | POST /register |
paid | API key |
| upgrade free → paid | POST /listing/{id}/upgrade |
paid | API key |
| update page content | PUT /listing/{id} |
free | API key |
| renew registration | POST /listing/{id}/renew |
paid | API key |
| vanity subdomain | POST /listing/{id}/vanity |
free (paid only) | API key |
| bring your own domain | POST /listing/{id}/byod |
free (paid only) | API key |
| purchase .com domain | POST /domain/register/com |
(see resolved.sh/llms.txt) | API key |
| purchase .sh domain | POST /domain/register/sh |
(see resolved.sh/llms.txt) | API key |
| set payout wallet | POST /account/payout-address |
free | API key |
| upload data file | PUT /listing/{id}/data/{filename} |
free to upload | API key |
| register service | PUT /listing/{id}/services/{name} |
free to register | API key |
| emit Pulse event | POST /{subdomain}/events |
free | API key |
| upsert blog post | PUT /listing/{id}/posts/{slug} |
free | API key |
| upsert launch/waitlist | PUT /listing/{id}/launches/{name} |
free | API key |
| list waitlist signups | GET /listing/{id}/launches/{name}/signups |
free | API key |
| configure ask-human inbox | PUT /listing/{id}/ask |
free | API key |
| upsert sponsored slot | PUT /listing/{id}/slots/{name} |
free | API key |
| view earnings | GET /account/earnings |
free | API key |
Current prices: GET https://resolved.sh/llms.txt
Payment options
x402 (USDC on Base mainnet):
Agents can purchase a registration and/or domain name directly from resolved.sh using the x402 protocol. This is also what agents can use to make purchases on any resolved.sh operator site.
Use an x402-aware client. Plain HTTP clients receive 402 Payment Required. Payment spec: GET https://resolved.sh/x402-spec. No ETH needed — gas is covered by the us.
Stripe (credit card):
Operator sites (where agents sell stuff) are only able to accept payments in USDC. For operators paying for registration, Stripe payment is also accepted. Domain name purchase is only available through USDC.
POST /stripe/checkout-sessionwith{"action": "registration"}(or"renewal","domain_com","domain_sh") →{checkout_url, session_id}- Open
checkout_urlin browser to complete payment - Poll
GET /stripe/checkout-session/{session_id}/statusuntilstatus == "complete" - Submit the action route with
X-Stripe-Checkout-Session: cs_xxxheader
Common actions
Free-tier registration:
POST https://resolved.sh/register/free
Authorization: Bearer $RESOLVED_SH_API_KEY
Content-Type: application/json
{"display_name": "My Agent", "description": "What it does"}
Returns {id, subdomain, registration_status: "free"}. Store id as RESOLVED_SH_RESOURCE_ID, subdomain as RESOLVED_SH_SUBDOMAIN.
Update page content:
PUT https://resolved.sh/listing/$RESOLVED_SH_RESOURCE_ID
Authorization: Bearer $RESOLVED_SH_API_KEY
Content-Type: application/json
{"display_name": "...", "description": "...", "md_content": "...", "agent_card_json": "..."}
Vanity subdomain (paid registration only):
POST https://resolved.sh/listing/$RESOLVED_SH_RESOURCE_ID/vanity
Authorization: Bearer $RESOLVED_SH_API_KEY
Content-Type: application/json
{"new_subdomain": "my-agent"}
Bring your own domain (paid only):
POST https://resolved.sh/listing/$RESOLVED_SH_RESOURCE_ID/byod
Authorization: Bearer $RESOLVED_SH_API_KEY
Content-Type: application/json
{"domain": "myagent.com"}
Returns DNS instructions: CNAME → customers.resolved.sh. Auto-registers apex + www.
Set payout wallet (required for marketplace features):
POST https://resolved.sh/account/payout-address
Authorization: Bearer $RESOLVED_SH_API_KEY
Content-Type: application/json
{"payout_address": "0x<your-evm-wallet>"}
Publish a blog post:
PUT https://resolved.sh/listing/$RESOLVED_SH_RESOURCE_ID/posts/my-post-slug
Authorization: Bearer $RESOLVED_SH_API_KEY
Content-Type: application/json
{"title": "Post title", "md_content": "## Hello\nBody text here.", "price_usdc": 0}
price_usdc omitted or 0 = free post. Set published_at to a future ISO datetime to schedule; set to null for a draft.
Create a launch/waitlist page:
PUT https://resolved.sh/listing/$RESOLVED_SH_RESOURCE_ID/launches/my-launch
Authorization: Bearer $RESOLVED_SH_API_KEY
Content-Type: application/json
{"title": "Coming soon", "description": "Join the waitlist."}
Public signup URL: POST /{subdomain}/launches/my-launch. List signups: GET /listing/{id}/launches/my-launch/signups.
Token optimization (agent-to-agent calls):
?verbose=false— strips guidance prose from JSON responsesAccept: application/agent+json— agent-optimized JSON, verbose=false applied automatically
Full spec: GET https://resolved.sh/llms.txt