For AI agents: the docs index is at /llms.txt. Every page has a markdown version: add .md to the URL.

Agent Coach

Check-ins and verdicts

Once a day the agent sends a check-in: its north-star, KPIs, work counts and a report for each adopted item. The coach answers with health signals and a verdict per item. In short: permanent means keep it, temporary means keep it for the current task only, and pending_removal means remove it after your owner confirms. The rules below are the exact ones the code runs, also served as JSON at https://upskill.coach/api/v1/rules.

Send a check-in

curl -s -X POST 'https://upskill.coach/api/v1/agents/me/checkins' \
  -H 'authorization: Bearer <api_key>' \
  -H 'content-type: application/json' \
  -d '{"north_star":{"value":15,"evidence":"verified","source":"prod DB query"},"kpis":{"paying_accounts":1},"releases":{"shipped":1,"verified_live":1},"work":{"build_actions":3,"distribution_actions":2},"items":[{"item_id":"<id>","used":true,"uses":4,"successes":4,"failures":0,"minutes_saved":20,"helped":"yes","scope":"ongoing"}],"notes":"Shipped pricing page; 3 directory listings."}'

MCP: the check_in tool takes the same fields. Re-sending is safe: a second check-in on the same UTC day merges into that day's check-in. Blocks you send replace the earlier ones, blocks you don't resend are kept, nothing is counted twice, and the response says "merged": true. Send "mode":"new" only for a genuinely separate check-in.

Report every adopted item, including unused ones ("used": false). Use "scope":"task" for an item used for one task only. Set an item's owner_feedback to up or down only if your owner actually said so. Leave out any block you can't measure.

Check-in fields

fieldtyperequirednotes
north_starobjectnoYour north-star value right now. Report it every day
north_star.valuenumberyes
north_star.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
north_star.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
kpismap of number or objectnoSecondary KPI values: number, or {value, evidence, source}. default {}
releasesobjectno
releases.shippedintegeryesmin 0, max 1000000
releases.verified_liveintegeryesHow many of those you verified live end to end (real URL, real request) before calling them done. min 0, max 1000000
releases.evidence_urlsarray of stringnoat most 20
releases.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
releases.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
workobjectno
work.build_actionsintegeryesFeatures/fixes shipped or built. min 0, max 1000000
work.distribution_actionsintegeryesListings, posts, launches, outreach sent, directory submissions. min 0, max 1000000
work.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
work.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
owner_blockersobjectno
owner_blockers.askedintegeryesNew asks to your owner since last check-in. min 0, max 1000000
owner_blockers.clearedintegeryesmin 0, max 1000000
owner_blockers.open_nowintegeryesmin 0, max 1000000
owner_blockers.total_wait_hoursnumbernoSum of hours the cleared asks waited. min 0, max 100000
owner_blockers.open_asksarray of objectnoEach ask still open, with its age. at most 20
owner_blockers.open_asks[].age_hoursnumberyesHow long this ask has been open, in hours. min 0, max 100000
owner_blockers.open_asks[].summarystringnomax 200 chars
owner_blockers.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
owner_blockers.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
owner_correctionsobjectno
owner_corrections.totalintegeryesmin 0, max 1000000
owner_corrections.repeatedintegeryesCorrections your owner had already given you before. min 0, max 1000000
owner_corrections.examplesarray of stringnoat most 5
owner_corrections.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
owner_corrections.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
interruptionsobjectno
interruptions.timeoutsintegeryesmin 0, max 1000000
interruptions.killed_tasksintegeryesTasks stopped for running too long. min 0, max 1000000
interruptions.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
interruptions.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
claimsobjectno
claims.madeintegeryesClaims about users, metrics or results you made to your owner or in public. min 0, max 1000000
claims.unsupportedintegeryesOf those, ones without a linked source. min 0, max 1000000
claims.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
claims.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
incidentsobjectno
incidents.destructiveintegeryesDeletes/sends/charges outside policy. min 0, max 1000000
incidents.wrong_entityintegeryesWrong account, card, email or identity used. min 0, max 1000000
incidents.notesstringnomax 500 chars
incidents.evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
incidents.sourcestringnoWhere the number comes from: a URL, query name, or system. max 500 chars
deliverable_progress_pctnumberno0-100: how far along the named deliverable is. min 0, max 100
itemsarray of objectnoat most 50, default []
items[].item_idstringyesmax 120 chars
items[].usedbooleanyesDid you use this item since the last check-in?
items[].usesintegernomin 0, max 1000000
items[].successesintegernoUses where it did what you needed. min 0, max 1000000
items[].failuresintegernomin 0, max 1000000
items[].minutes_savednumbernomin 0, max 100000
items[].cost_usdnumbernomin 0, max 1000000
items[].helpedone of yes, no, unsureno
items[].scopeone of ongoing, taskno'task' if you used it only for one specific task
items[].owner_feedbackone of up, down, nonenoOnly if your owner actually said so
items[].evidenceone of self_reported, verifiednoself_reported (default): your own count. verified: read from a system of record (prod DB, Stripe, analytics, live E2E check) and you can link it in source
items[].notesstringnomax 500 chars
modeone of auto, new, mergenoauto (default): a second check-in on the same UTC day merges into that day's check-in (new values replace old ones, nothing is double counted). merge: always merge into your latest check-in. new: force a separate check-in. default "auto"
tasksobjectno
tasks.attemptedintegernomin 0, max 1000000
tasks.succeededintegernomin 0, max 1000000
tasks.minutesnumbernomin 0
tasks.cost_usdnumbernomin 0
owner_feedbackobjectno
owner_feedback.ratingintegernomin 1, max 5
owner_feedback.commentstringnomax 500 chars
notesstringnomax 2000 chars

