npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

coursera-cli

v0.3.2

Published

Your Coursera courses from the terminal: CLI + MCP server that pulls transcripts and readings from the courses you are enrolled in

Readme

coursera-cli

 ██████  █████  ██   ██ ██████  ███████ ███████ ██████   █████
██      ██   ██ ██   ██ ██   ██ ██      ██      ██   ██ ██   ██
██      ██   ██ ██   ██ ██████  ███████ █████   ██████  ███████
██      ██   ██ ██   ██ ██   ██      ██ ██      ██   ██ ██   ██
 ██████  █████   █████  ██   ██ ███████ ███████ ██   ██ ██   ██

npm License: MIT Bun TypeScript Tests MCP

Your own Coursera courses, from the terminal — and from Claude Code, over MCP.

Downloads the transcripts and readings of courses you are enrolled in, through Coursera's internal API. No HTML scraping, no gigabytes of video.

coursera courses --search pricing     find the course
coursera map                          see what you actually studied
coursera transcript <slug>            pull the content as text

Install

Requires Bun — the CLI is TypeScript and Bun runs it directly, with no build step.

bun add -g coursera-cli     # or: npm install -g coursera-cli

That puts a coursera command on your PATH. It works even when Bun itself is not on PATH: the installed command is a small Node launcher that goes looking for Bun, and says so plainly if it cannot find it.

From source

git clone https://github.com/StephCastrof001/coursera-cli.git
cd coursera-cli
bun install
bun link                    # optional: same global `coursera` command

Without bun link, run it as bun run index.ts <command> from the repo root.

Session

The CLI needs your account's CAUTH cookie. It looks in three places, in order:

  1. The COURSERA_CAUTH environment variable
  2. Its own store, under the platform config directory
  3. A store left by an earlier capture (~/.config/coursera_recon/session.json)

Getting the cookie

Logging in is not automated. Typing credentials from a script is what triggers the CAPTCHA, so the cookie is copied by hand — once. It lasts days, not hours: the longest measured lifetime so far is 126 hours.

  1. Log in to coursera.org in your browser
  2. Open DevTools (F12) → Application tab on Chrome, Storage on Firefox
  3. Cookieshttps://www.coursera.org → find the row named CAUTH
  4. Copy its Value — a long opaque string

Then hand it to the CLI:

# macOS, Linux, Git Bash
export COURSERA_CAUTH="paste-the-value-here"

# PowerShell
$env:COURSERA_CAUTH = "paste-the-value-here"

Make it permanent by adding that line to your shell profile, or keep it in the session store. Either way, coursera session tells you whether it worked:

coursera session   # is it alive, where did it come from, how old is it
coursera doctor    # session + routes + paths, all at once
[OK]   version: coursera-cli 0.3.1 on win32, bun 1.3.11
[OK]   session-present: found via legacy, 108.2 h old
[OK]   session-alive: 215 courses visible
[OK]   endpoints: 10 routes declared, domains.v1 alive
[OK]   paths: state C:\Users\you\AppData\Local\coursera-cli

5/5 checks passed

Commands

| Command | What it does | |---|---| | coursera session | Session state: source, age, alive or dead | | coursera doctor | Diagnoses session, live routes and writable paths | | coursera courses [filters] | Your courses | | coursera map [--detail] | Branches, levels, institutions, unfinished specializations | | coursera course <slug> | Syllabus, institution, instructors, declared level | | coursera transcript <slug> | Downloads transcripts and readings |

Filters

Filters compose with AND, and multi-word values need no quotes:

coursera courses --search machine learning
coursera courses --level intermediate --domain data-science
coursera courses --lang es --hours 5          # short courses in Spanish
coursera courses --university duke

| Flag | Example | |---|---| | --search <text> | name or slug | | --level | beginner, intermediate, advanced | | --domain <id> | branch or sub-branch, e.g. data-science, machine-learning | | --lang <code> | primary language, e.g. es | | --hours <n> | at most n estimated hours | | --university <name> | e.g. duke |

Global flags

| Flag | Default | Purpose | |---|---|---| | --json | off | Structured output. Implied when stdout is piped | | --out <dir> | platform data dir | Where to write | | --limit <n> | all | Stop after n items | | --lang es,en | es,es-LA,en | Subtitle preference order | | --quiet | off | No progress output | | --color / --no-color | auto | Force colour on or off. Auto-detects TTY, and honours NO_COLOR and FORCE_COLOR |

Library map

coursera map cross-references your library against Coursera's own taxonomy:

215 courses in your library
levels: beginner 99   intermediate 66   advanced 7   undeclared 43
business                         158  ████████████████████████ 1366 h
data-science                      90  ██████████████            735 h
computer-science                  35  █████                     255 h

