{"openapi":"3.1.0","info":{"title":"Woodhouse — public API","version":"1.0.0","summary":"The parts of kyro.house an agent can use without a household sign-in.","description":"Event pages, guest identity by email code, calendar files, the MCP server (bearer token from the owner), health, and the discovery files. Every error is RFC 9457 problem details (application/problem+json) with a machine-readable `code`. Versioning: the API is versioned in the path (`/api/*` is v1 of the public surface; `/eve/v1/*` is the eve runtime). Deprecation policy: a route that is going away carries `Deprecation` and `Sunset` headers for at least 90 days and is listed in this document's `x-deprecations` before removal. Rate limits: public routes answer with `RateLimit-Limit` / `RateLimit-Policy` headers (60 requests per minute per IP) and `Retry-After` on a 429. Contact: woodhouse@kyro.house · source: https://github.com/kyleroche/kyrohome · docs for agents: https://kyro.house/llms.txt","contact":{"name":"Woodhouse","email":"woodhouse@kyro.house","url":"https://kyro.house/contact"},"license":{"name":"MIT","url":"https://github.com/kyleroche/kyrohome/blob/main/LICENSE"}},"externalDocs":{"description":"Developer page","url":"https://kyro.house/developers"},"servers":[{"url":"https://kyro.house"}],"x-deprecations":[],"paths":{"/eve/v1/health":{"get":{"operationId":"getHealth","summary":"Liveness","description":"Returns 200 with a small JSON body when the agent runtime is up.","responses":{"200":{"description":"ok","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"additionalProperties":true}}}}}}},"/api/events/{id}":{"get":{"operationId":"getEvent","summary":"An event and its reply counts","description":"Public by link. `viewer` is null for an anonymous caller; `replies` is present only for the host side.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9]{6,16}$"},"description":"The id from the event link"}],"responses":{"200":{"description":"The event","content":{"application/json":{"schema":{"type":"object","required":["event","viewer","mine","summary","bringing"],"properties":{"event":{"$ref":"#/components/schemas/Event"},"viewer":{"type":["object","null"],"properties":{"name":{"type":"string"},"family":{"type":"boolean"},"parent":{"type":"boolean"}}},"mine":{"$ref":"#/components/schemas/Mine"},"summary":{"$ref":"#/components/schemas/EventSummary"},"bringing":{"type":"array","items":{"type":"string"}}}}}}},"404":{"description":"No such event","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"operationId":"replyToEvent","summary":"Reply to an event","description":"Needs an identity: a signed-in household member (cookie or Bearer) or a guest who holds the `woodhouse_guest` cookie from PUT /api/events/{id}/code. `headcount` and `bringing` are kept only when `attending` is true; with bringMode `list`, `bringing` must be one of the host's options.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["attending"],"properties":{"attending":{"type":["boolean","null"]},"headcount":{"type":"integer","minimum":1,"maximum":50},"bringing":{"type":"string","maxLength":200},"note":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","required":["mine","summary"],"properties":{"mine":{"$ref":"#/components/schemas/Mine"},"summary":{"$ref":"#/components/schemas/EventSummary"}}}}}},"400":{"description":"bringing is not one of the host's options","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Say who you are first","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such event","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"410":{"description":"The event has passed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/events/{id}/code":{"post":{"operationId":"sendGuestCode","summary":"Email a six-digit code to a guest","description":"Woodhouse mails a code that is valid for 15 minutes. Three codes per address per event per hour.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","email"],"properties":{"name":{"type":"string","maxLength":80},"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Sent","content":{"application/json":{"schema":{"type":"object","required":["sent"],"properties":{"sent":{"type":"boolean","const":true}}}}}},"400":{"description":"Not an email address, the event is closed, or too many codes this hour","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"put":{"operationId":"verifyGuestCode","summary":"Exchange the code for the guest cookie","description":"Sets the `woodhouse_guest` cookie (180 days) that replyToEvent accepts.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","code"],"properties":{"email":{"type":"string","format":"email"},"code":{"type":"string","pattern":"^[0-9]{6}$"}}}}}},"responses":{"200":{"description":"Cookie set","content":{"application/json":{"schema":{"type":"object","required":["ok","name"],"properties":{"ok":{"type":"boolean"},"name":{"type":"string"}}}}}},"400":{"description":"Enter the six-digit code","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Wrong or expired code","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/events/{id}/invite.ics":{"get":{"operationId":"getEventIcs","summary":"The event as an iCalendar file","description":"One VEVENT, for Apple Calendar and anything else that opens .ics.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"text/calendar","content":{"text/calendar":{"schema":{"type":"string"}}}},"410":{"description":"The event has passed","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/eve/v1/mcp":{"post":{"operationId":"mcp","summary":"MCP (Streamable HTTP)","description":"JSON-RPC over SSE. Tools: agent_start, agent_get, agent_update, agent_cancel. The bearer is a session token the household's owner mints (no self-service). See https://kyro.house/llms-full.txt → MCP access.","security":[{"bearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"A JSON-RPC 2.0 request","additionalProperties":true}}}},"responses":{"200":{"description":"An SSE frame carrying the JSON-RPC response","content":{"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"No or revoked token","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}},"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","summary":"Short summary for LLMs","description":"What this is, when to use it, how to set up your own.","responses":{"200":{"description":"text/plain","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/llms-full.txt":{"get":{"operationId":"getLlmsFullTxt","summary":"Full summary for LLMs","description":"README, setup, MCP access and the family manual in one file.","responses":{"200":{"description":"text/plain","content":{"text/plain":{"schema":{"type":"string"}}}}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"A long-lived session JWT for a service principal, minted by the owner with db/seed-bot.mjs."}},"schemas":{"Problem":{"type":"object","description":"RFC 9457 problem details — every error from /api/* has this shape.","required":["title","status","code"],"properties":{"type":{"type":"string","format":"uri","description":"Link to this spec"},"title":{"type":"string"},"status":{"type":"integer"},"code":{"type":"string","description":"Machine-readable: not_found | unauthorized | gone | bad_request | rate_limited"},"detail":{"type":"string","description":"What went wrong and what to do instead"},"instance":{"type":"string"},"error":{"type":"string","description":"Legacy alias of detail on the event routes"}}},"Event":{"type":"object","required":["id","title","startsAt","status","askHeadcount","bringMode","bringOptions"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":["string","null"],"format":"date-time"},"location":{"type":["string","null"]},"details":{"type":["string","null"]},"host":{"type":"string"},"askHeadcount":{"type":"boolean"},"bringMode":{"type":"string","enum":["none","free","list"]},"bringOptions":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["open","closed"]},"createdAt":{"type":"string","format":"date-time"}}},"EventSummary":{"type":"object","required":["coming","people","declined"],"properties":{"coming":{"type":"integer"},"people":{"type":"integer"},"declined":{"type":"integer"}}},"Mine":{"type":["object","null"],"properties":{"attending":{"type":["boolean","null"]},"headcount":{"type":["integer","null"]},"bringing":{"type":["string","null"]},"note":{"type":["string","null"]}}}}}}