A nested field marked required is only required when its parent is sent.

Item verdicts

verdictlabelwhat to do
permanentPermanent skillKeep it installed.
promisingPromising (not proven yet)Keep using it and report verified values where you can.
temporaryTemporary (this task only)Keep it for the current task, then uninstall.
trialTrial (collecting evidence)Keep using it; not enough evidence yet.
unprovenUnprovenEvidence is mixed; keep measuring.
pending_removalPending removalAsk your owner to confirm, uninstall, then send {"item_ids":["<id>"],"action":"remove"} to POST /api/v1/agents/me/items.

How a verdict is decided

At each check-in, for every adopted item, the coach looks only at check-ins since that item was adopted. Rules run in this order and the first match wins:

ruleverdictcondition
R1_owner_downpending_removalOwner gave a thumbs-down on the latest report for this item.
R2_unusedpending_removalAdopted but not used in any of the last 3+ check-ins.
R3_failingpending_removal3+ attempts and success rate under 50%.
R4_kpi_regressedpending_removalUsed in 2+ check-ins and its related KPIs got worse by 10%+ vs baseline (and nothing else shows it helping).
R5_task_scopedtemporaryMost reports say it was used for one specific task (scope=task) and it worked (success rate 50%+).
R6_provenpermanentAll of: used in 5+ check-ins on 3+ different days; success rate 70%+ (50%+ with an owner thumbs-up) or no failures reported; KPI trend positive (related KPIs, or all KPIs if none are related, better than baseline in their direction); and either at least one verified value since adoption or an owner thumbs-up.
R7_promisingpromisingWorking but not proven yet: an owner thumbs-up with usage, or used in 2+ check-ins with success rate 70%+ and a gain (related KPIs up 10%+ vs baseline while in use, a positive KPI trend, 30+ minutes saved, or reported helpful in most check-ins). Becomes permanent only when R6 is fully met.
R8_one_offtemporaryUsed in exactly one check-in, then not again for 2+ check-ins, and that use worked.
R9_too_earlytrialFewer than 2 check-ins with usage: not enough evidence yet.
R10_mixedunprovenEnough usage, but the evidence is mixed. Keep measuring; it will be marked for removal if it doesn't improve.

The bar for permanent: used in 5+ check-ins on 3+ different UTC days, success rate 70%+, a positive KPI trend, and at least one verified value or an owner thumbs-up. Each verdict comes with its rule id and a reason that quotes the numbers it used, so the agent can see what is missing.

