# AI Diataxis Scaffold

> Stand up the four Diátaxis mode directories, each seeded with an index page, in a project that has no documentation tree. Invoke ONLY via the /ai-diataxis-scaffold slash command. Do not activate from intent, keywords, or near-synonyms — slash incantation is required.

- Skill: `aws-samples/ai-diataxis-scaffold` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add aws-samples/ai-diataxis-scaffold`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aws-samples/ai-diataxis-scaffold/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: aws-samples (https://skillmd.com/u/aws-samples)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aws-samples/ai-diataxis-scaffold

---


# Agent: Scaffold a Diátaxis Documentation Tree

You stand up the four [Diátaxis](https://diataxis.fr) mode directories —
`tutorial/`, `how-to/`, `reference/`, `explanation/` — in a project that does not
have them, and you seed every directory you create with a real index page. You
create only what is missing, you never overwrite, and you never leave a directory
empty.

Classifying individual pages is `/ai-diataxis`'s job, not yours. You place four
index pages whose mode is known by construction; you do not run the compass over
anything.

## Why this skill exists, and where it deviates

Diátaxis is explicit that creating the four **empty** mode directories up front is
the practice to avoid: getting started "certainly does not mean that you should
create empty structures for tutorials/howto guides/reference/explanation" —
structures "with nothing in them." Then: "Don't do that. It's horrible."
(<https://diataxis.fr/how-to-use-diataxis/>.)

Two things about that rule, both stated in full at
`.claude/skills/ai-skills-reference/diataxis-classification.md` §6. **Read it
before you run.**

- **Its scope is projects that already have documentation.** The rule sits inside
  an improvement cycle whose first step is "Choose something - any piece of the
  documentation," which presupposes documentation to choose from. The source is
  silent on a project with none.
- **Its spirit is broader than its letter, and this skill deviates from that
  spirit.** The source's claim is that structure should form "from the inside."
  A scaffold imposes it from outside. Do not tell the user Diátaxis endorses what
  you are doing. It does not; the argument for doing it anyway is that a person
  cannot adopt a structure they have never seen, and that every directory here
  ships with a page in it.

**The same disclaimer covers the second axis.** When step 2's audience question is
answered with anything but its default, this skill builds a tree partitioned by
reader as well as by mode. The one upstream page that raises that shape —
<https://web.archive.org/web/20260802004758/https://diataxis.fr/complex-hierarchies/>
(snapshot captured 2026-08-02, retrieved 2026-08-24; the live URL returns 404 as of
2026-08-24, so the guidance is published-but-withdrawn) — **presents it only as a
question it declines to answer**: "Which better? There seems to be a lot of
repetition in either cases." So claim no source support for the two-axis shape
either. State that Diátaxis does not endorse it, name that page as raising and
declining it, and say the argument for offering it is this project's own.

**So: never create a directory you do not also seed.** That is not a stylistic
preference. Git does not track empty directories, so four empty directories
produce zero commits and there is nothing to hand over; and an autogenerated
sidebar over an empty directory fails a Docusaurus build.

## User Input

```text
$ARGUMENTS
```

Treat any argument as a hint about where the docs root should be — it feeds step 2
as the user's stated preference. An empty argument is the normal case.

---

## Step 1: Gate on project context

Read `.context/README.md` from the project root.

- **Absent** → print exactly: "No project context found at `.context/README.md`.
  Run `/ai-init` first to set up your project context." Then **stop**. Write
  nothing. `/ai-init` is the sole writer of that file and every other skill in
  this collection gates the same way.
- **Present** → parse its YAML frontmatter and carry `docs_path` and
  `output_path` into step 2. Also read Voice and Principles: the seed pages are
  prose this project ships, so they follow the project's register.

## Step 2: Resolve the published docs root

Resolve in this order and **report which step resolved it**:

1. **`docs_path` in `.context/README.md` frontmatter.** Present and a string →
   use it and ask nothing. Present but not a string → WARN: "docs_path in
   `.context/README.md` is not a string; asking where the docs root should live."
   Fall through. Do not block.
2. **A static-site config**, via
   `.claude/skills/ai-skills-reference/framework-detection.md` — match a
   generator config to its docs location.
3. **Conventional directories**, in order: `docs/`, `documentation/`, `website/`.
4. **`AskUserQuestion`.** Offer the detected or conventional path marked
   **(recommended)**, plus the other plausible candidates.

**Expect step 4 to fire.** This is the point most likely to be got wrong:
`framework-detection.md` matches a generator config to an existing docs location,
so it detects a site that is *already there*. A greenfield project — the case this
skill exists for — has no config to match and no docs directory, so steps 2 and 3
return nothing and **the interview is the normal path, not the fallback.** Write
the question accordingly: say that the answer becomes the root of the whole tree,
and name what you will create under it.

On confirmation, write `docs_path` into `.context/README.md` frontmatter with the
Edit tool and report that the interview will not repeat. If the user declines, use
the value for this run only.

### Step 2b: Ask the audience question — once, before anything is created

**Ask this in step 2 and not later.** Step 5 creates directories, and the above-mode
shape cannot be adopted after that: once `docs_path/how-to/` holds six pages, moving
to `user-docs/how-to/` relocates every page and breaks every cross-mode index link.
The one moment the choice costs nothing is before the tree exists.

Use `AskUserQuestion` with three options:

- **No audiences** *(recommended)* — the four mode directories go directly under
  `docs_path`. One readership, which is the ordinary case.
- **A user tree and a developer tree** — two audience roots, each holding its own
  four mode directories.
- **Something else** — the builder names their audiences.

Write the question to the same standard step 2 already sets for the docs root: say
that **the answer determines where the four mode directories go**, name what will be
created under each option, and say that **changing it later moves every page.**

**The options are examples of a shape, not a vocabulary.** `user` and `developer` are
offered because they are the common pair; a project that picks "something else" names
its own labels with no suggestion from this skill. An audience has a **label** — the
project's own word — and an **object**, the thing that audience's readers act on
(*the released command-line tool*, *this repository's source tree*). **The object is
never a person**, and it is what the landing page seed needs. The rule in full is
reference §12 in
`.claude/skills/ai-skills-reference/diataxis-classification.md`.

**Do not write the answer into `.context/README.md`.** `/ai-init` is the sole writer
of that file's body, and `## Audiences` is never interviewed for there. Instead, when
the answer is anything but the default, **print the `## Audiences` section for the
user to paste**, one bullet per audience carrying its label and the object its readers
act on.

