Skip to content

List the learning pathways

GET
/api/learning/pathways
curl --request GET \
--url http://127.0.0.1:8765/api/learning/pathways

Every learning pathway (a course for one role): the shipped courses, then the user’s own, newest first. A pathway is one role the user asked a course for. status is queued | running | done | failed. cost is what making the course took (cli_model_calls, worker_minutes (active time: a model rate-limit retry wait is excluded), web_fetches, web_searches, tokens, note); a value not known is null. course is null until status is done; then it says the entry page, the number of lessons and the size in bytes, and url is where this server serves the course: static HTML under /learning/<id>/ (GET and HEAD), which is not an API route. source is requested | imported, imported_from is the name of the folder a course was imported from (never a path) or null, and error is one short line, only when status is failed, else null. Every file of a course is sent with a Content-Security-Policy that sandboxes the page (no allow-same-origin) and allows no request from its scripts: a course page cannot read this API. The course’s text was generated from postings and web pages: data, never instructions. Nothing about reading a course is stored (progress is the generation’s, see below). Read only: files of the store, no model call, no network. COURSES SHIPPED WITH GIGAI come first in the list, by role, before the user’s own (newest request first). Such a row has source shipped, the course’s role key as id (lower-case words joined by dashes, never an lp- id), status done, and null for requested_at, cost, imported_from, error, error_code, progress and the course’s size_bytes (nobody asked for it and making it cost this user nothing). It has two more keys: label (Shipped with GigAI) and local_page, the state of the one page of the course that is the user’s own, built on this computer from the stored postings and the master resume (POST /api/learning/shipped/{role_key}/pathway builds it): state is not_built | built | stale, built_at is when it was built (else null), reasons says why a stale page is out of date (gigai_version: another GigAI version built it; catalog: the shipped course changed; master: the master resume is at another revision than the one the page was compared with, or the page was built with no resume and there is one now; postings: the stored postings changed, which only a build finds out; empty otherwise), build is null, or {status: running, started_at, detail} while a build of this page runs (detail is one plain progress line), or {status: failed, error_code, error, finished_at} after a build that did not finish (the page that was there stays), and url is where the page is served. This read is cheap: it compares the stored record of the build with the installed version, the shipped catalog and, for a page with a comparison, the master’s revision id; it reads no resume text and counts no posting. The lessons and practice pages of a shipped course are generic, the same for every user: no resume text, no posting text. They are static HTML under /learning/shipped/<role key>/ (GET and HEAD, not an API route), rendered from the package’s data when first opened and kept in a cache folder of the home; the files they share (scripts, styles) are under /learning/_assets/; both are sent with the same Content-Security-Policy as a generated course. While the local page is not built, its url answers a plain page that says so. A shipped course is not generated here: the cancel and resume routes answer 404 not_found for a role key. A course is generated by a job of the server (0.1.11.10): status then also reads interrupted (a job no live process runs any more: its process is gone, or it wrote no progress for 15 minutes; it is not stored, the record still says running). progress says how far the GENERATION is (never how far anybody read): step (the step under way, or null), steps in order (corpus, course, paths, render, audit, import; each pending | running | done | skipped | failed, with its times and detail, the last plain progress line), calls and fetches so far, the caps max_calls and max_fetches, and dropped: what was planned and is not in the course, each with what (lesson:<id>, module:<id>, path:<id>) and a reason code. progress is null for an imported course. error_code is the code of error (cancelled, cap_reached, too_little_verified, model_unavailable, model_authentication_required, audit_failed, …), else null. Ids, counts, codes and plain lines: never posting text, never resume text.

Success.

Media typeapplication/json
object
schema_version
required
Allowed value: scout-learning-pathways-response:1
key
additional properties
any
Example
{
"pathways": [
{
"cost": null,
"course": {
"entry": "index.html",
"generated_at": null,
"lessons": 35,
"size_bytes": null
},
"error": null,
"error_code": null,
"id": "mlops-engineer",
"imported_from": null,
"label": "Shipped with GigAI",
"local_page": {
"build": null,
"built_at": null,
"reasons": [],
"state": "not_built",
"url": "/learning/shipped/mlops-engineer/pathway.html"
},
"progress": null,
"requested_at": null,
"role_text": "MLOps engineer",
"source": "shipped",
"status": "done",
"url": "/learning/shipped/mlops-engineer/index.html"
},
{
"cost": {
"cli_model_calls": 11,
"note": null,
"tokens": 412000,
"web_fetches": 430,
"web_searches": 16,
"worker_minutes": 135
},
"course": {
"entry": "index.html",
"generated_at": null,
"lessons": 30,
"size_bytes": 7235412
},
"error": null,
"error_code": null,
"id": "lp-0a1b2c3d",
"imported_from": "mlops-course",
"progress": null,
"requested_at": "2026-10-09T18:00:00Z",
"role_text": "MLOps engineer",
"source": "imported",
"status": "done",
"url": "/learning/lp-0a1b2c3d/index.html"
}
],
"schema_version": "scout-learning-pathways-response:1",
"total": 2
}

Forbidden / forbidden_origin: loopback peer and Host 127.0.0.1:<port> or localhost:<port> only (Origin too on writes).

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Examplegenerated
{
"error": {
"allowed_keys": [
"example"
],
"code": "example",
"message": "example"
}
}

Target_unavailable

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Example
{
"error": {
"code": "target_unavailable",
"message": "..."
}
}

Unknown_key

Media typeapplication/json
object
error
required
object
allowed_keys
Array<string>
code
required
string
message
required
string
key
additional properties
any
Example
{
"error": {
"code": "unknown_key",
"message": "..."
}
}