CLI for devdocs.io content — search and read development documentation from the terminal or from automated workflows (scripts, LLM tool-use loops, editor integrations).
Docsets are downloaded once, stored under $LOCADOC_HOME, and searched with the same scoring algorithm devdocs.io uses in-browser.
Prefer a local replay? The raw asciicast is checked in:
asciinema play docs/demo.cast # replay at recorded speed
asciinema play -s 2 docs/demo.cast # 2× speed
bash scripts/demo.sh # run the demo live against your locadoc installAI-assisted project. This codebase was designed and implemented collaboratively with an AI coding agent (Claude Code). The initial research, architecture decisions, and full implementation were produced in a single session from the prompt below. Review the source before depending on it in production.
Original prompt:
I want to create a cli powered version of devdocs.io, to allow searching and fetching development documents directly from the terminal or piped in automated workflows. We can use https://github.com/toiletbril/dedoc as reference, but I don't want to make a carbon copy of the codebase, the idea is to keep things simple and make the tool AI friendly. Look into devdocs repository as well if needed (https://github.com/freeCodeCamp/devdocs).
curl -fsSL https://raw.githubusercontent.com/jctosta/locadoc/main/install.sh | bashGrabs the right prebuilt binary for your OS/arch from GitHub Releases, verifies its SHA-256, and drops locadoc into ~/.local/bin. macOS and Linux (x64 and arm64) are supported.
Env overrides:
| Variable | Default | Purpose |
|---|---|---|
PREFIX |
$HOME/.local/bin |
install directory (e.g. PREFIX=/usr/local/bin sudo bash install.sh) |
LOCADOC_VERSION |
latest |
pin a specific release tag (e.g. LOCADOC_VERSION=v0.1.0) |
If $PREFIX isn't on your PATH, the installer prints a one-liner to add to your shell rc.
For Windows, download the binary directly from the latest release.
bun install
bun link # exposes `locadoc` as a global commandOr run without linking:
bun run src/cli.ts <command>locadoc docs # fetch the manifest of available docsets
locadoc ls --all | head # browse what's available
locadoc download bun react # install one or more docsets
locadoc ls # see what's installed
locadoc search useEffect # search across all installed docsets
locadoc read react reference/react/useeffectPage paths come from the path column of search output — don't guess them. They map directly to keys in the docset's db.json.
locadoc is TTY-aware. Pretty output goes to a terminal, JSON goes to a pipe:
locadoc search useEffect # human-friendly table
locadoc search useEffect | jq '.[0]' # structured JSONForce either explicitly:
locadoc search useEffect --json
locadoc ls --all --textSet NO_COLOR=1 to disable ANSI styling.
Fetch the manifest of available docsets from https://devdocs.io/docs.json. Cached for 24h; use --refresh to force re-fetch.
Default: list installed docsets. --all lists everything in the manifest (requires locadoc docs first).
Install one or more docsets. Fetches {slug}.tar.gz from downloads.devdocs.io and falls back to the per-file JSON endpoints on documents.devdocs.io if the tarball is missing.
Re-download docsets whose mtime is older than the manifest. With no args, updates everything installed.
Delete docsets from disk and the registry.
Search installed docsets. Scoring is a port of devdocs' searcher.js: exact substring first, then fuzzy regex for queries ≥ 3 chars. Without --docset, searches across every installed docset.
Replace the running binary with the latest GitHub release. Fetches the release asset for the current OS/arch, verifies it against SHA256SUMS, then atomically swaps the binary at process.execPath.
--check— print latest version, exit without installing. Works from source, too.--force— reinstall even if already at the latest version.--dry-run— show what would happen; no download, no replace.
On Windows, the running .exe is renamed aside and the new binary moved into place. Close other locadoc processes first if the rename fails.
Running from source (bun run src/cli.ts self-update) is refused — use git pull && bun install instead. --check and --dry-run still work from source.
JSON schema:
{ currentVersion, latestVersion, action: "updated" | "no-op" | "available" | "dry-run" | "refused", path?, reason? }Sanity-check the locadoc installation. Runs eight checks:
home—$LOCADOC_HOMEexists and is writablemanifest— manifest cached, age under 24hdatabase— SQLitePRAGMA integrity_checkdocsets— registry rows match the directories on diskbinary—process.execPathonPATHversion— whether a newer release is available (skip with--no-network)skill (global)/skill (project)— Claude Code skill installation status
JSON:
{ checks: { name, status: "ok" | "warn" | "fail", detail }[],
summary: { ok, warn, fail } }Exit code 5 if any check is fail; 0 if only warnings or all ok.
Render a docset page. Paths come from search output. Fragments slice the HTML to a heading and its siblings.
--format defaults:
ansiwhen stdout is a TTYmdwhen piped or--jsonis setrawreturns the untouched HTML;htmlreturns the stripped/sliced HTML
Stable shapes, safe to consume from scripts / LLM tool calls.
ls / ls --all — LsRow[]:
{ slug, name, version?, release?, mtime, installed, stale }search — SearchResult[]:
{ docset, name, path, type, score }read — ReadResult:
{ docset, path, fragment?, title, markdown, attribution? }docs — { count, cachedAt, path }
download / remove — per-slug status records.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Not found (docset, page, search results) |
| 2 | Usage error |
| 3 | Network error |
| 4 | Storage error |
| 5 | Doctor check failed |
$LOCADOC_HOME (default: ~/.locadoc/)
├── manifest.json # cached docs.json
├── docsets/<slug>/ # index.json, db.json, meta.json (+ html assets)
└── locadoc.db # SQLite: installed docsets + flattened entries index
Set LOCADOC_HOME or pass --home <path> to relocate.
locadoc is designed to be called from LLM tool loops and scripts.
# Find a page, then read it, all as JSON
locadoc search 'promise.all' --json --limit 1 \
| jq -r '.[0] | "\(.docset) \(.path)"' \
| xargs -n2 locadoc read --json \
| jq -r '.markdown'--json/--textforce the output format independent of TTY state.--quietsilences stderr progress.- Schemas are stable — only additive changes within
0.x. - No prompts, no spinners when piped.
locadoc ships with a Claude Code skill that teaches the model when and how to reach for locadoc. Install it once and any future Claude Code session picks it up automatically:
locadoc skill install # writes ~/.claude/skills/locadoc/SKILL.md
locadoc skill install --project # ./.claude/skills/locadoc/SKILL.md (this project only)
locadoc skill install --force # overwrite existing
locadoc skill install --dry-run # preview without writing
locadoc skill where # print the target path
locadoc skill show # dump the embedded SKILL.md
locadoc skill uninstall # remove itThe skill auto-triggers on API / library documentation questions (e.g. "how does useEffect work", "signature of Array.prototype.reduce") and includes allowed-tools: Bash(locadoc:*) so Claude doesn't need to ask for permission on every invocation.
JSON schemas (stable within 0.x):
install/uninstall/ dry-run →{ scope, path, action, bytes? }whereaction ∈ {installed, updated, skipped, removed, absent, dry-run}.where→{ scope, path, exists }.show→ raw SKILL.md to stdout (no wrapper).
The SKILL.md content is embedded in the compiled binary via Bun's text-import — installing works offline and is version-locked to your locadoc binary. Update the skill by re-running locadoc skill install --force after upgrading.
locadoc is released under the MIT License, with one exception: src/searcher.ts is a TypeScript port of devdocs.io's assets/javascripts/app/searcher.js and remains under the Mozilla Public License 2.0 per MPL's file-level copyleft.
Documentation content fetched at runtime is © its respective upstream authors, aggregated by devdocs.io under MPL 2.0. This project does not redistribute docset content; it downloads it on demand from the public devdocs CDN.
dedoc (GPL-3.0) by toiletbril served as a reference for the command surface and storage model — no code was copied from it. locadoc is an independent Bun/TypeScript implementation with different design goals (TTY-aware JSON output, Markdown rendering, AI tool-use friendly schemas).
bun test # run the test suite
bunx tsc --noEmit # typecheck
LOCADOC_HOME=/tmp/x bun run src/cli.ts docs