← Among the Locals
API

Drive Among the Locals from your own code

The one metered task, field-report, is available over HTTP. It takes one everyday ritual - its name, setting, what happens, who takes part and what happens if it is skipped - plus the page's own seven-marker check and the verdict. It returns a mock-scholarly name, a field note, a reading of each marker, what the ritual does for the people in it, two or three house rules, what happens if it breaks, a museum placard caption and a closing line.

The division of labour first: a fixed rule on the page picks the verdict from the seven answers; the model only writes the words. After a run the page checks that the report copied the verdict and every marker's answer, did not find a marker answered "no", and kept to its word limits. A playful lens, not professional advice.

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":"among-the-locals"}), 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, what_happens, markers, verdict and the rest of the field table) 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 field report is metered and needs 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: field-report (the one task is field-report); a missing or different one is still answered as field-report. Each of the seven markers is answered yes, no or unsure; only yes counts. The verdict, checked in order: threshold is yes - threshold-rite; exchange is yes - gift-circle; roles is yes and sanction or unspoken is yes - pecking-order; three or more markers are yes - set-ceremony; otherwise loose-habit.

FieldRequiredWhat it holds
taskyesAlways field-report.
ritual_name, settingyesWhat the person calls it and where it happens (60 characters each), or (not given).
what_happensyesWhat happens, at least 12 and at most 280 characters.
who_takes_part, if_skippedyesWho takes part and what happens if it is skipped (120 each), or (not given).
markersyes7 lines in the order sequence, objects, roles, unspoken, sanction, exchange, threshold, such as roles: yes - Do particular people always do particular parts?.
strengthyesHow many markers are yes, such as 4 of 7.
verdictyesThe page's verdict id.
retry_notenoOnly on the page's single reformat retry.

The reply is one JSON object:

{"verdict": "gift-circle", "field_name": "...", "observation": "...", "markers": [{"id": "sequence", "state": "no", "reading": "..."}, {"id": "objects", "state": "yes", "reading": "..."}, ... 7 in all], "function": "...", "house_rules": ["...", "..."], "if_broken": "...", "placard": "...", "closing": "..."}
FieldWhat it holds
verdictCopied from the input.
field_name, observationA mock-scholarly name (at most 7 words) and a field note retelling what happens (at most 45).
markers7 objects in the input's order: state copied from the answer, reading what the marker does (yes, at most 20 words) or a plain note (no or unsure, at most 12).
functionWhat the ritual does for the people in it, read through the verdict (at most 30).
house_rules2 or 3 rules restating what the input says happens (at most 16 words each).
if_broken, placard, closingWhat happens if it breaks (24), a museum placard caption (25) and a closing line (18).

The page then checks the reply (FieldKit.check) and lists any disagreement under "The page's check".

Worked examples - every verdict

These are the five free samples on the page: the exact input the page sends and the reply that replays for free.

The Friday bell - marks a change: a threshold rite

Input:

{
 "task": "field-report",
 "ritual_name": "the Friday bell",
 "setting": "our small design office",
 "what_happens": "On Friday afternoons the last person to send off their work rings the little brass bell on the shelf, everyone says 'weekend' together and the laptops close.",
 "who_takes_part": "the whole team; whoever finishes last rings it",
 "if_skipped": "people just keep working a little longer",
 "markers": "sequence: yes - Does it go in the same order every time?\nobjects: yes - Is a particular object, seat or spot part of it?\nroles: yes - Do particular people always do particular parts?\nunspoken: unsure - Are there rules nobody has ever said out loud?\nsanction: no - Does something happen if someone skips it or gets it wrong?\nexchange: no - Is something given, passed on or paid back?\nthreshold: yes - Does it mark a change - an arrival, a leaving, a start or an end?",
 "strength": "4 of 7",
 "verdict": "threshold-rite"
}

Reply:

{
 "verdict": "threshold-rite",
 "field_name": "The Rite of the Friday Bell",
 "observation": "In your small design office, Friday afternoons close when the last person to send off their work rings the little brass bell on the shelf; the whole team says 'weekend' together, and the laptops close.",
 "markers": [
  {
   "id": "sequence",
   "state": "yes",
   "reading": "It unfolds in the same order: the last person rings the bell, then 'weekend' is said, then laptops close."
  },
  {
   "id": "objects",
   "state": "yes",
   "reading": "The little brass bell on the shelf is the one object this ritual always uses."
  },
  {
   "id": "roles",
   "state": "yes",
   "reading": "Whoever is last to send off their work takes on the part of ringing the bell."
  },
  {
   "id": "unspoken",
   "state": "unsure",
   "reading": "Whether any part of this goes unsaid isn't confirmed."
  },
  {
   "id": "sanction",
   "state": "no",
   "reading": "By your answer, nothing happens if this is skipped."
  },
  {
   "id": "exchange",
   "state": "no",
   "reading": "By your answer, nothing is given, passed on or repaid."
  },
  {
   "id": "threshold",
   "state": "yes",
   "reading": "It marks the end of the afternoon's work, when everyone says 'weekend' and laptops close."
  }
 ],
 "function": "It marks the moment work gives way to the weekend, the point where the whole team closes their laptops together.",
 "house_rules": [
  "Whoever finishes last must ring the little brass bell on the shelf.",
  "Everyone must say 'weekend' together after the bell rings.",
  "The laptops must close only after the bell rings and 'weekend' is said."
 ],
 "if_broken": "If skipped, people just keep working a little longer.",
 "placard": "In a small design office, the last person rings a brass bell on Friday afternoons as the team says 'weekend' and closes their laptops.",
 "closing": "What a lovely way to mark the turn from work into weekend, together with your team."
}

The biscuit tin - something passed on: a gift circle

Input:

{
 "task": "field-report",
 "ritual_name": "the biscuit tin",
 "setting": "our shared flat kitchen",
 "what_happens": "Whoever eats the last biscuit buys the next packet and puts it in the blue tin, and it has to be a kind nobody has bought before.",
 "who_takes_part": "the four flatmates",
 "if_skipped": "the empty tin is left on the counter where everyone can see it",
 "markers": "sequence: no - Does it go in the same order every time?\nobjects: yes - Is a particular object, seat or spot part of it?\nroles: no - Do particular people always do particular parts?\nunspoken: yes - Are there rules nobody has ever said out loud?\nsanction: yes - Does something happen if someone skips it or gets it wrong?\nexchange: yes - Is something given, passed on or paid back?\nthreshold: no - Does it mark a change - an arrival, a leaving, a start or an end?",
 "strength": "4 of 7",
 "verdict": "gift-circle"
}

Reply:

{
 "verdict": "gift-circle",
 "field_name": "On the Replenishment of the Biscuit Tin",
 "observation": "In the shared flat kitchen, whichever of the four flatmates eats the last biscuit buys the next packet and places it in the blue tin, and it must be a kind nobody has bought before.",
 "markers": [
  {
   "id": "sequence",
   "state": "no",
   "reading": "By your answer, this ritual follows no set order."
  },
  {
   "id": "objects",
   "state": "yes",
   "reading": "The blue tin is the fixed object here, the exact one that must hold the newly bought packet."
  },
  {
   "id": "roles",
   "state": "no",
   "reading": "By your answer, no one person owns this part."
  },
  {
   "id": "unspoken",
   "state": "yes",
   "reading": "The rule that it must be a kind nobody has bought before is never spoken, just followed."
  },
  {
   "id": "sanction",
   "state": "yes",
   "reading": "Skip or botch it and the empty tin sits on the counter in plain view of everyone."
  },
  {
   "id": "exchange",
   "state": "yes",
   "reading": "Finishing the last biscuit obliges you to buy and supply the next packet for the tin."
  },
  {
   "id": "threshold",
   "state": "no",
   "reading": "By your answer, this ritual marks no such change."
  }
 ],
 "function": "The next packet of biscuits is what's passed on, and buying it each time keeps the tin's cycle going.",
 "house_rules": [
  "Whoever eats the last biscuit must buy the next packet.",
  "The new packet must go into the blue tin.",
  "The unwritten rule is that the replacement must be a kind not already bought."
 ],
 "if_broken": "If someone skips it or gets it wrong, the empty tin is left on the counter where everyone can see it.",
 "placard": "In the shared flat kitchen, a blue tin waits to be filled with a fresh biscuit packet by whoever eats the last one.",
 "closing": "What a quietly generous way to keep passing biscuits on in your kitchen."
}

The good sofa corner - set roles with unwritten rules: a pecking order, nothing recorded if skipped

Input:

