Download version-specific library documentation for AI coding agents.
Inspired by Next.js evals showing that providing AGENTS.md with bundled docs dramatically improves AI agent performance (Claude Opus 4.6: 71% → 100%), ASK generalizes this pattern to any library.
ASK uses a lazy-first architecture. You declare the libraries you
care about in a root-level ask.json, and ask install resolves
versions from your lockfile and generates AGENTS.md + SKILL.md
with lazy documentation references. AI agents then access docs
on-demand via ask src / ask docs commands.
ask add npm:next # Add to ask.json
ask add github:vercel/next.js@v14.2.3 # GitHub with inline ref
ask install # Resolve versions + generate AGENTS.md/SKILL.mdAfter ask add, your ask.json looks like:
{
"libraries": [
"npm:next",
"github:vercel/next.js@v14.2.3"
]
}Entries can also be written as { "spec": "...", "docsPaths": [...] } objects when you want to scope ask docs to a subset of discovered directories — see Add a library below.
Each successful install:
- Resolves the version (lockfile for
npm:, inline@refforgithub:) - Generates a Claude Code skill in
.claude/skills/<library>-docs/SKILL.mdwithask src/ask docsreferences - Generates/updates
AGENTS.mdwith version warnings and lazy command references
No documentation is downloaded during install — agents access docs
on-demand via ask src / ask docs, which fetch and cache on first use.
ask install is postinstall-friendly: failures on individual entries
emit a warning and the command still exits 0.
bun install
bun run buildpackages/cli/ @pleaseai/ask CLI (npm publishable)
apps/registry/ ASK Registry browser (Nuxt + Nuxt Content v3, Cloudflare Pages)
# PM-driven npm entry — version comes from your lockfile at install time
ask add npm:next
ask add npm:@mastra/client-js
# GitHub entry with inline ref
ask add github:vercel/next.js@v14.2.3
ask add vercel/next.js@v14.2.3 # github: prefix is implied for owner/repoask add appends a spec string to ask.json and immediately runs
install for that single entry.
When a library exposes multiple candidate documentation directories
(e.g. both docs/ and dist/docs/), ask add probes the local
node_modules/<pkg>/ and any already-cached git checkout, and — if
more than one candidate is found and stdout is a TTY — shows a
multiselect prompt so you can pin the entry to a specific subset.
The selection is saved back to ask.json as an object entry:
{
"libraries": [
"npm:zod",
{ "spec": "npm:next", "docsPaths": ["docs"] }
]
}Downstream ask docs <spec> calls then emit only the selected paths
instead of every candidate. Flags:
ask add npm:next --docs-paths docs,dist/docs # non-interactive — same effect as the prompt
ask add npm:next --clear-docs-paths # drop the override, restore default discoveryDiscovery is offline-first: ask add never triggers a fresh clone
on your behalf. If a spec has never been cached, the prompt is silently
skipped and the bare spec string is recorded. Run ask docs <spec>
once to warm the cache, then re-run ask add <spec> to pick paths.
ask install # Resolve versions + generate AGENTS.md/SKILL.mdask install reads ask.json, resolves each entry's version
(lockfile for npm:, inline @ref for github:), and generates AGENTS.md and .claude/skills/<name>-docs/SKILL.md
with lazy references (ask src / ask docs). No documentation is
downloaded — agents fetch docs on-demand.
ask list # Tabular view of ask.json + resolved versions
ask list --json # Same data as ListModelSchema-conformant JSONask remove next
ask remove @mastra/client-js
ask remove github:vercel/next.jsask remove deletes the matching spec from ask.json, removes the
skill file, and regenerates the AGENTS.md block.
ask src and ask docs are the primary way agents access
documentation. They print absolute paths to cached source trees,
fetching on cache miss:
ask src <spec> # Print the absolute path to a cached library source tree
ask docs <spec> # Print all candidate documentation paths from node_modules + the cached sourceBoth commands fetch on cache miss (first run) and short-circuit on cache
hit. They share the same ~/.ask/github/github.com/<owner>/<repo>/<tag>/
store.
# Print the absolute path to React's source tree (fetches on first run)
ask src react
# Grep across the full React source via shell substitution
rg "useState" $(ask src react)
# Print all docs candidates for vue — one path per line, agent picks
ask docs vue
# Search across every monorepo docs/ directory at once
rg "defineComponent" $(ask docs vue)
# CI guard: exit 1 if the cache is empty
ask src react --no-fetchSpec syntax — same npm:/github:/ecosystem-prefixed format as
ask add, plus an optional trailing @version:
ask src react # latest from npm registry
ask src react@18.2.0 # explicit version
ask src @vercel/ai@5.0.0 # scoped npm name + version
ask src github:facebook/react # github default branch
ask src github:facebook/react@v18.2.0 # github tag
ask src pypi:requests # cross-ecosystemVersion resolution priority for npm specs without an explicit
@version: project lockfile → resolver "latest". Explicit @version
always wins.
Registry-free — neither command consults the curated ASK Registry; both go straight to upstream package metadata.
ask docs walks node_modules/<pkg>/ only for npm-ecosystem specs (not
for github:/pypi:/etc.), and surfaces every subdirectory whose name
matches /doc/i up to depth 4, skipping node_modules, .git, .next,
.nuxt, dist, build, coverage, and dotdirs. The source root is
always emitted as the first line so the agent can fall back to it when no
docs/ directory exists.
If the spec has a persisted docsPaths override in ask.json (see
Selecting docs paths at add time),
ask docs emits only those paths. Stale entries (paths that no longer
exist on disk — e.g. after a major version bump) are dropped; when every
stored path is stale, a warning is written to stderr and the command
falls back to the unfiltered walk.
ask skills is a sibling namespace to ask docs that surfaces and
installs producer-side skills shipped by libraries under a top-level
skills/ directory (convention inherited from tanstack-intent).
# List all candidate skill paths for a library (read-only, one per line)
ask skills <spec> # shorthand for `skills list`
ask skills list <spec>
# Vendor skills into .ask/skills/ and symlink into each selected agent dir
ask skills install <spec>
ask skills install <spec> --agent claude,cursor
ask skills install <spec> --force # overwrite conflicting entries
# Reverse a prior install using the lock file
ask skills remove <spec>
ask skills remove <spec> --ignore-missingSkills are vendored once into .ask/skills/<spec-key>/<skill-name>/
(gitignored) and symlinked into each selected agent directory
(.claude/skills/, .cursor/skills/, .opencode/skills/,
.codex/skills/). install auto-detects which agents the project uses;
if more than one is present it prompts you to pick. A lock file at
.ask/skills-lock.json tracks what was installed so remove can reverse
the operation deterministically without touching user-authored skills.
v1 platform support is POSIX only (macOS/Linux) — Windows junction fallback is on the roadmap.
The ASK Registry (apps/registry/) is a community-maintained catalog of library documentation configs. Each entry is a JSON file keyed by <github-owner>/<repo>.json:
apps/registry/content/registry/
├── vercel/ # github owner
│ ├── next.js.json
│ └── ai.json
├── colinhacks/ # github owner
│ └── zod.json
├── tailwindlabs/ # github owner
│ └── tailwindcss.json
└── ... # one directory per github owner
Each entry describes one GitHub repository and declares one or more packages. A package is a documentation target (a single library has one, a monorepo has many). Each package declares ordered sources the CLI tries head-first with fallback on failure. See ADR-0001 for the rationale.
{
"name": "Next.js",
"description": "The React framework by Vercel",
"repo": "vercel/next.js",
"homepage": "https://nextjs.org",
"license": "MIT",
"tags": ["react", "framework", "ssr", "vercel"],
"packages": [
{
"name": "next",
"aliases": [
{ "ecosystem": "npm", "name": "next" }
],
"sources": [
{ "type": "npm", "package": "next", "path": "dist/docs" },
{ "type": "github", "repo": "vercel/next.js", "path": "docs" }
]
}
]
}One package per documentation target; each owns its own aliases and source chain.
{
"name": "Mastra",
"description": "TypeScript framework for building AI agents, workflows, and RAG pipelines",
"repo": "mastra-ai/mastra",
"packages": [
{
"name": "@mastra/core",
"aliases": [{ "ecosystem": "npm", "name": "@mastra/core" }],
"sources": [
{ "type": "npm", "package": "@mastra/core", "path": "dist/docs" },
{ "type": "github", "repo": "mastra-ai/mastra", "path": "docs" }
]
},
{
"name": "@mastra/memory",
"aliases": [{ "ecosystem": "npm", "name": "@mastra/memory" }],
"sources": [
{ "type": "npm", "package": "@mastra/memory", "path": "dist/docs" },
{ "type": "github", "repo": "mastra-ai/mastra", "path": "docs" }
]
}
]
}type |
Required fields | Optional |
|---|---|---|
npm |
package |
path (path inside the tarball, e.g. dist/docs) |
github |
repo (owner/name) |
branch or tag (mutually exclusive), path |
web |
urls (array, non-empty) |
maxDepth, allowedPathPrefix |
llms-txt |
url |
— |
Supported alias ecosystems: npm, pypi, pub, go, crates, hex, nuget, maven.
Add a new .json file under apps/registry/content/registry/<github-owner>/ and submit a PR. The file is validated against the registryEntrySchema in packages/schema/src/registry.ts at build time — duplicate aliases, duplicate package names, and slug collisions across packages are all rejected.
When a library isn't in the registry, ASK can automatically resolve its GitHub repository from ecosystem package metadata. This works for any ecosystem-prefixed spec:
ask add npm:lodash # Looks up registry.npmjs.org → lodash/lodash
ask add pypi:fastapi # Looks up pypi.org → fastapi/fastapi
ask add pub:riverpod # Looks up pub.dev → rrousselGit/riverpodSupported ecosystems:
| Ecosystem | API | Metadata field |
|---|---|---|
npm |
registry.npmjs.org/<name> |
repository.url |
pypi |
pypi.org/pypi/<name>/json |
info.project_urls.Source |
pub |
pub.dev/api/packages/<name> |
latest.pubspec.repository |
The resolver extracts the GitHub owner/repo from the package metadata and delegates to the GitHub source for download. The registry is always checked first — resolvers only activate on a registry miss.
Extracts documentation from npm package tarballs.
Downloads documentation from a GitHub repository at a specific tag or branch.
Crawls documentation websites and converts HTML to Markdown.
ASK maintains a global docs store at ~/.ask/ so identical <pkg>@<version> entries are fetched once per machine and reused across projects.
~/.ask/ # ASK_HOME
├── STORE_VERSION # always "2"
├── npm/
│ └── next@16.2.3/ # immutable doc entry
├── github/
│ └── github.com/ # host (reserved — gitlab/bitbucket later)
│ └── vercel/next.js/v16.2.3/ # per-tag shallow clone, .git/ stripped
├── web/
│ └── <sha256>/ # crawled snapshots
└── llms-txt/
└── <sha256>@<version>/
If you upgraded from an older ASK, you may have a legacy
~/.ask/github/{db,checkouts}/ tree left behind. Running ask install
prints a one-line warning on first touch pointing at the cleanup
command:
ask cache clean --legacyThe command is idempotent and safe to run on a clean tree.
Override the store location: ASK_HOME=/path/to/store ask install
ask cache ls # list store entries with sizes
ask cache ls --kind npm # filter by kind
ask cache gc --dry-run # preview what would be removed
ask cache gc # remove unreferenced entriesWe run our own eval suite (evals/nuxt-ui/) comparing documentation strategies on 6 Nuxt UI v4 tasks — including 3 breaking-change evals with negative assertions that catch deprecated v2/v3 API usage.
| Doc source | Pass rate | Est. cost | Retries needed |
|---|---|---|---|
| ASK github-docs (AGENTS.md) | 100% (6/6) | $1.67 | 0 |
| No docs (baseline) | 86% (6/7) | $1.82 | 1 |
| llms-full.txt (~200KB) | 46% (6/13) | $2.93 | 7 |
| llms.txt (~5KB) | 40% (6/15) | $4.83 | 9 |
Key findings:
- ASK-style docs outperform all alternatives — 100% pass rate at the lowest cost. Structured docs with version warnings let the agent find correct v4 APIs without excessive exploration.
- llms.txt / llms-full.txt hurt more than they help — Both scored below baseline. The agent spends tokens searching through unstructured docs but still uses deprecated patterns.
- Cost scales inversely with quality — The worst performer (llms.txt) costs 2.9x more than the best (ASK github-docs), driven by retry loops and exploratory tool calls.
Same docs payload, same model, same sandbox — only the delivery format changes:
| Delivery format | First-try pass rate | Notes |
|---|---|---|
| AGENTS.md pointer | 100% (6/6) | Baseline ASK behavior |
.claude/skills/<pkg>-docs/SKILL.md |
50% (3/6) | Failed first-try on 3 breaking-change evals (001, 003, 005); only recovered on retry |
This reproduces Vercel's public finding ("AGENTS.md outperforms skills in our agent evals") inside ASK's own suite.
See evals/nuxt-ui/README.md for full methodology and detailed results.
The Next.js evals benchmark (source code) showed that AI agents perform significantly better when given access to version-specific documentation via AGENTS.md:
| Agent | Without docs | With AGENTS.md |
|---|---|---|
| Claude Opus 4.6 | 71% | 100% |
| Gemini 3.1 Pro | 76% | 100% |
| GPT 5.3 Codex | 86% | 100% |
ASK makes it easy to apply this pattern to any library in any project.
- next-evals-oss — Vercel's open-source Next.js agent evals showing AGENTS.md impact
- skills-npm — Convention for shipping agent skills inside npm packages (maintainer-side)
- TanStack Intent — CLI for generating, validating, and shipping Agent Skills with npm packages
- Skilld — Generates agent skills from npm dependencies using docs, release notes, and GitHub discussions
- mdream — High-performance HTML to Markdown converter optimized for LLM applications
MIT