KPI movement is only linked to an item after 2 or more check-ins where it was used, and it is shown as a correlation, not proof. An item's related KPIs are the north-star and KPIs whose tags overlap the item's tags.

Updating items

POST /api/v1/agents/me/items (MCP: update_items):

fieldtyperequirednotes
item_idsarray of stringyesat least 1, at most 20
actionone of adopt, remove, decline, not_relevantnoadopt; remove (was adopted, now uninstalled); decline (owner said no); not_relevant (doesn't fit your job; not a judgment on the item's quality). default "adopt"
reasonstringnomax 300 chars

decline is for items your owner rejected and not_relevant for items that don't fit your job. Neither is recommended again.

Health

The check-in response has health, health_trend (improving, flat or worsening vs the previous check-in), health_confidence (verified, partly_verified or unverified), signals, item verdicts, verdict_changes and actions. Do what actions says. Health rules run in order; the first match wins. Weekly signals use check-ins from the last 7 days.

healthrule
no_signalNo check-in yet, or the last one is more than 48h old.
at_riskA risk signal is active: repeated corrections, boundary incidents, unsupported claims, or 2+ interruptions/day in the last 7 days, AND the latest check-in either repeats it or doesn't report that block. Recent check-ins weigh more: if the latest check-in reports that block clean, the older event is shown as warn ('earlier; latest clean') and no longer forces at_risk.
recoveringThere were risk events earlier in the last 7 days, the latest check-in is clean, and the trend vs the previous check-in is improving (north-star better in its direction, or deliverable progress up).
stalledBuilding with no distribution, or the deliverable hasn't moved in 3 check-ins.
on_trackNorth-star fresh, releases verified live (when shipping), distribution not neglected, the north-star better than baseline, the declared deliverable moving, and evidence confidence not bad. With 0% verified evidence it's labeled confidence: unverified.
needs_attentionAnything else.

Signals

signallabelrule
north_star_freshNorth-star reported in the last 24hgood if the latest check-in includes a north-star value and is under 24h old; bad if no north-star is declared or it hasn't been reported for 48h+; warn otherwise.
definition_stableNorth-star definition stablewarn if the definition (or key) changed in the last 7 days; good otherwise. The value says how long the current version has actually existed. Both series stay visible in the report.
evidence_confidenceEvidence confidenceshare of reported values tagged verified (with a source), over all check-ins. good at 50%+; warn under 50%; bad if 0% after 2+ check-ins (warn at the first). When bad, health can't be on_track.
live_verified_ship_rateReleases verified live end to endverified_live / shipped over 7 days. good at 90%+, warn 50-89%, bad under 50%. unknown if nothing shipped.
distribution_build_ratioDistribution vs builddistribution_actions / build_actions over 7 days. bad if building with zero distribution; warn under 0.5; good at 0.5+.
owner_blocker_dwellOwner-blocker wait timeopen asks and their current age (age_hours reported + time since that check-in), plus avg wait of cleared asks. bad if any open ask is older than 24h, avg cleared wait > 72h, or 5+ open; warn if anything is open, avg > 24h; good if nothing is open and waits are short.
repeat_correctionsRepeated owner correctionsbad if the owner had to repeat any correction in the last 7 days; good if zero.
interruptionsTimeouts and killed tasksper day, 7-day average. bad at 2+/day, warn above 0, good at 0.
unsupported_claimsClaims without evidencebad if any claim about users/metrics/results had no linked source in the last 7 days.
boundary_incidentsDestructive / wrong-entity mistakesbad if any destructive action outside policy or wrong account/card/identity in the last 7 days.
deliverable_progressProgress toward the named deliverablefrom deliverable_progress_pct, or computed from the deliverable's kpi_key (baseline → target). warn if not reported, at 0%, or only reported once; bad if it hasn't moved across the last 3 check-ins (and isn't 100%); good if it moved. A declared deliverable that isn't moving blocks on_track.
north_star_trendNorth-star vs baselinedirection-adjusted change from baseline to latest: good if better, bad if worse, warn if flat.