← Do Not Dig Here
Marker API
Tokens

Drive Do Not Dig Here from your own code

The one metered task, carve, is available over HTTP. It takes what is sealed, where it is, when it was sealed, why nobody should open it, what the finder should do instead, a tone, how long the marker must work, your own draft warning and the page's drift scan of that draft. It returns a four-layer far-future warning (a top line, a warning, what, where, when and why, and the full record), 2 to 4 pictograms from a fixed set, every phrase in the draft that will not survive with a plain swap, a verdict on the draft, a line for a five-year-old in the house today and how a far-future finder might misread the top line.

The division of labour first: the page owns the drift scan, the weathering slider and the verdict rule; the model owns the reading of the draft and the wording of the marker; the page re-checks the reply.

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": "...", "status": 402, "details": { ... } } }

The token is minted for this app (the guest call takes {"slug":"do-not-dig-here"}), 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, thing, where, sealed, danger, wish, tone, horizon, draft, drift_scan) 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: a carving is metered and needs a personal token.
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 and the verdicts

Every run sends task: carve (the one task is carve); a missing or different one is still answered as carve. The verdict on the draft is a rule, checked in order: fresh if the draft is (no draft); recarve if the draft never names the thing or never says where it is; recarve if 3 or more phrases will not survive; patch for 1 or 2; durable for none. The model reports the two draft checks and the drift list it counted, so the page can recompute the verdict and warn if it differs.

Input fields (every value is a string)

FieldRequiredWhat it holds
taskyesAlways carve.
thingyesWhat is sealed (at most 80 characters), or (not given).
whereyesWhere it is (at most 80), or (not given).
sealedyes<Month> <year>, <year> or not given.
danger / wishyesWhy nobody should open it (at most 300) and what to do instead (at most 140), or (not given).
toneyesdeadpan, solemn or frantic.
horizonyes1 year, 100 years, 1,000 years or 10,000 years.
draftyesYour own warning (at most 600), or (no draft).
drift_scanyesOne line per flagged phrase, <n> | <phrase> | <name|date|slang|shout|in-joke>, or (none), or (no draft).
clip_notenoWhat the page shortened, if anything.
retry_notenoOnly on the automatic reformat retry.

The reply

One JSON object, in output.output of the finished job:

{"task": "carve", "title": "...", "draft_names_thing": true, "draft_says_where": true,
 "drift": [{"phrase": "...", "kind": "name | date | slang | shout | in-joke | brand", "swap": "..."}],
 "verdict": "fresh | durable | patch | recarve", "verdict_reason": "...",
 "level1": "...", "level2": "...", "level3": {"what": "...", "where": "...", "when": "...", "why": "..."}, "level4": "...",
 "pictograms": [{"id": "face | hand | lid | rays | nose | knot | door | walk | eye | suns | fire | spike", "why": "..."}],
 "kid_line": "...", "misreading": "..."}
FieldWhat it holds
draft_names_thing / draft_says_whereWhether the draft itself names what is sealed and says where it is (both false with no draft).
driftEvery phrase from the page's scan, in order, plus any other phrase that depends on outside knowledge, each with a plain swap of at most 12 words.
verdict / verdict_reasonThe rule above, and one sentence of facts behind it.
level1 to level4The top line (at most 8 words, no numbers), the warning (at most 25), four facts of at most 14 words each, the full record (40 to 110 words) in the chosen tone.
pictograms2 to 4 ids from the fixed set, always including face; suns only for 1,000 years or more.
kid_line / misreadingA line for a five-year-old today (at most 15 words) and a deadpan misreading of the top line and pictograms (at most 35).
titleA playful name of at most 8 words.

The page then checks the reply against the form (MarkKit.check): the verdict against the rule, every scanned phrase answered in the drift, every drift phrase really in the draft, the word limits, the sealed year in the 'when' line and no date that was never given, 2 to 4 pictograms from the set, no name from the draft on the marker, no exclamation marks, no he or she, no "years ago" and no internal field name in the prose.

Worked examples, one per verdict

These are the four free samples on the page: the exact input and a stand-in model's reply, unedited. Together they cover recarve, durable, patch and fresh.

The tub at the back - recarve

Input:

{
 "task": "carve",
 "thing": "A takeaway tub of curry",
 "where": "The bottom shelf of the fridge, behind the pickle jar",
 "sealed": "August 2026",
 "danger": "The lid bulges and the smell clears the kitchen when anyone lifts it.",
 "wish": "Carry it to the outside bin without opening it.",
 "tone": "deadpan",
 "horizon": "10,000 years",
 "draft": "DO NOT open Dave's curry from August!! Trust me. Ask Priya if unsure lol",
 "drift_scan": "1 | DO NOT | shout\n2 | Dave's | name\n3 | August | date\n4 | !! | shout\n5 | Trust me | in-joke\n6 | Priya | name\n7 | lol | slang"
}

Reply:

