# docs-autogen

On-demand regeneration of `README.AUTOGEN.md` companion files for every
package under `ts/packages/**` in the TypeAgent monorepo.

This package implements the workflow described in
[`ts/docs/architecture/doc-autogen.md`](../../docs/architecture/doc-autogen.md).
It is intended to be invoked manually from CI via `workflow_dispatch`
(no schedule) and exposes a CLI (`docs-autogen`) for local invocation.

> **Important:** `docs-autogen` writes to a parallel
> `README.AUTOGEN.md` file alongside each package's hand-written
> `README.md` and **never modifies `README.md`**. The hand-written
> README is treated as authoritative source material — its content is
> read on every run and forwarded to the LLM as context the AI-authored
> documentation should mirror and extend, never overwrite.
>
> This README itself is hand-written and **not** regenerated by
> `docs-autogen` — the generator skips its own package and anything
> outside `ts/packages/**`.

## What it produces

For each eligible package, `docs-autogen` writes a `README.AUTOGEN.md`
file at the package root with this structure:

1. Copyright header (markdown comments).
2. `<!-- AUTOGEN:DOCS:START -->` marker.
3. Content hash + `SOURCE` comment pointing back at `./README.md`.
4. `# <pkg-name> — AI-generated documentation` H1 title.
5. AI-authored documentation banner.
6. AI-authored multi-section body (Overview / What it does / Key Files
   / How to extend, plus optional sections). Validated for
   length, tone, link integrity, and required sections.
7. Deterministic `## Reference` appendix: entry points, dependencies,
   used-by graph, files of interest, agent surface, and a per-action
   reference table for agent packages — all computed from
   `package.json`, `src/`, and the workspace graph at the commit
   recorded in the staleness footer.
8. Staleness footer (commit SHA + ISO date + verify hint).
9. `<!-- AUTOGEN:DOCS:END -->` marker.

Regeneration is content-hash gated; packages whose inputs are
unchanged are skipped, and packages whose new file differs only in the
staleness footer/hash are also skipped so repeated dispatches don't
churn unchanged docs.

## Usage (local)

After `pnpm install` and `pnpm --filter @typeagent/docs-autogen build`:

```bash
# Plan-only (default): print which packages would be regenerated.
pnpm docs:generate:dry

# Regenerate README.AUTOGEN.md for every changed package and write the
# new content to disk (placeholder body — no LLM call). Useful for
# refreshing the deterministic Reference section without spending tokens.
pnpm docs:generate

# Same, plus author the documentation body via Azure OpenAI (requires
# AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_API_KEY in ts/.env).
pnpm docs:generate:llm

# Spot-check that every link in every package's README.AUTOGEN.md still
# resolves on disk.
pnpm docs:verify-links
```

The CLI accepts more granular flags:

```bash
# Regenerate one package only. The `-agent` suffix on agent packages
# is optional; both `--package list-agent` and `--package list` resolve.
node tools/docsAutogen/bin/docs-autogen.cjs --package list --render --write --llm

# Diff against an explicit ref instead of the watermark.
node tools/docsAutogen/bin/docs-autogen.cjs --since main --render --write

# Dry-run preview without touching disk.
node tools/docsAutogen/bin/docs-autogen.cjs --package list --render --write --dry-run

# JSON output for tool-driven consumers.
node tools/docsAutogen/bin/docs-autogen.cjs --all --render --json > /tmp/plan.json

# Cap how many packages a single run touches (default 25).
node tools/docsAutogen/bin/docs-autogen.cjs --all --render --write --max-packages 5
```

> The `bin/docs-autogen.cjs` shim is a thin launcher that silences a
> Node 24 deprecation warning from `simple-git` and filters a known
> Windows libuv shutdown-race assertion from stderr. The underlying
> CLI is still `dist/cli.js` and accepts identical flags if you need
> to invoke it directly — the launcher sets `DOCS_AUTOGEN_LAUNCHED=1`
> so the CLI can suppress the launcher tip when invoked correctly.
>
> **Known limitation (Windows + Node 24, `--llm` only):** the libuv
> shutdown bug (`STATUS_STACK_BUFFER_OVERRUN` / exit code
> `-1073740791`) fires from inside `aiclient`'s dependency tree
> _after_ a successful LLM run completes. The launcher hides the
> stderr text and rewrites the abnormal exit code to `0`; Node 22 is
> the repo's documented minimum and is not affected, and CI runs on
> Linux and is not affected. Treat the run as successful if every
> per-package `write=...` line shows `wrote`, `unchanged`, or
> `footer-only` — those are emitted before exit, so any real failure
> would be visible there.

`--render` without `--write` prints the assembled `README.AUTOGEN.md`
contents to stdout so you can inspect what would be written. `--write`
requires `--render`. Every link inside the generated file is validated
against on-disk paths before the file is written; broken links produce
a `broken-links` verdict and the file is left untouched.

## First-run cleanup