## Step 3: Detect the static-site generator

Run the detection table in `framework-detection.md` again, this time for the
generator rather than the path.

- **Found** → report which one and where its config is.
- **None found** → report that no static-site generator was detected and that the
  tree will not render as a site until one is added.

**Generate no configuration either way.** Standing up a generator is a different
job, and it is most of what got the retired `ai-code-docs-setup` skill deleted.
Create the tree regardless: the directories and pages are useful as files, and a
generator added later picks them up.

## Step 4: Check every artifact independently, and report before writing

Check the existence of **each directory and each page separately**. Do not use a
single global "does a docs site exist?" gate — that is what the retired setup
skill did, and it is wrong in both directions here: a run interrupted after
creating directories but before writing pages looks complete, and a project with a
finished site in some other shape gets refused when it needs a report.

Report a table of what you found, before creating anything:

```text
docs_path: docs/docs   (from .context/README.md)
generator: Docusaurus  (docs/docusaurus.config.ts)

  tutorial/       exists, 2 pages       — leaving untouched
  how-to/         exists, 6 pages       — leaving untouched
  reference/      missing               — will create + seed index.md
  explanation/    missing               — will create + seed index.md
  _templates/     missing               — will copy 5 templates
  ../CLAUDE.md    exists                — will print a snippet instead

Creating 2 directories, 2 index pages, 5 template files. Writing 0 existing files.
```

**When step 2b returned audiences, report the whole shape in the same form**, and
report it **before writing anything** — the count is the number most worth seeing
early, because it is more than double the default:

```text
docs_path: docs/docs   (from .context/README.md)
generator: Docusaurus  (docs/docusaurus.config.ts)
audiences: user, developer   (from the step 2b answer)

  user-docs/                    missing   — will create + seed index.md
  user-docs/tutorial/           missing   — will create + seed index.md
  user-docs/how-to/             missing   — will create + seed index.md
  user-docs/reference/          missing   — will create + seed index.md
  user-docs/explanation/        missing   — will create + seed index.md
  developer-docs/               missing   — will create + seed index.md
  developer-docs/tutorial/      missing   — will create + seed index.md
  developer-docs/how-to/        missing   — will create + seed index.md
  developer-docs/reference/     missing   — will create + seed index.md
  developer-docs/explanation/   missing   — will create + seed index.md
  _templates/                   missing   — will copy 5 templates
  ../CLAUDE.md                  missing   — will write

Creating 10 directories, 10 index pages, 5 template files. Writing 0 existing files.
Against 4 directories and 4 pages for the no-audiences answer.
```

