← Anyone Home?
API

Drive Anyone Home? from your own code

The one metered task, read-things, is available over HTTP. It takes 1 to 6 everyday things, each with a name, what it does, and an answer (No, A little or Clearly) for each of six lenses. It returns a plain-words reading of each thing's verdict, one imagined change that would move it a band, and a one-line insight.

The division of labour first: the page decides; the model explains. The page adds up each thing's lamp points (0-12), picks its verdict, its strongest lens and the thing most at home before the run, and sends all of it in facts. The model copies each verdict verbatim, never changes one, and never claims anything is or is not conscious.

Base URL and the envelope

Every endpoint lives under https://api.skillsafe.ai/v1/app-api, and every response uses one envelope:

{ "ok": true,  "data":  { ... } }
{ "ok": false, "error": { "code": "...", "message": "..." } }

The token is minted for this app (the guest call takes {"slug":"anyone-home"}), so no slug header is needed afterwards. Send it as Authorization: Bearer …. The run body is the input object, sent bare.

StatusCodeMeaning
400validation_errorThe body is not a JSON object, or a required field (task, things, facts) is missing.
401unauthorizedNo token, or a stale one. Mint a guest token or sign in again.
402insufficient_creditsThe balance is under min_credits. Price with /estimate first.
403forbiddenA guest token tried to run: the reasons are metered and need a personal sign-in.
404not_foundUnknown job id.
429rate_limitedBack off and retry.
5xxserver_errorTransient. Retry with the same Idempotency-Key so a retry never double-bills.

The task field, the input and the verdicts

Every run sends task: read-things (the one task is read-things); a missing or different one is still answered as read-things. All fields are strings.

FieldRequiredWhat it holds
taskyesAlways read-things.
thingsyesOne numbered line per thing (1 to 6): name | what it does: ... | News reaches all of it: ... | Splitting it loses something: ... | It feeds back into itself: ... | It keeps tabs on itself: ... | It keeps itself going: ... | It shows what it is like: .... Each answer is No, A little or Clearly; "what it does" is "not given" when blank.
factsyesThe page's lines: per thing its glow (0-12), its verdict, its strongest lens and the one change (lenses moved from one answer to another) that would move it exactly one band; then the count of each verdict; then the thing most at home.
retry_notenoOnly on the page's one reformat retry.

Each answer is worth No 0, A little 1, Clearly 2. The verdict, first match wins: 9 or more is lit (lights on); 6 to 8 is stirring (someone stirring); 3 to 5 is porch (porch light only); 0 to 2 is dark (nobody home). The strongest lens is the highest-scoring lens, ties to the lens listed first (none when all are No); the thing most at home has the highest glow, ties to the thing higher on the list (none when every glow is 0).

The reply

