Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,31 @@ tags: [react, framework, ssr]

**Content API**: Nuxt Content v3 exposes registry entries as JSON via `/api/registry/{owner}/{name}`. The CLI fetches this during `ask add` / `ask install` when `--source` is omitted, passing either `{ecosystem}/{name}` (for ecosystem-prefixed specs) or `{owner}/{repo}` (for github shorthand specs).

### `apps/docs/` — Documentation Site (`@pleaseai/ask-docs`)

```
apps/docs/
├── app/
│ └── app.config.ts # site metadata (title, GitHub repo, UI overrides)
├── content/
│ ├── index.md # landing page (MDC syntax)
│ └── docs/
│ └── 1.getting-started/
│ ├── .navigation.yml
│ ├── 1.introduction.md
│ └── 2.installation.md
├── public/ # static assets (favicon, landing images)
├── eslint.config.ts # vue: true; ignores content/**/*.md (MDC isn't valid markdown)
├── nuxt.config.ts # extends ['docs-please']; same build-time D1/sqlite split as registry
├── package.json # depends on docs-please ^0.2.6 + nuxt ^4
├── tsconfig.json
└── wrangler.jsonc # Cloudflare Pages config (D1 binding name `DB`)
```

`apps/docs` is a thin wrapper around the [`docs-please`](https://github.com/pleaseai/docs) Nuxt layer (shadcn-vue + Nuxt Content + Tailwind 4). The layer ships the chrome (header, footer, sidebar, TOC) and styling; this app provides metadata via `app.config.ts` and the actual content as `.md` files under `content/`.

Same Cloudflare/sqlite split as `apps/registry/`: the `nuxt.config.ts` inspects `NITRO_PRESET` / `CF_PAGES` / `NUXT_CONTENT_DATABASE_TYPE` at build time and picks the D1 binding or the native sqlite connector accordingly.

## Global Store (`~/.ask/`)

ASK maintains a per-machine docs store at `ASK_HOME` (default `~/.ask/`) so identical entries are fetched once and reused across projects. All four source kinds follow the PM-style `<kind>/<identity>@<version>/` mental model:
Expand Down
10 changes: 8 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ bun run --cwd apps/registry build
bun run --cwd apps/registry test # unit only (e2e skipped without host)
REGISTRY_E2E_HOST=http://localhost:3000 bun run --cwd apps/registry test # e2e against a separately started dev server

# Docs site (apps/docs/)
bun run --cwd apps/docs dev
bun run --cwd apps/docs build # Cloudflare Pages preset (default)
bun run --cwd apps/docs build:node # Node preset (no D1 required)

# Running CLI directly
node packages/cli/dist/index.js docs add <spec> -s <source> [options]
```
Expand All @@ -48,8 +53,9 @@ node packages/cli/dist/index.js docs add <spec> -s <source> [options]
## Gotchas

- Always use `bun run test` (not `bun test`) to run tests — `bun test` may be blocked by hooks or workspace configuration.
- bun workspace uses `.bun/` symlink structure — native Node modules (e.g. better-sqlite3) may fail to load. Prefer native alternatives (e.g. `node:sqlite`)
- Docus (Nuxt docs theme) is incompatible with bun workspace (nuxt-content/docus#1279)
- Root `bunfig.toml` forces `linker = "hoisted"`. Bun 1.3.2+ defaults workspace projects to the `isolated` linker (pnpm-style `.bun/` symlinks), which breaks Nitro's Rollup pipeline when a dep ships raw `.ts`/`.vue` from `node_modules` (see nuxt-content/docus#1279). With hoisted, `node_modules/` is flat and 1300+ packages live at root — no `.bun/` directory exists. If you ever flip back to isolated, re-test `apps/docs` (docs-please) and `apps/registry` and re-validate the `h3@2.0.1-rc.*` cleanup in root postinstall (it becomes a no-op under hoisted).
- bun workspace previously used `.bun/` symlink structure — native Node modules (e.g. better-sqlite3) failed to load. Prefer native alternatives (e.g. `node:sqlite`). Under hoisted these issues do not manifest, but the `node:sqlite` preference still applies for Cloudflare Workers / D1 compatibility.
- Docus (Nuxt docs theme) is incompatible with bun workspace (nuxt-content/docus#1279). `docs-please` (Nuxt layer from github.com/pleaseai/docs) is the documentation backbone for `apps/docs/`. It publishes raw `.vue` files that use `interface Props extends NuxtLinkProps` / `extends PrimitiveProps` — Vue SFC compiler cannot resolve the auto-imported types when the .vue sits inside `node_modules/`, so `patches/docs-please@0.2.6.patch` injects `/* @vue-ignore */` before each base. Upstream pleaseai/docs uses `workspace:*` so the issue only surfaces when consuming `docs-please` as a published npm package. If `docs-please` ever ships a fix (or pre-compiled .vue), drop the patch.
- Nuxt Content v3 requires SQLite at build time even when deploying to D1. Use `experimental.sqliteConnector: 'native'` (requires Node 22.5+)
- In `content.config.ts`, import `z` from `@nuxt/content` — do not install zod separately
- `getSource(type)` (`packages/cli/src/sources/index.ts:54`) returns a `DocSource`; pass config to `DocSource.fetch(options)`, not to `getSource`. It is a single-arg factory.
Expand Down
6 changes: 6 additions & 0 deletions apps/docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.nuxt/
.output/
dist/
.data/
node_modules/
.turbo/
1 change: 1 addition & 0 deletions apps/docs/.wrangler/deploy/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "configPath": "../../dist/_worker.js/wrangler.json" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Remove this file and add .wrangler/ to .gitignore. The config.json inside .wrangler/deploy/ is auto-generated by wrangler deploy / wrangler pages deploy and should not be committed to version control. The repo's source-of-truth for Wrangler config is already apps/docs/wrangler.jsonc.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/.wrangler/deploy/config.json, line 1:

<comment>Remove this file and add `.wrangler/` to `.gitignore`. The `config.json` inside `.wrangler/deploy/` is auto-generated by `wrangler deploy` / `wrangler pages deploy` and should not be committed to version control. The repo's source-of-truth for Wrangler config is already `apps/docs/wrangler.jsonc`.</comment>

<file context>
@@ -0,0 +1 @@
+{ "configPath": "../../dist/_worker.js/wrangler.json" }
</file context>

52 changes: 52 additions & 0 deletions apps/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# ASK Docs

Documentation site for [`@pleaseai/ask`](../../packages/cli/), built with the [`docs-please`](https://github.com/pleaseai/docs) Nuxt layer.

## Development

```bash
# From the workspace root
bun install
bun run --cwd apps/docs dev
```

## Build

```bash
# Cloudflare Pages (production)
bun run --cwd apps/docs build

# Local Node preset (no D1 required)
bun run --cwd apps/docs build:node
```

The build target picks the [`@nuxt/content`](https://content.nuxt.com) database backend automatically:

- Cloudflare signals (`NITRO_PRESET=cloudflare_pages`, `CF_PAGES=1`, or `NUXT_CONTENT_DATABASE_TYPE=d1`) → D1 binding `DB`
- Local builds → native `sqlite` connector at `.data/content/contents.sqlite`

## Structure

```
apps/docs/
├── app/
│ └── app.config.ts # site metadata (title, GitHub repo, UI overrides)
├── content/
│ ├── index.md # landing page
│ └── docs/
│ └── 1.getting-started/
│ ├── 1.introduction.md
│ └── 2.installation.md
├── public/ # static assets
├── eslint.config.ts
├── nuxt.config.ts
├── package.json
├── tsconfig.json
└── wrangler.jsonc # Cloudflare Pages config (D1 binding)
```

## Deploy (Cloudflare Pages)

1. Create the D1 database: `wrangler d1 create ask-docs-db`
2. Paste the returned `database_id` into `wrangler.jsonc`
3. Cloudflare Pages project: root = repo root, build command = `bun run --cwd apps/docs build`, output = `apps/docs/dist`
28 changes: 28 additions & 0 deletions apps/docs/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export default defineAppConfig({
docs: {
title: 'ASK',
github: {
url: 'https://github.com/pleaseai/ask',
owner: 'pleaseai',
name: 'ask',
branch: 'main',
},
},
github: {
rootDir: 'apps/docs',
},
ui: {
pageHero: {
slots: {
title: 'font-semibold sm:text-6xl',
container: '!pb-0',
},
},
pageCard: {
slots: {
container: 'lg:flex min-w-0',
wrapper: 'flex-none',
},
},
},
})
2 changes: 2 additions & 0 deletions apps/docs/content/docs/1.getting-started/.navigation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
title: Getting Started
icon: i-lucide-rocket

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The icon field must be nested under a navigation: key. Without this, Nuxt Content will not apply the icon to the directory navigation item returned by queryCollectionNavigation().

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/content/docs/1.getting-started/.navigation.yml, line 2:

<comment>The `icon` field must be nested under a `navigation:` key. Without this, Nuxt Content will not apply the icon to the directory navigation item returned by `queryCollectionNavigation()`.</comment>

<file context>
@@ -0,0 +1,2 @@
+title: Getting Started
+icon: i-lucide-rocket
</file context>

33 changes: 33 additions & 0 deletions apps/docs/content/docs/1.getting-started/1.introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: Introduction
description: What ASK is and why it exists.
---

# Introduction

**ASK** (Agent Skills Kit) is a CLI that downloads version-specific library documentation and source for AI coding agents, then generates an `AGENTS.md` index plus per-library Claude Code skills under `.claude/skills/<name>-docs/SKILL.md`.

The agent reads the docs that match the version your project actually runs — not the snapshot baked into its training data.

## Why this exists

Training data ages. Lockfiles don't.

When an agent recalls "how `zod` works" from memory, it's recalling whatever shape the API had at the cutoff. When the project pins `zod@3.22.0`, the agent should be reading `~/.ask/...zod/3.22.0/README.md`, not guessing.

ASK bridges the two by:

1. Reading the version from `bun.lock` → `package-lock.json` → `pnpm-lock.yaml` → `yarn.lock` → `package.json` range fallback.
2. Fetching docs/source once and caching under `~/.ask/` (override via `ASK_HOME`).
3. Printing absolute paths to stdout, errors to stderr — safe for `$(ask …)` composition.

## How agents consume ASK

Two surfaces, depending on workflow:

- **Declarative** — `ask.json` at the project root lists libraries. `ask install` resolves every entry, materializes docs under `.ask/docs/<name>@<version>/`, writes a Claude skill, and regenerates the auto-managed block in `AGENTS.md`.
- **One-shot** — `ask docs <spec>` and `ask src <spec>` emit cached paths for ad-hoc reads. Composable with `rg`, `cat`, `fd`.

## Next steps

- [Installation](/docs/getting-started/installation) — install the CLI and run it against an existing project.
78 changes: 78 additions & 0 deletions apps/docs/content/docs/1.getting-started/2.installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
title: Installation
description: Install the ASK CLI and run it against your project.
---

# Installation

## Prerequisites

- Node.js **22.5+** (required for the `node:sqlite` connector used by some integrations)
- A package manager (bun, npm, pnpm, or yarn) — ASK reads whichever lockfile is present

## Install the CLI

```bash
# bun (recommended for this repo)
bun add -d @pleaseai/ask

# npm
npm install -D @pleaseai/ask

# pnpm
pnpm add -D @pleaseai/ask

# yarn
yarn add -D @pleaseai/ask
```

Or run ad-hoc without installing:

```bash
bunx @pleaseai/ask docs zod
npx @pleaseai/ask docs zod
```

## First run

Declare libraries in `ask.json`:

```json
{
"libraries": [
"npm:next",
"npm:zod",
{ "spec": "github:tanstack/intent", "ref": "v0.5.0" }
]
}
```

Then resolve, fetch, and wire everything up:

```bash
ask install
```

This will:

1. Resolve every entry against the project's lockfile (or the pinned `ref` for github specs).
2. Fetch docs into `.ask/docs/<name>@<version>/` (gitignored).
3. Write a Claude Code skill at `.claude/skills/<name>-docs/SKILL.md`.
4. Regenerate the `<!-- BEGIN:ask-docs-auto-generated -->` block in `AGENTS.md`.

## One-shot reads

No `ask.json` required:

```bash
# Candidate doc directories (one per line)
ask docs zod

# Cached checkout root (single path)
ask src facebook/react

# Producer-shipped skills
ask skills list vercel/ai
```

All three commands share a single cache at `~/.ask/` (override with `ASK_HOME`).
80 changes: 80 additions & 0 deletions apps/docs/content/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: ASK
seo:
title: Version-accurate library docs for AI coding agents
description: ASK (Agent Skills Kit) downloads version-specific library documentation and generates AGENTS.md and Claude Code skills so AI agents reference accurate docs instead of training data.
---

::u-page-hero
#headline
:::u-button{to="https://github.com/pleaseai/ask/releases" target="_blank" variant="outline" size="sm"}
ASK is on npm →
:::

#title
Version-accurate library docs for AI coding agents.

#description
ASK downloads version-specific library docs and generates **AGENTS.md** + **Claude Code skills** so your agent reads real code at the version your project actually runs — not last year's training snapshot.

#links
:::u-button{to="/docs/getting-started/introduction" size="lg"}
Get Started →
:::

:::u-button{to="https://github.com/pleaseai/ask" target="_blank" variant="outline" size="lg"}
Star on GitHub
:::
::

::u-page-section
:::u-page-grid{class="lg:grid-cols-2"}
::::u-page-card{class="col-span-1"}
#title
Pinned to your [lockfile]{.text-primary}

#description
ASK resolves versions from `bun.lock`, `package-lock.json`, `pnpm-lock.yaml`, or `yarn.lock` — every read reflects the version your project actually installs.
::::

::::u-page-card{class="col-span-1"}
#title
Generates [AGENTS.md]{.text-primary}

#description
Each library lands as a Claude Code skill under `.claude/skills/<name>-docs/SKILL.md`, indexed by a single auto-generated `AGENTS.md` block.
::::

::::u-page-card{class="col-span-2"}
#title
Works with [npm, PyPI, Go, Crates, Pub, Hex, NuGet, Maven]{.text-primary}

#description
The ASK Registry maps ecosystem specs (`npm:react`, `pypi:fastapi`, `crates:tokio`) to their GitHub source and docs path. Bare `owner/repo` works too.

#body
```bash
ask install # resolve every entry in ask.json
ask add npm:next # add a library and regenerate AGENTS.md
ask docs zod # print candidate doc paths for the version in lockfile
ask src facebook/react # print the cached checkout root
```
::::

::::u-page-card{class="col-span-1"}
#title
[One-shot reading]{.text-primary} commands

#description
`ask docs <spec>` and `ask src <spec>` emit absolute paths to stdout — drop them straight into `$(…)` for `rg`, `cat`, `fd`, or any tool that takes a path.
::::

::::u-page-card{class="col-span-1"}
#title
Cached at [`~/.ask/`]{.text-primary}

#description
Every fetched library is stored once under `~/.ask/`. Multiple projects share the same cache; `ask cache ls` and `ask cache clean` manage disk pressure.
::::
:::
::
12 changes: 12 additions & 0 deletions apps/docs/eslint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai(
{
vue: true,
},
{
// MDC syntax (`#headline`, `::component`, `:::block`) parses as
// invalid Markdown to ESLint's `markdown` plugin. Skip content/.
ignores: ['content/**/*.md'],
},
)
Loading