{
 "task": "field-report",
 "ritual_name": "the good corner of the sofa",
 "setting": "our living room on film nights",
 "what_happens": "Whoever cooked dinner gets the corner seat with the footrest; everyone else sits in the order they came in, and nobody takes the corner while the cook is still washing up.",
 "who_takes_part": "my housemates and me",
 "if_skipped": "(not given)",
 "markers": "sequence: yes - Does it go in the same order every time?\nobjects: yes - Is a particular object, seat or spot part of it?\nroles: yes - Do particular people always do particular parts?\nunspoken: yes - Are there rules nobody has ever said out loud?\nsanction: unsure - Does something happen if someone skips it or gets it wrong?\nexchange: no - Is something given, passed on or paid back?\nthreshold: no - Does it mark a change - an arrival, a leaving, a start or an end?",
 "strength": "4 of 7",
 "verdict": "pecking-order"
}

Reply:

{
 "verdict": "pecking-order",
 "field_name": "The Cook's Precedence at the Sofa Corner",
 "observation": "On film nights in your living room, among you and your housemates, whoever cooked dinner gets the corner seat with the footrest, everyone else sits in the order they came in, and nobody takes the corner while the cook is still washing up.",
 "markers": [
  {
   "id": "sequence",
   "state": "yes",
   "reading": "Keeps the same order each time: everyone else sits exactly in the order they came in."
  },
  {
   "id": "objects",
   "state": "yes",
   "reading": "Centers on a particular spot, the corner seat with the footrest."
  },
  {
   "id": "roles",
   "state": "yes",
   "reading": "The cook always gets the corner seat; that part always belongs to whoever cooked."
  },
  {
   "id": "unspoken",
   "state": "yes",
   "reading": "No one spells it out, yet nobody takes the corner while the cook is still washing up."
  },
  {
   "id": "sanction",
   "state": "unsure",
   "reading": "Not confirmed whether skipping or getting it wrong leads anywhere."
  },
  {
   "id": "exchange",
   "state": "no",
   "reading": "By your account, nothing is given, passed on or paid back here."
  },
  {
   "id": "threshold",
   "state": "no",
   "reading": "By your account, no arrival, leaving, start or end is marked."
  }
 ],
 "function": "It shows that whoever cooks dinner gets the corner seat, while everyone else's place follows from when they came in.",
 "house_rules": [
  "This unwritten rule says whoever cooks dinner must get the corner seat and footrest.",
  "Everyone else must sit in the order they came in.",
  "The corner must stay free until the cook finishes washing up."
 ],
 "if_broken": "Your notes do not record what happens if this is skipped or done wrong.",
 "placard": "In the living room on a film night, the cook takes the corner seat and footrest, and housemates settle in the order they came in.",
 "closing": "Thank you for letting me into your sofa's corner and order."
}

The plant round - three markers, no roles: a set ceremony

Input:

{
 "task": "field-report",
 "ritual_name": "the plant round",
 "setting": "my flat",
 "what_happens": "I water the plants in the same order every time, starting with the fern by the window, always with the chipped green jug, and I say each plant's name as I go.",
 "who_takes_part": "just me",
 "if_skipped": "nothing happens; the plants just get watered later",
 "markers": "sequence: yes - Does it go in the same order every time?\nobjects: yes - Is a particular object, seat or spot part of it?\nroles: no - Do particular people always do particular parts?\nunspoken: yes - Are there rules nobody has ever said out loud?\nsanction: no - Does something happen if someone skips it or gets it wrong?\nexchange: no - Is something given, passed on or paid back?\nthreshold: no - Does it mark a change - an arrival, a leaving, a start or an end?",
 "strength": "3 of 7",
 "verdict": "set-ceremony"
}

Reply:

{
 "verdict": "set-ceremony",
 "field_name": "The Rite of the Plant Round",
 "observation": "In your flat, you water the plants in the same order every time: starting with the fern by the window, always with the chipped green jug, saying each plant's name as you go.",
 "markers": [
  {
   "id": "sequence",
   "state": "yes",
   "reading": "Fixes the order of watering, starting at the fern by the window each time."
  },
  {
   "id": "objects",
   "state": "yes",
   "reading": "The chipped green jug is the one tool always used for this watering."
  },
  {
   "id": "roles",
   "state": "no",
   "reading": "By your answer, no one else takes a fixed part in this."
  },
  {
   "id": "unspoken",
   "state": "yes",
   "reading": "Naming each plant as you go is a practice never spelled out as a rule."
  },
  {
   "id": "sanction",
   "state": "no",
   "reading": "By your answer, nothing happens if this is skipped or missed."
  },
  {
   "id": "exchange",
   "state": "no",
   "reading": "By your answer, nothing is given, passed on or paid back here."
  },
  {
   "id": "threshold",
   "state": "no",
   "reading": "By your answer, no arrival, leaving, start or end is marked."
  }
 ],
 "function": "Doing the plants in the same order, with the same jug, each time gives this small task a steady, reliable shape.",
 "house_rules": [
  "The fern by the window must be watered before any other plant, every time.",
  "The chipped green jug must be the one used for every watering.",
  "Each plant's name must be said aloud, though the rule is unwritten."
 ],
 "if_broken": "Your notes say nothing happens if this is skipped; the plants just get watered later.",
 "placard": "In the flat, the fern by the window is watered before the other plants, from the chipped green jug, while each plant's name is spoken.",
 "closing": "What a tidy little rhythm you keep with your plants and that chipped green jug."
}

Coffee before email - no marker present: a loose habit

Input:

{
 "task": "field-report",
 "ritual_name": "coffee before email",
 "setting": "(not given)",
 "what_happens": "Most workdays I make a coffee before opening my email, though some days I forget and open the laptop first.",
 "who_takes_part": "(not given)",
 "if_skipped": "nothing happens",
 "markers": "sequence: unsure - Does it go in the same order every time?\nobjects: no - Is a particular object, seat or spot part of it?\nroles: no - Do particular people always do particular parts?\nunspoken: no - Are there rules nobody has ever said out loud?\nsanction: no - Does something happen if someone skips it or gets it wrong?\nexchange: no - Is something given, passed on or paid back?\nthreshold: unsure - Does it mark a change - an arrival, a leaving, a start or an end?",
 "strength": "0 of 7",
 "verdict": "loose-habit"
}

Reply:

{
 "verdict": "loose-habit",
 "field_name": "The Coffee Before Email Custom",
 "observation": "On most workdays, you make a coffee before opening your email; on the days you forget, you open the laptop first instead.",
 "markers": [
  {
   "id": "sequence",
   "state": "unsure",
   "reading": "Not confirmed either way whether this always follows the same order."
  },
  {
   "id": "objects",
   "state": "no",
   "reading": "No particular object, seat or spot is part of this."
  },
  {
   "id": "roles",
   "state": "no",
   "reading": "No one in particular is assigned a special part here."
  },
  {
   "id": "unspoken",
   "state": "no",
   "reading": "No rules here go unsaid, by your answer."
  },
  {
   "id": "sanction",
   "state": "no",
   "reading": "By your answer, nothing happens if this is skipped or missed."
  },
  {
   "id": "exchange",
   "state": "no",
   "reading": "Nothing is given, passed on or paid back here."
  },
  {
   "id": "threshold",
   "state": "unsure",
   "reading": "Not confirmed either way whether this marks any change."
  }
 ],
 "function": "Honestly, this still reads more like a habit than a ritual - nothing here yet tips it toward one.",
 "house_rules": [
  "You must make a coffee on most workdays.",
  "You must open your email on most workdays."
 ],
 "if_broken": "Nothing happens if this is skipped.",
 "placard": "A coffee is made before the email opens; on some days, the laptop opens first instead.",
 "closing": "Thank you for sharing this coffee-and-email moment from your workdays."
}

Build the input yourself

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

const K = FieldKit;
const built = K.buildInput(K.form({ ritual_name: "the good mug", setting: "", what_happens: "Whoever arrives first fills the kettle and uses the good mug.", who: "", if_skipped: "",
  answers: { sequence: "yes", objects: "yes", roles: "yes", unspoken: "no", sanction: "no", exchange: "no", threshold: "unsure" } }));
built.facts.verdict                     // the verdict the page's rule gives
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, "the good mug")   // the report as Markdown

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://among-the-locals.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":"among-the-locals"}' | 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": "field-report", "ritual_name": "the biscuit tin", "setting": "our shared flat kitchen", "what_happens": "Whoever eats the last biscuit buys the next packet ...", "who_takes_part": "the four flatmates", "if_skipped": "...", "markers": "sequence: no - ...\nobjects: yes - ...", "strength": "4 of 7", "verdict": "gift-circle"}
# - 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 among-the-locals:<task>:<inputHash>:a<attempt> (the one task is field-report), 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="among-the-locals:field-report:$(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: among-the-locals:field-report:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json