{
 "task": "carve",
 "title": "The Curry That Must Never Be Opened",
 "draft_names_thing": true,
 "draft_says_where": false,
 "drift": [
  {
   "phrase": "DO NOT",
   "kind": "shout",
   "swap": "do not open, in plain letters"
  },
  {
   "phrase": "Dave's",
   "kind": "name",
   "swap": "someone who lived here"
  },
  {
   "phrase": "August",
   "kind": "date",
   "swap": "2026"
  },
  {
   "phrase": "!!",
   "kind": "shout",
   "swap": "a plain full stop"
  },
  {
   "phrase": "Trust me",
   "kind": "in-joke",
   "swap": "leave it out"
  },
  {
   "phrase": "Priya",
   "kind": "name",
   "swap": "someone else"
  },
  {
   "phrase": "lol",
   "kind": "slang",
   "swap": "leave it out"
  }
 ],
 "verdict": "recarve",
 "verdict_reason": "The draft never says where the tub is kept, so it cannot stand alone as the marker.",
 "level1": "People sealed this. It is not good.",
 "level2": "If this is opened, the lid bulges and the smell clears the kitchen. Keep it closed and do not open it.",
 "level3": {
  "what": "A takeaway tub of curry, sealed shut.",
  "where": "Bottom shelf of a cold box for food, a fridge, behind a pickle jar.",
  "when": "Sealed in August 2026.",
  "why": "The lid bulges and the smell clears the kitchen if lifted."
 },
 "level4": "A takeaway tub of curry was sealed here by the people who lived here. It sits on the bottom shelf of a cold box for food, a fridge, behind a pickle jar. It was sealed in August 2026. The lid bulges and the smell clears the kitchen when anyone lifts it. Do not open it. Carry it to the outside bin without opening it.",
 "pictograms": [
  {
   "id": "face",
   "why": "Something here is clearly wrong, shown by the bulging lid."
  },
  {
   "id": "lid",
   "why": "The tub must stay closed to keep the bad smell inside."
  },
  {
   "id": "nose",
   "why": "Opening it lets a strong smell fill the whole kitchen."
  },
  {
   "id": "suns",
   "why": "This warning must keep working for a very long stretch of time."
  }
 ],
 "kid_line": "Please do not open the tub in the fridge. Just leave it there.",
 "misreading": "A finder might think something bad and smelly was sealed because people dreaded it and wanted it kept shut for a very long time."
}

The cable drawer - durable

Input:

{
 "task": "carve",
 "thing": "A drawer of tangled charger cables",
 "where": "The kitchen drawer under the toaster",
 "sealed": "2019",
 "danger": "Pull one cable and the whole knot comes out with it, and it takes an hour to put back.",
 "wish": "Close it again and leave the knot alone.",
 "tone": "solemn",
 "horizon": "1,000 years",
 "draft": "Knotted cables in this kitchen drawer under the toaster. Pull one and all of them come out. Keep it shut.",
 "drift_scan": "(none)"
}

Reply:

{
 "task": "carve",
 "title": "The Cable Knot That Must Not Be Freed",
 "draft_names_thing": true,
 "draft_says_where": true,
 "drift": [],
 "verdict": "durable",
 "verdict_reason": "No phrase in the draft depends on a name, date, slang, shout, or shared memory, so nothing needs to be recarved.",
 "level1": "People sealed this, and it is not good.",
 "level2": "Pulling a cable drags the whole tangle out, and it is slow to undo. Leave it closed.",
 "level3": {
  "what": "A drawer of tangled charger cables.",
  "where": "The kitchen drawer under the toaster.",
  "when": "Sealed in 2019.",
  "why": "Pulling a cable drags the whole tangle out, and it is slow to fix."
 },
 "level4": "Here is a drawer of tangled charger cables, kept in the kitchen drawer under the toaster. It was sealed in 2019. Do not open it. Pulling a cable draws the whole tangle out with it, and setting it right again takes a long time. Close the drawer again, and leave the knot alone: this is what was asked. Nothing more about this is written. Let it remain closed and undisturbed.",
 "pictograms": [
  {
   "id": "face",
   "why": "Opening the drawer causes a tangle that takes a long time to undo."
  },
  {
   "id": "knot",
   "why": "The cables inside are tangled, and pulling any of them drags the rest loose."
  },
  {
   "id": "lid",
   "why": "Closing the drawer again and leaving it alone is what should happen."
  },
  {
   "id": "suns",
   "why": "This marker must stay clear and true for a very long time."
  }
 ],
 "kid_line": "Please leave this drawer shut and do not pull on any cables.",
 "misreading": "Reading only that people sealed something bad, saw a tangled knot, a shut lid, and endless suns, a finder might conclude a dangerous beast was imprisoned for all time."
}

The chilli jar - patch

Input:

{
 "task": "carve",
 "thing": "A jar of pickled chillies",
 "where": "The top shelf of the pantry",
 "sealed": "2024",
 "danger": "Far too hot to eat. Everyone who tried one cried.",
 "wish": "(not given)",
 "tone": "frantic",
 "horizon": "100 years",
 "draft": "Pickled chillies on this top shelf. Too hot to eat. Opened once in 2024 and everyone cried. Keep the lid on.",
 "drift_scan": "1 | 2024 | date"
}

