Sign In Join
Docs · v1.0.0

The h3 command line

Your Human 3.0 progress, Maturity Model position, badges and library from a terminal, and a stable JSON API any agent can drive.

Install

curl -fsSL https://human3.ai/cli/install.sh | sh

The installer downloads https://human3.ai/cli/h3.js, checks its SHA-256 against the digest built into the installer, and refuses to install on a mismatch. It needs Node.js 20 or newer, or Bun. It puts h3 in ~/.local/bin (set H3_INSTALL_DIR to change that). The digest is also published at https://human3.ai/cli/h3.js.sha256.

Or run it without installing: curl -fsSLO https://human3.ai/cli/h3.js && node h3.js help.

Log in

$ h3 login

  Your one-time code: BCDF-GHJK
  Open https://human3.ai/cli/authorize while signed in, enter the code, and approve.

  Waiting for approval (the code expires in 10 minutes)…
✓ Logged in as you@example.com (key sk_h3_AbCd1234…, read + write, expires 2026-12-25).

Open the page while signed in to Human 3.0, type the code, check where the request came from, the access and the expiry, and approve. Codes expire after 10 minutes and work once. The CLI then stores a new API key in ~/.config/h3/credentials.json, readable only by you (mode 0600). h3 logout revokes that key on the server and deletes the file.

A key from h3 login expires after 90 days; pass --expires 30 for a shorter one or --expires never for one that lasts until you revoke it. The device name is whatever the terminal sent, so the approval page also shows the country the request came from, and warns you when that country or network differs from yours. Never approve a code someone else gave you.

For CI or an agent, create a key on your account page and set H3_API_KEY; it takes precedence over the stored login. Test identities cannot hold keys.

Using it from an agent

Every command prints only JSON on stdout when stdout is not a terminal, or with --json. Errors go to stderr, as JSON under --json: {"error": {"code": "…", "message": "…", "exit_code": 2}}. h3 help --json prints the whole catalog: commands, arguments, flags, exit codes, environment and endpoints. During h3 login --json the approval code is written to stderr as one JSON line so an agent can show it to you.

Global flags

--json
Print only JSON on stdout (the default whenever stdout is not a terminal).
--help
Show help for the command.
--no-color
Disable colour (the NO_COLOR environment variable does the same).

Exit codes

CodeNameMeaning
0okThe command did what it said.
1usageBad arguments, an unknown command, or an id that does not exist.
2authNot logged in, the key is invalid, revoked or expired, lacks the scope, or API access is suspended.
3subscriptionThe command needs an active Human 3.0 membership.
4rate_limitedA rate limit was hit; stderr says how many seconds until it resets.
5serverNetwork failure, timeout, or a server error.

Commands

CommandWhat it does
h3 loginLog in from this machine with a device code.
h3 logoutRevoke this machine's key and delete the stored credentials.
h3 whoamiShow who the key belongs to and what it can do.
h3 progressYour curriculum progress, overall and per track.
h3 scoreYour H3 Maturity Model position and scores.
h3 badgesBadges you have earned and the ones still open.
h3 libraryList the library, optionally one track or type.
h3 itemOne library item in full.
h3 nextThe item to do next.
h3 completeMark an item complete.
h3 coursesThe individual courses for sale.
h3 usageHow much of your rate limits you have used.
h3 completionPrint a shell completion script.
h3 versionPrint the CLI version.
h3 helpShow help for all commands or one.

h3 login

Log in from this machine with a device code.

POST /api/v1/device/code

Starts a device login. The CLI prints a short code and https://human3.ai/cli/authorize; open that page signed in to Human 3.0, enter the code, check where the request came from, the scopes and the expiry, and approve. The CLI then stores a new API key in ~/.config/h3/credentials.json (mode 0600). The key expires after 90 days unless you pass --expires. Under --json the code is printed to stderr as one JSON line so an agent can pass it to you.