SPECIALIZATIONS (15)
  ✓ AI Product Management                            3/3  complete
  ○ Digital Product Management                       3/5  2 missing

Two caveats it prints itself, because both are real: a course filed under two branches counts in both, and hours come from Coursera's free-text workload field, which 78 of 215 courses do not state readably.

MCP for Claude

Register the server with the absolute path to the Bun binary — the process that launches MCP servers does not inherit your PATH, so "command": "bun" fails with "Failed to connect". Find yours with which bun (where.exe bun on Windows).

Claude Code

In .mcp.json at your project root, or in ~/.claude.json to have it everywhere:

{
  "mcpServers": {
    "coursera": {
      "command": "C:/Users/you/.bun/bin/bun.exe",
      "args": ["C:/Users/you/coursera-cli/src/mcp/index.ts"]
    }
  }
}

Claude Desktop

Same shape, in the app's own config file — %APPDATA%\Claude\claude_desktop_config.json on Windows, ~/Library/Application Support/Claude/claude_desktop_config.json on macOS:

{
  "mcpServers": {
    "coursera": {
      "command": "/Users/you/.bun/bin/bun",
      "args": ["/Users/you/coursera-cli/src/mcp/index.ts"]
    }
  }
}

Tools

| Tool | Returns | |---|---| | session_status | Whether the session is alive, where it came from, how many courses it sees | | list_courses | Your courses, with the same filters as the CLI | | get_library_map | Branches, levels, institutions, specialization progress | | get_course_outline | The course tree plus institution and instructors | | fetch_transcripts | Downloads a course, returns the index of what landed | | read_transcript | The text of one item |

fetch_transcripts returns paths, not text: a course is ~130 KB (≈35k tokens) and sending it whole would blow up the conversation. To read, use read_transcript.

What it downloads

Text, by default: a .txt transcript per video and a .reading.md per reading. No video — a course is gigabytes as MP4 against ~130 KB as text, and for studying or summarizing the text carries the same signal.

Files are organized per module, numbered in order, with a manifest.json index.

Locked modules

When a course is in preview or has locked weeks, the aggregating API censors the item type: it returns them empty, and extractors that filter by type skip 75% of the syllabus believing it is empty.

This CLI does not filter. It asks the video and reading microservices about every item directly and keeps whatever answers.

Architecture

Four layers, one direction of dependency: commands and MCP call services, services call http.ts, http.ts calls the network. Commands never build URLs and services never print — that is what lets the CLI and the MCP server share every line of business logic.

index.ts             → CLI dispatcher (one file per command, lazily imported)
src/
  constants.ts       → base URL, user agent, rate limit, paths
  config.ts          → session loading: env var, own store, legacy Python store
  session.ts         → bridge between the stored session and the HTTP client
  http.ts            → typed client; 200-with-HTML means a dead route, 401 a dead session
  errors.ts          → error vocabulary: every failure has a code and a hint
  output.ts          → flag parsing, table rendering, human vs JSON mode
  endpoints.json     → the routes. A deprecation is fixed here, not in the code
  services/          → business logic, shared by CLI and MCP
    memberships.ts   → your enrolled courses, paginated and filtered
    courses.ts       → the syllabus tree, rebuilt from flat linked lists
    transcripts.ts   → probes video and reading microservices per item
    download.ts      → writes files, records where each course landed
    library.ts       → taxonomy cross-reference behind `coursera map`
    partners.ts      → resolves institution names to ids
  commands/          → one file per CLI command
  mcp/index.ts       → MCP server, 6 tools
  ui/
    theme.ts         → colour tokens, truecolor detection
    banner.ts        → wordmark and status dashboard
  cli/               → cligentic blocks: json-mode, error-map, xdg-paths, doctor
test/                → 87 tests against responses captured live from the API

Tech Stack

  • Bun — runtime. TypeScript runs directly, no build step
  • TypeScript — strict mode, no any
  • MCP SDK — the Claude integration, 6 tools
  • picocolors — the only runtime dependency besides the MCP SDK. Truecolor is layered on top of it in ui/theme.ts
  • cligentic — copy-paste blocks for agent-facing CLI concerns: structured output, typed errors, XDG paths, health checks

Docs

| File | Contents | |---|---| | SPEC.md | The spec: problem, decisions, scope, verification | | CONTEXT.md | Domain glossary | | RESEARCH.md | Portal recon: endpoints, gotchas, what is alive | | CHANGELOG.md | What changed in each version | | endpoints.json | The routes. A deprecation is fixed here, not in the code |

Tests

bun test          # 87 tests against responses captured live from the API
bun run typecheck

Legal

Reaches your own account with your own session, for courses you are already enrolled in. Downloaded material is copyrighted by Coursera and its universities: it is for your personal study. Do not redistribute it.