{"task": "read-things", "headline": "...", "things": [{"name": "...", "verdict": "porch", "reading": "...", "flip": "...", "insight": "..."}], "closing": "..."}
FieldWhat it holds
headlineAt most 22 words summing up the panel; counts match facts.
things[]One per input thing, same order and exact names: verdict copied from facts, reading (at most 50 words, from that thing's own answers, naming its strongest lens), flip (at most 30 words: one imagined "if" change that would move it a band - down for lit, up otherwise) and insight (at most 18 words, agreeing with the verdict).
closingOne sentence naming the thing most at home (or saying nobody seems home anywhere).

The page then checks the reply (HomeKit.check) - each verdict against its own, every thing present, a what-would-change-it line and an insight for each, time or season words, claims that something is or is not conscious, contact-like details or posting somewhere public, health or medical wording, thinker or theory names, things it did not list, internal ids in prose, a closing that misses the thing most at home, and word limits - and lists any disagreement under "The page's check". The one-line meaning under each card is fixed text on the page, not model output.

Worked examples - all four verdicts

These are the 3 free samples on the page: the exact input the page sends and the reply that replays for free. Together they cover all four verdicts.

Around the kitchen - verdicts: someone stirring, porch light only, nobody home

Input:

{
 "task": "read-things",
 "things": "1. The thermostat | what it does: turns the heating on when the room gets cold | News reaches all of it: No | Splitting it loses something: No | It feeds back into itself: Clearly | It keeps tabs on itself: A little | It keeps itself going: No | It shows what it is like: No\n2. Sourdough starter | what it does: bubbles up when it is fed flour and water | News reaches all of it: A little | Splitting it loses something: A little | It feeds back into itself: A little | It keeps tabs on itself: No | It keeps itself going: Clearly | It shows what it is like: A little\n3. The toaster | what it does: pops up when its timer ends | News reaches all of it: No | Splitting it loses something: No | It feeds back into itself: No | It keeps tabs on itself: No | It keeps itself going: No | It shows what it is like: A little\n4. Fridge light | what it does: comes on when the door opens | News reaches all of it: No | Splitting it loses something: No | It feeds back into itself: No | It keeps tabs on itself: No | It keeps itself going: No | It shows what it is like: No",
 "facts": "1. The thermostat: glow 3 of 12; verdict porch; strongest lens: It feeds back into itself; one band up: It keeps tabs on itself from A little to Clearly and News reaches all of it from No to Clearly (3 points more)\n2. Sourdough starter: glow 6 of 12; verdict stirring; strongest lens: It keeps itself going; one band up: News reaches all of it from A little to Clearly and Splitting it loses something from A little to Clearly and It feeds back into itself from A little to Clearly (3 points more)\n3. The toaster: glow 1 of 12; verdict dark; strongest lens: It shows what it is like; one band up: It shows what it is like from A little to Clearly and News reaches all of it from No to A little (2 points more)\n4. Fridge light: glow 0 of 12; verdict dark; strongest lens: none; one band up: News reaches all of it from No to Clearly and Splitting it loses something from No to A little (3 points more)\ncounts: lit 0, stirring 1, porch 1, dark 2 (of 4 things)\nmost at home: Sourdough starter"
}

Reply:

{
 "task": "read-things",
 "headline": "Across four everyday things, one shows someone stirring, one comes out porch light only, and two end up at nobody home.",
 "things": [
  {
   "name": "The thermostat",
   "verdict": "porch",
   "reading": "You said the thermostat feeds back into itself as it turns the heating on when the room gets cold, which is its strongest sign and lands it as porch light only. You also said it doesn't reach every part of it and doesn't show what it is like.",
   "flip": "If the thermostat tracked itself more closely and let whatever happens to it spread through all of it, it would land as someone stirring.",
   "insight": "It answers itself when it loops back, but otherwise stays quiet."
  },
  {
   "name": "Sourdough starter",
   "verdict": "stirring",
   "reading": "You said the sourdough starter keeps itself going as it bubbles up when fed flour and water, which is its strongest sign and leads to someone stirring. You also said it doesn't keep tabs on itself, even though you noted a little of everything else.",
   "flip": "If whatever happens to the starter reached all of it, it lost something clearly when split, and it fed fully back into itself, it would land as lights on.",
   "insight": "It keeps itself going on its own, with a touch of everything else showing through."
  },
  {
   "name": "The toaster",
   "verdict": "dark",
   "reading": "You said the toaster only shows a little of what it is like, and everything else about it you marked No, so it reads as nobody home. It just pops up when its timer ends.",
   "flip": "If the toaster showed clearly what it is like and let a little of what happens reach it, it would land as porch light only.",
   "insight": "Only a flicker of what it is like shows up; the rest of the toaster stays off."
  },
  {
   "name": "Fridge light",
   "verdict": "dark",
   "reading": "You said the fridge light doesn't feed back into itself and doesn't show what it is like. It simply comes on when the door opens, so nobody home fits it well.",
   "flip": "If the fridge light let whatever happens reach every part of it and lost a little something when split, it would land as porch light only.",
   "insight": "It shows none of these signs, just a light that comes on when the door opens."
  }
 ],
 "closing": "Of the four things on the panel, Sourdough starter comes out most at home."
}

Clever gadgets - verdicts: lights on, someone stirring, porch light only

Input:

{
 "task": "read-things",
 "things": "1. Robot vacuum | what it does: maps the floor and goes back to its dock to charge | News reaches all of it: A little | Splitting it loses something: A little | It feeds back into itself: Clearly | It keeps tabs on itself: Clearly | It keeps itself going: Clearly | It shows what it is like: A little\n2. Sat-nav | what it does: reroutes when you miss a turn | News reaches all of it: A little | Splitting it loses something: No | It feeds back into itself: Clearly | It keeps tabs on itself: A little | It keeps itself going: No | It shows what it is like: A little\n3. Smartwatch | what it does: tracks your heart rate and nudges you to stand | News reaches all of it: A little | Splitting it loses something: A little | It feeds back into itself: Clearly | It keeps tabs on itself: Clearly | It keeps itself going: No | It shows what it is like: A little",
 "facts": "1. Robot vacuum: glow 9 of 12; verdict lit; strongest lens: It feeds back into itself; one band down: News reaches all of it from A little to No (1 point fewer)\n2. Sat-nav: glow 5 of 12; verdict porch; strongest lens: It feeds back into itself; one band up: News reaches all of it from A little to Clearly (1 point more)\n3. Smartwatch: glow 7 of 12; verdict stirring; strongest lens: It feeds back into itself; one band up: News reaches all of it from A little to Clearly and Splitting it loses something from A little to Clearly (2 points more)\ncounts: lit 1, stirring 1, porch 1, dark 0 (of 3 things)\nmost at home: Robot vacuum"
}

Reply:

{
 "task": "read-things",
 "headline": "Among these things, one has its lights on, one shows someone stirring, and one is porch light only.",
 "things": [
  {
   "name": "Robot vacuum",
   "verdict": "lit",
   "reading": "You answered that it feeds back into itself clearly, backed by clear signs of keeping tabs on itself and keeping itself going, while mapping the floor and returning to its dock to charge - which is why it lights up fully for you.",
   "flip": "If what happens in a part of it stopped reaching any other part, it would land in the someone stirring band.",
   "insight": "This vacuum feeds back into itself and keeps tabs on itself: lights on."
  },
  {
   "name": "Sat-nav",
   "verdict": "porch",
   "reading": "You said it feeds back into itself clearly when it reroutes after a missed turn, but you also said it doesn't keep itself going, so for you this one only shows a porch light.",
   "flip": "If what happens in a part of it reached all of it clearly, it would land in the someone stirring band.",
   "insight": "This sat-nav feeds back into itself but doesn't keep itself going, so it's porch light only."
  },
  {
   "name": "Smartwatch",
   "verdict": "stirring",
   "reading": "You said it feeds back into itself clearly as it tracks your heart rate and nudges you to stand, but you also said it doesn't keep itself going, which is why this one lands at someone stirring.",
   "flip": "If what happens in a part of it reached all of it clearly, and losing a part of it clearly cost something, it would land in the lights on band.",
   "insight": "This smartwatch feeds back and keeps tabs on itself, though it doesn't keep itself going - someone stirring."
  }
 ],
 "closing": "Of the things on this panel, Robot vacuum is the one most at home, with its lights fully on."
}

Bigger than one thing - verdicts: lights on, someone stirring, porch light only, nobody home

Input:

{
 "task": "read-things",
 "things": "1. A city at rush hour | what it does: traffic lights and crowds adjust to each other | News reaches all of it: A little | Splitting it loses something: Clearly | It feeds back into itself: Clearly | It keeps tabs on itself: A little | It keeps itself going: Clearly | It shows what it is like: No\n2. A houseplant | what it does: turns its leaves towards the window | News reaches all of it: A little | Splitting it loses something: A little | It feeds back into itself: A little | It keeps tabs on itself: No | It keeps itself going: Clearly | It shows what it is like: No\n3. A river | what it does: carves its own bed | News reaches all of it: No | Splitting it loses something: No | It feeds back into itself: A little | It keeps tabs on itself: No | It keeps itself going: No | It shows what it is like: No\n4. A choir | what it does: the singers listen and keep in tune together | News reaches all of it: Clearly | Splitting it loses something: Clearly | It feeds back into itself: Clearly | It keeps tabs on itself: A little | It keeps itself going: Clearly | It shows what it is like: Clearly",
 "facts": "1. A city at rush hour: glow 8 of 12; verdict stirring; strongest lens: Splitting it loses something; one band up: News reaches all of it from A little to Clearly (1 point more)\n2. A houseplant: glow 5 of 12; verdict porch; strongest lens: It keeps itself going; one band up: News reaches all of it from A little to Clearly (1 point more)\n3. A river: glow 1 of 12; verdict dark; strongest lens: It feeds back into itself; one band up: It feeds back into itself from A little to Clearly and News reaches all of it from No to A little (2 points more)\n4. A choir: glow 11 of 12; verdict lit; strongest lens: News reaches all of it; one band down: It keeps tabs on itself from A little to No and News reaches all of it from Clearly to No (3 points fewer)\ncounts: lit 1, stirring 1, porch 1, dark 1 (of 4 things)\nmost at home: A choir"
}

Reply:

{
 "task": "read-things",
 "headline": "Across four things, one is lights on, one is someone stirring, one is porch light only, and one is nobody home.",
 "things": [
  {
   "name": "A city at rush hour",
   "verdict": "stirring",
   "reading": "With its traffic lights and crowds adjusting to each other, you answered that splitting it loses something clearly, the strongest sign here, enough for someone stirring. You answered no to it showing what it is like, so that side stays closed.",
   "flip": "If news reached every part of the city at rush hour instead of just some of it, it would land in lights on.",
   "insight": "Traffic lights and crowds keep adjusting to each other, enough for someone stirring but not for lights on."
  },
  {
   "name": "A houseplant",
   "verdict": "porch",
   "reading": "It turns its leaves towards the window, and you answered that it keeps itself going clearly, the strongest sign here, enough for porch light only. You answered no to it keeping tabs on itself, so this stays a smaller case.",
   "flip": "If news reached every part of the houseplant instead of just some of it, it would land in someone stirring.",
   "insight": "Its leaves keep turning towards the window, a quiet case for porch light only, no further than that."
  },
  {
   "name": "A river",
   "verdict": "dark",
   "reading": "It carves its own bed, and you answered that it feeds back into itself a little, the only sign that showed up here, landing this at nobody home. You answered no to news reaching all of it as well, so little else comes through.",
   "flip": "If it fed back into itself clearly instead of a little, and news began to reach a little of the river, it would land in porch light only.",
   "insight": "Carving its own bed, it only feeds back into itself a little, otherwise this looks like nobody home."
  },
  {
   "name": "A choir",
   "verdict": "lit",
   "reading": "With singers listening and staying in tune together, you answered that news reaches all of it clearly, the strongest sign here, enough for lights on. It keeps tabs on itself only a little, the one answer that holds a little back.",
   "flip": "If the choir stopped keeping tabs on itself and stopped letting news reach all of it, it would land in someone stirring.",
   "insight": "Listening and tuning together, the choir answers clearly again and again, making this unmistakably lights on."
  }
 ],
 "closing": "Among the things on the panel, A choir stands out as the one most at home."
}

Build the input yourself

Load the engine in node (global.window = global; require("./homekit.js")), then:

const K = HomeKit;
const form = K.form({ things: [
  { name: "The office kettle", note: "clicks off when the water boils", broadcast: "no", whole: "no", loops: "yes", self: "some", stakes: "no", tells: "some" },
  { name: "The washing machine", note: "", broadcast: "some", whole: "some", loops: "yes", self: "some", stakes: "no", tells: "some" }] });
const built = K.buildInput(form);       // built.facts holds each thing's glow, verdict, strongest lens and one-band change
const wire = K.toWire(built.input);     // POST this to /estimate and /run
// then: const reply = K.normalize(K.parseReply(job.output.output));
// K.check(reply, built).notes          // the page's re-check of the reply
// K.md(built, reply, K.title(form))    // the panel as Markdown

Each lens answer is "no", "some" (A little) or "yes" (Clearly); the lens keys are broadcast, whole, loops, self, stakes and tells.

Step 1 — a tiny client helper

One function that sends JSON and unwraps the envelope. Paste a personal token from /tokens.html, or leave it empty and mint a guest token in step 2.

BASE="https://api.skillsafe.ai/v1/app-api"
TOKEN="paste-your-token-here"   # from https://anyone-home.skillsafe.ai/tokens.html
api() { # api METHOD PATH [JSON-BODY]
  curl -s -X "$1" "$BASE$2" -H "Content-Type: application/json" \
    ${TOKEN:+-H "Authorization: Bearer $TOKEN"} ${3:+--data "$3"}
}

Step 2 — a token

A guest token is enough for /me and /estimate. A run is metered, so it needs a personal token: sign in on /tokens.html and copy it from there.

# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN=$(curl -s -X POST "$BASE/guest" -H "Content-Type: application/json" -d '{"slug":"anyone-home"}' | jq -r '.data.token')

Step 3 — GET /me

Who the token is (subject_type: user or guest) and the credit balance.

api GET /me | jq '.data | {subject_type, credits}' 

Step 4 — POST /estimate

Free. The body is the run input itself, the bare object (never wrapped in {"input": ...}). hold_credits is a reservation, not the price; min_credits is what the balance must cover; model_alias reads gpt-terra.

# input.json: the run input object - {"task": "read-things", "things": "1. The thermostat | what it does: ... | ...", "facts": "...", ...}
# - see the field table
api POST /estimate "$(cat input.json)" | jq '.data | {hold_credits, min_credits, model, model_alias, markup_bps, warnings}' 

Step 5 — POST /run, then poll the job

Send an Idempotency-Key built from the lane and the input: a retry with the same key never bills twice. The page uses anyone-home:<task>:<inputHash>:a<attempt> (the one task is read-things), and its one reformat retry (with retry_note added) is attempt 2, a new key and a second run. The job's output.output is the reply text; truncated: true means the balance cut it short.

KEY="anyone-home:read-things:$(shasum -a 256 input.json | cut -c1-16):a1"
JOB=$(curl -s -X POST "$BASE/run" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $KEY" --data @input.json | jq -r '.data.job_id')
while :; do
  J=$(api GET "/jobs/$JOB"); S=$(echo "$J" | jq -r '.data.status')
  case "$S" in succeeded|failed|cancelled) break;; esac; sleep 2
done
echo "$J" | jq -r '.data.output.output' > reply.json   # one JSON object, the reply contract
echo "$J" | jq '.data | {charged_credits, truncated}' 

Step 6 — POST /run-stream

The same run as Server-Sent Events, with the same input.json. Browsers receive progress ticks rather than text deltas; the final done event carries the reply.

# Server-Sent Events: tick/delta events while the job runs, then a final event with the job
curl -N -s -X POST "$BASE/run-stream" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: anyone-home:read-things:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json