Reply:

{
 "task": "carve",
 "title": "The Chilli Jar That Must Stay Shut",
 "draft_names_thing": true,
 "draft_says_where": true,
 "drift": [
  {
   "phrase": "2024",
   "kind": "date",
   "swap": "the year it was sealed"
  }
 ],
 "verdict": "patch",
 "verdict_reason": "One phrase, the year, will not survive; everything else in the draft can stay.",
 "level1": "People sealed something here. It is not good.",
 "level2": "It is far too hot to eat and will make you cry if you try it. Keep it closed.",
 "level3": {
  "what": "A jar of pickled chillies.",
  "where": "The top shelf of the pantry.",
  "when": "Sealed in 2024.",
  "why": "Far too hot to eat. Everyone who tried one cried."
 },
 "level4": "Do not open this. Do not open it. A jar of pickled chillies sits on the top shelf of the pantry. It was sealed in 2024. It is far too hot to eat. Everyone who tried one cried. Leave it closed. Do not open it. Leave it closed. It must stay closed. Leave it closed.",
 "pictograms": [
  {
   "id": "face",
   "why": "Something sealed here is bad and far too hot to eat."
  },
  {
   "id": "lid",
   "why": "The jar was sealed and should stay closed."
  },
  {
   "id": "fire",
   "why": "The chillies inside are far too hot to eat."
  },
  {
   "id": "hand",
   "why": "Tasting it made everyone who tried it cry."
  }
 ],
 "kid_line": "It is too hot. Please do not open it. Leave it closed.",
 "misreading": "A future finder might think people sealed something here because it is a dreaded, burning, untouchable thing that must stay shut and is simply not good."
}

The attic box - fresh

Input:

{
 "task": "carve",
 "thing": "A box of my teenage diaries",
 "where": "The attic, behind the water tank",
 "sealed": "2009",
 "danger": "Deeply embarrassing poems about a band I loved.",
 "wish": "Leave it closed. If you must move it, do not read it.",
 "tone": "solemn",
 "horizon": "10,000 years",
 "draft": "(no draft)",
 "drift_scan": "(no draft)"
}

Reply:

{
 "task": "carve",
 "title": "The Diaries That Must Never Reopen",
 "draft_names_thing": false,
 "draft_says_where": false,
 "drift": [],
 "verdict": "fresh",
 "verdict_reason": "There was no draft to check, so this marker is carved straight from the facts given.",
 "level1": "People sealed this. It is not good.",
 "level2": "Inside are poems that would deeply embarrass the person who sealed it. Keep this closed.",
 "level3": {
  "what": "A box of teenage diaries.",
  "where": "The attic, behind the water tank.",
  "when": "Sealed in 2009.",
  "why": "Poems that deeply embarrass the person who sealed it."
 },
 "level4": "Here, behind the water tank in the attic, lies a box of teenage diaries, sealed in 2009. Inside are poems that would deeply embarrass the person who sealed it, written about a band once loved. The person who sealed it asked that this remain closed, and that if it must ever be moved, no one read what is inside. That is all that is known and all that is asked. Let it stay as it was sealed.",
 "pictograms": [
  {
   "id": "face",
   "why": "This box holds something that would deeply embarrass the person who sealed it."
  },
  {
   "id": "lid",
   "why": "The wish is for this box to stay closed."
  },
  {
   "id": "eye",
   "why": "The person who sealed it asked that no one read what is inside."
  },
  {
   "id": "suns",
   "why": "This marker needs to make sense for a very long time."
  }
 ],
 "kid_line": "Leave the box alone. Do not open it or look inside.",
 "misreading": "Seeing only that people sealed something bad, a dreading face, a shut lid, a closed eye and endless suns, a finder might guess this seals away a monster for all eternity."
}

Build the input yourself

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

const K = MarkKit;
const form = K.form({ thing: "A jar of pickled chillies", where: "The top shelf of the pantry", year: "2024",
  danger: "Far too hot to eat.", tone: "frantic", horizon: "100", draft: "Too hot. Opened once in 2024. Keep the lid on." });
K.scan(form.draft);                              // [{n: 1, phrase: "2024", kind: "date", start: 23}]
const built = K.buildInput(form);
built.provisional;                               // {verdict: "", why: "1 phrase flagged so far; ..."}
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 carving
// K.md(built, reply)                            // the marker 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://do-not-dig-here.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":"do-not-dig-here"}' | 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": "carve", "thing": "A jar of pickled chillies", "where": "The top shelf of the pantry", "sealed": "2024", "danger": "Far too hot to eat.", "wish": "(not given)", "tone": "frantic", "horizon": "100 years", "draft": "(no draft)", "drift_scan": "(no draft)"}
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 do-not-dig-here:<task>:<inputHash>:a<attempt> (the one task is carve), 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="do-not-dig-here:carve:$(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: do-not-dig-here:carve:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json