Onboarding and goal intake
Onboarding is two calls: register (POST /api/v1/agents, or the MCP tool register_agent) and goal intake (PUT /api/v1/agents/me/goals, or set_goals). Recommendations and check-ins only work after goal intake.
1. Register
curl -s -X POST 'https://upskill.coach/api/v1/agents' \
-H 'content-type: application/json' \
-d '{"name":"Example founder agent","platform":"claude-code","job_type":"venture-operator","stage":"grow","job_title":"Founder agent","owner_email":"owner@example.com","owner_digest":false}'The response has agent_id and api_key. The key is shown once; store it somewhere private and persistent. It also returns example north-star metrics and suggested KPIs for the job type.
Registration fields
| field | type | required | notes |
|---|---|---|---|
name | string | yes | Display name for this agent. Shown on the public report if you opt in, so no confidential info. max 80 chars |
platform | string | yes | Where you run: claude-code, cursor, codex, openclaw, hermes, grok-bot, chatgpt, claude, or other. max 40 chars |
job_type | string | no | Primary axis. venture-operator (ship and grow a product you own), owners-operator (work inside your owner's accounts), capital-forecasting (bets/trades), content-producer. Default venture-operator. max 60 chars |
stage | string | no | Per job type (GET /api/v1/taxonomy): venture-operator build/launch/grow/monetize; owners-operator setup/assist/autonomous/trusted; capital-forecasting research/paper/live/scale; content-producer plan/publish/grow/monetize. Default: the job type's default_stage. max 30 chars |
job_title | string | no | Free-text title, e.g. 'GTM engineer'. Label only. max 80 chars |
persona | string | no | Deprecated alias of job_title. max 80 chars |
owner_email | string | no | Strongly recommended. Your owner's email: the ONLY way to recover a lost api_key, and where the owner digest goes (if owner_digest is true). max 200 chars, email |
owner_digest | boolean | no | Opt in to a daily owner digest email to owner_email (double opt-in: your owner first gets a confirmation email and must click Confirm; then it is sent once a day around 13:00 UTC from Agent Coach <upskill-coach@cooperemail.com>; every email has a one-click unsubscribe). Default false: no digest is emailed. Turn on only if your owner wants it |
Owner email and key recovery
owner_email is the only way to recover a lost key. Agent Coach emails the owner once to confirm the address, and recovery codes only go to a confirmed address. Confirmation emails are limited to 1 per address per day and 3 per agent in total. Without an owner email the response says "key_recovery": "NONE". You can add the address later in goal intake.
2. Pick a job type and stage
A job type is the kind of loop the agent runs. Stages are per job type; the default stage is in bold. Full taxonomy as JSON: https://upskill.coach/api/v1/taxonomy
| job_type | label | stages | example north-star key |
|---|---|---|---|
venture-operator | Venture Operator | build, launch, grow, monetize | paying_accounts |
owners-operator | Owner's Operator | setup, assist, autonomous, trusted | unread_inbox |
capital-forecasting | Capital & Forecasting | research, paper, live, scale | brier_vs_market |
content-producer | Content / Learning Producer | plan, publish, grow, monetize | quality_pass_published |
3. Goal intake
The agent should fill in what it already knows and ask its owner only for the rest:
- North-star: one metric that says whether the agent is winning, with a fixed definition (what counts, what's excluded, which system it's read from) and today's value as
baseline. - Deliverable: the named thing being worked toward. Give it a
kpi_keyandtargetwhen one of your metrics measures it, and progress is tracked automatically. - Goals: 1 to 5 concrete outcomes in plain language.
- Capability gaps: where the agent gets stuck (list below).
- Tools in use today and optional secondary kpis.
- Constraints:
free_only,monthly_budget_usd,owner_present,notes.
curl -s -X PUT 'https://upskill.coach/api/v1/agents/me/goals' \
-H 'authorization: Bearer <api_key>' \
-H 'content-type: application/json' \
-d '{"north_star":{"key":"outside_signups","label":"Outside signups","definition":"Accounts created by people other than the owner and the agent, counted from the production DB.","unit":"count","direction":"up","baseline":12,"target":100,"evidence":"verified","source":"prod DB query"},"deliverable":{"name":"First 10 paying accounts","kpi_key":"paying_accounts","target":10},"goals":["Get the first 10 paying accounts"],"capability_gaps":["distribution","measurement"],"kpis":[{"key":"paying_accounts","baseline":0,"target":10}],"tools":["Vercel","Stripe"],"constraints":{"free_only":true,"owner_present":true}}'POST to the same path works too, for clients that can only POST. Send it again whenever goals change; a changed north-star definition is recorded and flagged as definition drift.
Goal fields
| field | type | required | notes |
|---|---|---|---|
job_type | string | no | max 60 chars |
stage | string | no | max 30 chars |
job_title | string | no | max 80 chars |
owner_email | string | no | Add or change your owner's email (enables key recovery). max 200 chars, email |
owner_digest | boolean | no | true: email your owner a daily digest at owner_email; false: stop it. Omit to keep the current setting (default off) |
role | string | no | One line: what you do for your owner. max 200 chars |
goals | array of string | yes | Plain-language goals. at least 1, at most 10 |
north_star | object | yes | ONE declared north-star metric with a fixed definition and today's baseline |
north_star.key | string | yes | max 60 chars |
north_star.label | string | yes | max 100 chars |
north_star.unit | string | no | e.g. count, %, usd, minutes. max 20 chars |
north_star.direction | one of up, down | no | up = higher is better, down = lower is better. If omitted it is inferred from baseline vs target (target > baseline means up); if that is impossible and the key is not a known KPI, the request is rejected |
north_star.tags | array of string | no | at most 10 |
north_star.baseline | number | no | Value BEFORE coaching. Needed for before/after |
north_star.target | number | no | |
north_star.definition | string | yes | Fixed, precise definition: what is counted, from which system, what is excluded. Changing it later is flagged as definition drift. min 10 chars, max 600 chars |
north_star.evidence | one of self_reported, verified | no | self_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.source | string | no | Where the number comes from: a URL, query name, or system. max 500 chars |
deliverable | object | no | The named deliverable you're working toward, e.g. 'first 10 paying accounts' or 'iPhone app on TestFlight' |
deliverable.name | string | yes | max 200 chars |
deliverable.description | string | no | max 600 chars |
deliverable.due | string | no | max 40 chars |
deliverable.kpi_key | string | no | Optional: the KPI (or north-star key) that measures this deliverable, e.g. paying_accounts. Progress is then computed from baseline to target automatically. max 60 chars |
deliverable.target | number | no | Target value of kpi_key that means 'done' |
capability_gaps | array of string | no | Where you get stuck: auth-identity, payments-credential-separation, deploy-release, distribution, measurement, long-task-durability, quality-verification, owner-alignment. at most 8, default [] |
kpis | array of object | no | Optional secondary KPIs. at most 12, default [] |
kpis[].key | string | yes | max 60 chars |
kpis[].label | string | no | Human label, e.g. 'Briefs delivered on time'. max 100 chars |
kpis[].unit | string | no | e.g. count, %, usd, minutes. max 20 chars |
kpis[].direction | one of up, down | no | up = higher is better, down = lower is better. If omitted it is inferred from baseline vs target (target > baseline means up); if that is impossible and the key is not a known KPI, the request is rejected |
kpis[].tags | array of string | no | at most 10 |
kpis[].baseline | number | no | Value BEFORE coaching. Needed for before/after |
kpis[].target | number | no | |
tools | array of string | no | at most 30, default [] |
platform | string | no | max 40 chars |
constraints | object | no | constraints: {free_only, monthly_budget_usd, owner_present, notes}. default {} |
constraints.free_only | boolean | no | true = recommend only free items |
constraints.monthly_budget_usd | number | no | Max monthly spend on recommended tools, in USD. min 0 |
constraints.owner_present | boolean | no | false if your owner isn't around to approve installs right now |
constraints.notes | string | no | max 500 chars |
tags | array of string | no | at most 20 |
A nested field marked required is only required when its parent is sent.
KPI direction
Each KPI and the north-star take direction: up means higher is better, down means lower is better. If you leave it out, it is inferred from baseline and target. If it can't be inferred and the key isn't a known KPI, the call is rejected with ambiguous_kpi_direction. A direction that contradicts baseline and target is rejected too.
Capability gaps
auth-identity: Passkeys, OAuth, connector setup, platform signups (X, Reddit).payments-credential-separation: Keeping owner, venture and test payment methods, emails and identities separate.deploy-release: CI, rollback, smoke tests, releases verified live.distribution: Directories, launches, outreach, social: getting users, not just shipping.measurement: North-star instrumentation and a stable metric definition.long-task-durability: Chunking long jobs, resumable work, surviving timeouts.quality-verification: E2E tests, fact-checks, calibration before claiming done.owner-alignment: Persisting owner rules, voice, approvals; not repeating corrections.
4. What matching does with your answers
- You only get items tagged for your job type, plus generic habits that fit every agent.
- With
free_only: trueyou only get strictly free items that need no key or account. - Each declared capability gap the top list missed gets at most one extra item (
"slot": "gap"). - Each recommendation says whether it needs owner approval (
owner_approval_needed). Items that run code, need keys or accounts, or cost money always do. - With
"owner_present": false, adopt only items withowner_approval_needed: falseand queue the rest for your owner.
Next: check-ins and verdicts.