Earlier prototypes embedded the AUTOGEN region directly inside each
package's `README.md` between
`<!-- AUTOGEN:DOCS:START -->` / `<!-- AUTOGEN:DOCS:END -->` markers.
That has been removed in favour of the parallel `README.AUTOGEN.md`
file. If you find a `README.md` that still contains those markers
(e.g. on a stale branch), splice the marker block out by hand or
restore the file from `main`. The new generator does not touch
`README.md` and will silently leave such legacy blocks in place
otherwise.

`gatherPackageInputs` will fall back to reading a legacy AUTOGEN block
from `README.md` if no `README.AUTOGEN.md` exists yet — purely so the
first regeneration after the migration can refine prior LLM output
instead of starting from scratch.

## Operations

### CI workflow

The on-demand GitHub Action lives at
[`.github/workflows/docs-generate.yml`](../../../.github/workflows/docs-generate.yml).
It is **not** scheduled — runs are triggered manually via
`workflow_dispatch` with the same flags the CLI exposes. The job is
bound to the `development-fork` GitHub environment (the same
environment used by `smoke-tests.yml` and `build-docker-container.yml`)
so federated-credential exchange against the existing build-pipeline
Entra App registration succeeds and `getKeys.mjs` can read
`build-pipeline-kv` for Azure OpenAI credentials.

> **First-time pipeline setup** — installing the GitHub App,
> provisioning secrets and variables, and validating the first run
> — is covered in
> [`ts/docs/architecture/doc-autogen-setup.md`](../../docs/architecture/doc-autogen-setup.md).
> The summary below is reference-only; do not use it as a substitute
> for the setup guide on a fresh repo.

Required repository configuration (provision once):

| Kind     | Name                       | Purpose                                 |
| -------- | -------------------------- | --------------------------------------- |
| variable | `DOCS_BOT_APP_ID`          | GitHub App that opens the generated PR  |
| secret   | `DOCS_BOT_APP_PRIVATE_KEY` | Private key for the same GitHub App     |
| secret   | `AZURE_OPENAI_ENDPOINT`    | Azure OpenAI endpoint URL               |
| secret   | `AZURE_OPENAI_API_KEY`     | Azure OpenAI key (or wire OIDC instead) |

The GitHub App needs `contents: write` and `pull-requests: write` on
this repo. Until those are provisioned the workflow will run but fail
at the "Generate GitHub App token" step — that's safe (it cannot
modify anything before that step).

### Triggering manually

From the GitHub UI: **Actions → docs-generate → Run workflow**. The
dispatch form mirrors the CLI flags:

- `dry-run` — analyse and render only, never write or open a PR.
- `packages` — comma-separated list to override change detection.
- `since` — git ref to diff against, overriding the watermark.
- `llm` — toggle the AI authoring (default on; off emits placeholder
  documentation alongside the deterministic Reference).
- `max-packages` — per-run cap (default 25).

The workflow never advances the `docs-bot/last-run` watermark — there
is no scheduled run to protect against — so any dispatch is safely
idempotent against the operator's chosen `since` baseline.

### Resetting the watermark

The watermark is a lightweight git tag pointing at the SHA of the
commit a prior run was generated against. The workflow no longer
auto-advances it; operators advance, reset, or delete it by hand to
control the default diff baseline used when `since` is left blank:

```bash
# Inspect the current watermark.
git fetch origin --tags
git rev-parse refs/tags/docs-bot/last-run

# Force the watermark to a specific commit (e.g. force a full re-sweep).
git tag -f docs-bot/last-run <sha>
git push origin docs-bot/last-run --force

# Delete the watermark entirely (subsequent dispatches that omit
# `since` will fall back to "regenerate everything"; supply `since`
# explicitly to avoid that).
git tag -d docs-bot/last-run
git push origin :refs/tags/docs-bot/last-run
```

### First-run bootstrap

If the watermark tag does not exist, dispatches that leave `since`
blank have no diff baseline. Either tag a known-good SHA on `main`
manually, or use `workflow_dispatch` with `since: main` (or any other
ref) to seed.

### Cost expectations

Placeholder runs (`--llm` off) make zero LLM calls and are cheap
enough to run on every commit if needed. With `--llm` on, each
package costs roughly one `gpt-4`-class chat completion sized at
~6–10k input tokens (the documentation prompt forwards the
hand-written `README.md`, source samples, action list, and the
deterministic Reference) and ~1000–1500 output tokens, plus one retry
on validation failure. The default `--max-packages 25` cap bounds the
worst-case at ~50 calls per run.

### Opting a package out

Not yet implemented in v1. If a package should not be regenerated,
delete its `README.AUTOGEN.md` and add it to a future ignore list
when one is built. The hand-written `README.md` is never affected
either way. Explicit opt-out (`docs-autogen-opt-out: true` in
`package.json`) is tracked in the design doc.

## Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
trademarks or logos is subject to and must follow
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
Any use of third-party trademarks or logos are subject to those third-party's policies.