**Never overwrite.** Where a target file already exists, warn and ask whether to
overwrite or skip; default to skip. An existing page must be byte-identical after
the run.

**When all four directories already exist**, report that the tree is in place,
write nothing, and point the user at `/ai-diataxis` for classifying individual
pages. Do not seed a fifth thing to justify the run.

**When a populated docs tree exists in some other shape** — pages, but not these
four directories — report what is there, create the missing mode directories, and
say plainly that moving existing pages into modes is not this skill's job:
`/ai-diataxis` SURVEY assesses a tree page by page.

## Step 5: Create the missing directories and seed each one

Branch on step 2b's answer. The two branches share every non-negotiable below.

### 5a. The default answer — no audiences

Create the four mode directories directly under `docs_path`, seed each one, and
**change nothing else.** This path must be **byte-identical to a run of this skill
before the audience question existed**: four directories, four index pages, and **no
output line naming an audience, a readership, a shape, or a second axis.** Not even
to say the question was asked and declined.

That is the point rather than a nicety. A builder who answered "no audiences" has one
readership, and a scaffold that then tells them about a distinction selecting nothing
has reintroduced exactly the noise the axis was designed to avoid.

### 5b. Any other answer — one root per audience

Create **one audience root per declared audience**, each holding the four seeded mode
directories, plus **one landing page per root**. For two audiences that is ten
directories and ten pages, reported in step 4's form before any of it is written.

Then **print the registration lines and stop there**:

- **Docusaurus** — one sidebar entry and one navbar item per root:

  ```text
  // sidebars.ts — one per audience root
  userDocsSidebar: [{type: 'autogenerated', dirName: 'user-docs'}],
  developerDocsSidebar: [{type: 'autogenerated', dirName: 'developer-docs'}],

  // docusaurus.config.ts — navbar.items, one per audience root
  { type: 'docSidebar', sidebarId: 'userDocsSidebar', position: 'left', label: 'User docs' },
  { type: 'docSidebar', sidebarId: 'developerDocsSidebar', position: 'left', label: 'Developer docs' },
  ```

- **Another generator, or none detected** — name what it registers a top-level tree
  with, or say that no generator was detected and the tree will not render at all.

**Edit no configuration file, and say the tree is unreachable from the site's
navigation until those lines are added.** This is the failure most easily produced by
being helpful: pages that exist, build, and no reader can reach. Reference §12 states
the rule — a skill never creates an audience root it cannot register, so a skill that
creates one hands over the registration.

**Repeat the no-endorsement disclaimer here**, in one line, naming the withdrawn
upstream page as raising the two-axis shape and declining to recommend it.

### Seeding, both branches

The four mode seed shapes are in `references/seeds.md` — read it and use them; they
carry the frontmatter keys, the reader-facing paragraph, the fenced worked example,
and the cross-mode links. The **audience landing page** is the fifth shape in that
same file, used only in 5b.

Non-negotiables, all checked in step 8:

- **`.md`, never `.mdx`.** Under `format: 'detect'` an `.mdx` file goes through
  the MDX compiler, where `{anything}` is a JSX expression.
- **No `{` in any emitted page.** Write the worked examples filled in.
- **Only link to modes that exist or that this run is creating.** A seed's
  cross-mode links must not point at a directory you skipped.
- **Apply the project's Voice and Principles** from step 1. These pages are prose
  the project ships.

## Step 6: Copy the page templates

Copy all five files from this skill's `references/templates/` to
`docs_path/_templates/`, **headers intact**. Those headers carry the only MIT-0
attribution and upstream provenance there is — there is no LICENSE or NOTICE file
to fall back on, so stripping a header destroys the attribution.

Report where they landed and that they are reference material, not pages to
publish. The templates keep their `{placeholders}`; they are not emitted pages, so
the no-`{` rule does not apply to them.

**Check for a Docusaurus `exclude` override.** Docusaurus's default `exclude`
skips `**/_*/**`, but a project that sets its own `exclude` array *replaces* that
default rather than adding to it — at which point `_templates/` publishes. If the
detected config sets `exclude`, tell the user to add `'**/_*/**'` to it, and quote
the line. Do not edit their config. (This repository is its own example:
`docs/docusaurus.config.ts` overrides `exclude` and has lost that guard.)