h3 login [--name NAME] [--read-only] [--expires never|DAYS] [--no-browser]
--name NAME
Name for the key on your account page (default: this machine's hostname).
--read-only
Ask for a read-only key; `h3 complete` will then be refused.
--expires never|DAYS
Key lifetime: 1–365 days, or never. Default: 90 days.
--no-browser
Do not try to open the approval page in a browser.

Log in with a read and write key named after this machine.

$ h3 login

A 30-day read-only key for an agent.

$ h3 login --read-only --name claude-agent --expires 30

Output with --json:

{
  "logged_in": true,
  "email": "you@example.com",
  "key": { "id": "…", "name": "laptop", "prefix": "sk_h3_AbCd1234", "scopes": ["read", "write"], "expires_at": "2026-12-25T10:00:00.000Z" },
  "credentials_path": "/home/you/.config/h3/credentials.json"
}

h3 logout

Revoke this machine's key and delete the stored credentials.

needs a keyDELETE /api/v1/keys/current

Revokes the stored key on the server, then deletes ~/.config/h3/credentials.json. A key supplied through H3_API_KEY is not touched; revoke it on your account page.

h3 logout

Revoke and forget this machine's key.

$ h3 logout

Output with --json:

{ "logged_out": true, "revoked": true, "credentials_removed": true }

h3 whoami

Show who the key belongs to and what it can do.

needs a keyGET /api/v1/me

Your account, membership status, and the key in use (name, prefix, scopes, expiry).

h3 whoami

Check which account this machine is logged in as.

$ h3 whoami

Just the email.

$ h3 whoami --json | jq -r .user.email

Output with --json:

{
  "user": { "id": "…", "email": "you@example.com", "name": "You", "member_since": "2026-03-01T00:00:00.000Z" },
  "subscription": { "status": "active", "plan": "core", "active": true },
  "auth": { "type": "api_key", "key": { "id": "…", "name": "laptop", "prefix": "sk_h3_AbCd1234", "scopes": ["read", "write"], "expires_at": null } }
}

h3 progress

Your curriculum progress, overall and per track.

needs a keymembers onlyGET /api/v1/progress

How many library items you have completed, overall and per track, plus the ids you have completed and viewed.

h3 progress

A per-track table.

$ h3 progress

Overall completion percentage.

$ h3 progress --json | jq .percent

Output with --json:

{
  "completed": 12,
  "total": 64,
  "percent": 19,
  "viewed": 20,
  "tracks": [{ "track": "SO1", "name": "Purpose & Meaning", "completed": 3, "total": 5 }],
  "completed_ids": ["SO1-V1"],
  "viewed_ids": ["SO1-V1", "SO1-E1"]
}

h3 score

Your H3 Maturity Model position and scores.

needs a keymembers onlyGET /api/v1/h3mm

Where you are on the Human 3.0 Maturity Model: the current stage, how many stages are complete, the markers you have answered, and an overall position from 0 to 1. Also returns your saved H3MM self-scores when you have them.

h3 score

Current stage and per-stage markers.

$ h3 score

Just the stage name.

$ h3 score --json | jq .position.stage.name

Output with --json:

{
  "position": {
    "stage": { "order": 2, "name": "Activated" },
    "stages_complete": 1,
    "stages_total": 5,
    "markers_answered": 7,
    "markers_total": 20,
    "position": 0.28
  },
  "stages": [{ "order": 1, "name": "Aware", "answered": 4, "total": 4, "complete": true }],
  "scores": { "SO1": 3 }
}

h3 badges

Badges you have earned and the ones still open.

needs a keymembers onlyGET /api/v1/badges

Every badge with your level in it: 0 unearned, 1 Practicing, 2 Embodying.

h3 badges [--earned]
--earned
Only badges at level 1 or above.

What you have earned so far.

$ h3 badges --earned

Names of badges at Embodying.

$ h3 badges --json | jq '.badges[] | select(.level == 2) | .name'

Output with --json:

{
  "earned": 5,
  "total": 39,
  "badges": [{ "id": "navigator", "name": "Navigator", "description": "You know where you're going", "domain": "SO", "level": 1, "level_name": "Practicing", "earned_at": "2026-09-01 10:00:00" }]
}

h3 library

List the library, optionally one track or type.

needs a keymembers onlyGET /api/v1/library

Every active item in the library in curriculum order, with whether you have viewed or completed it. Video items link to their page on human3.ai; the API never hands out a playable video URL.

h3 library [--track TRACK] [--type TYPE] [--todo]
--track TRACK
A track (SO1…CA4) or a whole domain (SO, SH, CO, CA).
--type TYPE
Only items of this type (video, exercise, book, essay…).
--todo
Only items you have not completed.

The Purpose & Meaning track.

$ h3 library --track SO1

Everything left in the Capabilities domain, as JSON.

$ h3 library --track CA --todo --json

Output with --json:

{
  "count": 1,
  "items": [
    {
      "id": "SO1-V1",
      "track": "SO1",
      "track_name": "Purpose & Meaning",
      "type": "video",
      "title": "Finding Your TELOS",
      "description": "…",
      "duration_seconds": 1260,
      "completed": false,
      "viewed": true,
      "url": "https://human3.ai/content/SO1-V1",
      "video_page": "https://human3.ai/v/<stream-uid>/iframe"
    }
  ]
}

h3 item

One library item in full.

needs a keymembers onlyGET /api/v1/library/:id

Everything about one item: description, why it matters, its steps, and links.

h3 item <id>
<id>
The item id, as shown by `h3 library`.

Read the steps for an exercise.

$ h3 item SO1-E1

Output with --json:

{
  "item": {
    "id": "SO1-E1",
    "track": "SO1",
    "track_name": "Purpose & Meaning",
    "type": "exercise",
    "title": "Write your draft mission statement",
    "description": "…",
    "importance": "…",
    "steps": ["…"],
    "duration_seconds": null,
    "completed": false,
    "viewed": false,
    "has_file": false,
    "essay_url": null,
    "url": "https://human3.ai/content/SO1-E1",
    "video_page": null
  }
}

h3 next

The item to do next.

needs a keymembers onlyGET /api/v1/next

The item you started but have not finished, if there is one; otherwise the first item you have not completed, in curriculum order.

h3 next

What to work on now.

$ h3 next

Mark the next item done (needs a write key).

$ h3 complete "$(h3 next --json | jq -r .item.id)"

Output with --json:

{
  "reason": "in_progress",
  "item": {
  "id": "SO1-V1",
  "track": "SO1",
  "track_name": "Purpose & Meaning",
  "type": "video",
  "title": "Finding Your TELOS",
  "description": "…",
  "duration_seconds": 1260,
  "completed": false,
  "viewed": true,
  "url": "https://human3.ai/content/SO1-V1",
  "video_page": "https://human3.ai/v/<stream-uid>/iframe"
}
}

h3 complete

Mark an item complete.

needs write scopemembers onlyPOST /api/v1/progress/:id/complete

Marks the item complete, re-evaluates your badges exactly as the web does, and reports any badge that changed. Needs a key with the write scope.

h3 complete <id>
<id>
The item id.

Mark the mission-statement exercise done.

$ h3 complete SO1-E1

Output with --json:

{
  "item_id": "SO1-E1",
  "completed": true,
  "already_completed": false,
  "badges_changed": [{ "id": "navigator", "name": "Navigator", "level": 1, "level_name": "Practicing" }],
  "progress": { "completed": 13, "total": 64, "percent": 20 }
}

h3 courses

The individual courses for sale.

needs a keyGET /api/v1/courses

The à-la-carte course catalog, newest first. Every one is already included in the membership.

h3 courses

List the courses and prices.

$ h3 courses

Output with --json:

{
  "courses": [{ "id": "…", "title": "…", "kind": "video", "tier": "video-tier-1", "description": "…", "price_cents": 4995, "price": "$49.95", "duration_minutes": 83, "published_at": "2026-07-21", "url": "https://human3.ai/courses/…" }]
}

h3 usage

How much of your rate limits you have used.

needs a keyGET /api/v1/usage

Your key's per-minute budget, your per-minute budget across all your keys, and your per-day quota: limit, used, remaining, and seconds until each resets.

h3 usage

Check headroom before a batch job.

$ h3 usage

Output with --json:

{
  "key_minute": { "limit": 120, "used": 3, "remaining": 117, "reset_seconds": 41, "window_seconds": 60 },
  "member_minute": { "limit": 240, "used": 3, "remaining": 237, "reset_seconds": 41, "window_seconds": 60 },
  "member_day": { "limit": 10000, "used": 210, "remaining": 9790, "reset_seconds": 51000, "window_seconds": 86400 }
}

h3 completion

Print a shell completion script.

local

Prints a completion script for bash, zsh or fish. Add it to your shell's startup file.

h3 completion <bash|zsh|fish>
<shell>
bash, zsh or fish.

Install zsh completion (with ~/.zfunc on your fpath).

$ h3 completion zsh > ~/.zfunc/_h3

Install bash completion.

$ echo 'eval "$(h3 completion bash)"' >> ~/.bashrc

Output with --json:

{ "shell": "zsh", "script": "#compdef h3 …" }

h3 version

Print the CLI version.

local

The CLI version and the runtime it is running under.

h3 version

Which version is installed.

$ h3 version

Output with --json:

{ "version": "1.0.0", "runtime": "node", "runtime_version": "22.9.0" }

h3 help

Show help for all commands or one.

local

Lists every command. With --json, prints this whole catalog (commands, flags, exit codes, environment, endpoints) for an agent to read.

h3 help [command]
<command>
Show help for this command only. Optional.

Help for one command.

$ h3 help library

The machine-readable catalog.

$ h3 help --json

Output with --json:

{ "name": "h3", "version": "1.0.0", "commands": [ … ], "global_flags": [ … ], "exit_codes": [ … ], "env": [ … ], "endpoints": [ … ] }

Environment

VariableEffect
H3_API_KEYUse this key instead of the stored credentials. Takes precedence over h3 login.
H3_BASE_URLAPI origin (default https://human3.ai). Must be https, except for localhost.
NO_COLORAny value turns colour off.
XDG_CONFIG_HOMEWhere h3/credentials.json lives (default ~/.config).

API

The CLI is a thin client over https://human3.ai/api/v1. Send Authorization: Bearer sk_h3_…. Keys are 256-bit random strings; we store only their SHA-256 hash, show a short prefix so you can tell them apart, and let you revoke them any time. A key is read or read + write, may expire after 1 to 365 days, and a member can hold at most 20 active keys. Member-only endpoints use the same membership check as the website.

curl -s https://human3.ai/api/v1/progress -H "Authorization: Bearer $H3_API_KEY"
MethodPathAuthReturns
GET/api/v1/mekeyYour account, membership and the key in use.
GET/api/v1/subscriptionkeyMembership status, plan and period end.
GET/api/v1/usagekeyRate-limit usage for the key and the member.
GET/api/v1/courseskeyThe individual course catalog.
GET/api/v1/progresskey, memberCurriculum progress overall and per track.
GET/api/v1/h3mmkey, memberMaturity Model position, stages and self-scores.
GET/api/v1/badgeskey, memberEvery badge with your level.
GET/api/v1/librarykey, memberActive library items; ?track= (track or domain), ?type=.
GET/api/v1/library/:idkey, memberOne active item in full.
GET/api/v1/nextkey, memberThe recommended next item.
POST/api/v1/progress/:id/completekey (write), memberMark an item complete and re-evaluate badges.
DELETE/api/v1/keys/currentkeyRevoke the key making the request (logout).
POST/api/v1/device/codenoneStart a device login: returns a device code, a user code and the approval URL.
POST/api/v1/device/tokennonePoll a device login; returns the new key once, after approval.

Video items link to their page on human3.ai, which checks your membership before it plays anything; the API never returns a playable or signed video URL, a storage URL, or an unpublished item.

Errors

Every error is JSON: {"error": "<code>", "message": "…"}. A bad, revoked or expired key always gets the same 401 body.

StatusErrorMeaning
400invalid_requestA parameter or body field is missing or malformed.
400authorization_pendingDevice login: not approved yet; poll again after interval seconds.
400slow_downDevice login: polling too fast; the response carries the new interval.
400expired_tokenDevice login: the code expired (codes live 10 minutes).
400access_deniedDevice login: the member denied the request.
400invalid_grantDevice login: unknown or already-used device code.
401unauthorizedNo valid credentials. The body is identical for every cause.
403insufficient_scopeThe key lacks the scope this call needs (write).
403subscription_requiredThis call needs an active membership.
403api_access_suspendedAPI access for this account is suspended.
403forbidden_originA cross-site browser request was refused.
403key_refusedDevice login: this account cannot hold another key (test identity, suspended, or 20 active keys).
404not_foundNo such endpoint, or no active item with that id.
429rate_limitedA rate limit was hit; see Retry-After.
500internal_errorSomething failed on our side.

Rate limits

Every /api/v1 response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds), describing whichever budget you are closest to running out of, plus RateLimit-Policy listing all of them. A 429 also carries Retry-After, the seconds until that window ends. Windows are fixed and aligned to the clock.

PolicyLimitWindowCounted perNotes
key-minute120per minutekeyRequests per API key (or per signed-in browser session) per minute.
member-minute240per minutememberRequests per member per minute, across all of that member's keys and sessions, so more keys never mean more burst.
member-day10,000per UTC daymemberRequests per member per UTC day, across all of that member's keys and sessions.
auth-fail-ip30per 10 minutesipWrong or unknown API keys per IP address per 10 minutes. Past it, wrong keys from that IP get 429 until the window ends; valid keys and requests with no key are not affected.
device-start-ip10per 10 minutesiph3 login starts per IP address per 10 minutes.
device-poll-ip300per 10 minutesipDevice-token polls per IP address per 10 minutes.
key-create-member30per hourmemberAPI keys created per member per hour, on the account page or by h3 login together.
device-approve-member20per 10 minutesmemberCode look-ups and approvals on /cli/authorize per member per 10 minutes.

Device login polls faster than every 5 seconds answer slow_down, and each one adds 5 seconds to the interval.

Manage keys on your account page. Questions: support@unsupervised-learning.com.