## Step 7: Write the docs-tree `CLAUDE.md`, print the `AGENTS.md` snippet

Compute the placement:

```text
parent := dirname(docs_path)

if parent != project_root and no CLAUDE.md at parent:
    write parent/CLAUDE.md            # docs/docs → docs/CLAUDE.md
else:
    print the content as a snippet    # never clobber an existing CLAUDE.md
```

**Never write `docs_path/CLAUDE.md`.** Under MkDocs, every `.md` below the docs
directory becomes a page, so the agent-context file would publish as
documentation.

The content is in `references/seeds.md`, and **which variant you use follows step
2b**:

- **Default answer (no audiences)** → use the docs-tree `CLAUDE.md` seed **exactly as
  written, byte for byte.** It gains nothing about audiences, shapes, or thresholds.
- **Any other answer** → use the audience variant in the same file. It adds the
  audience paths filled in from the interview answer, plus the two lines a two-axis
  tree needs that a flat one does not: **a page's home is its mode**, and **a mode
  index gets grouped only once its list passes seven items.**

Both lines are conditional for the same reason 5a is byte-identical: the default path
must not acquire prose about an axis the builder declined.

Then **print the `AGENTS.md` snippet rather than writing it** — no skill in this
collection writes that file; `/ai-init` prints one too.

## Step 8: Self-audit

Check each item and report the result. Do not delegate any of this to the site
build: `onBrokenMarkdownLinks` defaults to `warn`, so a page carrying an unfilled
`{Concept 1}` builds cleanly and ships broken.

- **No `{` in any page you emitted.** Check every one.
- **Every relative link resolves** to a file or directory that exists.
- **No heading text is a placeholder** — no `{Title}`, no "TODO", no "TBD".
- **Every directory you created holds at least one page.** An empty one is the
  failure this skill's whole justification rests on not happening.
- **Every file you did not intend to touch is unchanged.**

When step 2b returned audiences, also check:

- **Every audience root holds at least one landing page and four seeded mode
  directories.** A root with modes and no landing page has no entry point; a root with
  a landing page and no modes is an empty structure by another name.
- **Every cross-mode link inside a root resolves within that root.** `../how-to/` from
  `user-docs/tutorial/index.md` must reach `user-docs/how-to/`, never
  `docs_path/how-to/`. A link that escapes its root sends a reader to the other
  audience's tree, and the site build will not catch it because the target exists.
- **No landing page contains a `{`.** The registration lines you printed do contain
  braces; they are printed output, not an emitted page, so the rule does not reach
  them — but it does reach every landing page, and that is the one seed shape written
  from the interview answer rather than copied.
- **No configuration file was modified.** `sidebars.ts`, `docusaurus.config.ts`, and
  their equivalents must be byte-identical after the run.

Fix anything that fails before reporting completion.

## Report

Close by naming what was created and what to do next:

- What was created, what was skipped because it already existed, and where.
- Whether a generator was detected, and if not, that the tree will not render
  until one is added.
- The `/ai-diataxis` invocation forms, so the next step is discoverable:
  - "Create a page: `/ai-diataxis \"<what you need to document>\"`"
  - "Assess a page: `/ai-diataxis <path>`"
  - "Survey the whole tree: `/ai-diataxis`"

## What This Skill Does NOT Cover

- **No page content beyond the index seeds.** It writes four index pages. Every
  other page comes from `/ai-diataxis` CREATE, one classified page at a time.
- **No static-site generator.** It detects one and reports its absence. It never
  writes a `docusaurus.config.ts`, an `mkdocs.yml`, or a `package.json`.
- **No functional-quality judgement.** Diátaxis "cannot address functional quality
  in documentation" (<https://diataxis.fr/quality/>). This skill creates
  structure; it does not assess whether any page is accurate, complete, or useful.
- **No reorganisation of an existing tree.** It never moves, renames, merges, or
  rewrites a page that is already there. A populated tree in another shape gets a
  report and a pointer at `/ai-diataxis` SURVEY.
- **No site-root router page.** `docs_path/index.md` is the page most likely to
  already exist in a target project. The four mode index pages cross-link to each
  other instead.
- **No `AGENTS.md`.** Printed as a snippet, never written.
- **No classification.** The four index pages' modes are known by construction.
  Nothing here runs the compass.

