Documentation
Every project documents itself the same way, so a developer or an AI agent can open any Activatus project and find what they need in the same place.
This is the docs framework from Launchpad. It is used for Launchpad itself and for every other project.
How it worksโ
| Part | What it is | Where it lives |
|---|---|---|
| The docs | Plain Markdown files. Every one is a Decision Doc | docs/ in the project root |
| The viewer | A Docusaurus site that displays those files | docsSite/ in the project root |
| The route | The docs appear at /docs in the running project | Switched on by the DOCS_URL environment variable |
The docs are written once, as Markdown, and read two ways:
- AI agents read the files in
docs/directly. No build, no server. - People browse them at
/docs, with a menu, search and page contents โ the same layout as this site.
๐ Every file is a Decision Docโ
Every file in docs/ is a Decision Doc. There is no separate decisions/ folder.
A design system is a decision. A scope is a decision. A database choice is a decision. Each doc states one decision and why it was made, so anyone โ or any agent โ can trace the work back to the reason for it, and never has to invent a product decision to unblock themselves.
- Tickets own the what. "Build GitHub authentication."
- Decision Docs own the why. "Developers are our audience and we must sync directly to their repositories."
See the Ontology for the terms.
๐ The foldersโ
Every project has the same folders. The folder is the menu group.
Reusable foldersโ
These are the same in every project:
| Folder | Holds decisions about | Files |
|---|---|---|
overview/ | What the project is and how to read its docs | what-is-it, how-it-works, writing-docs |
ai/ | Agents, models and what they may do | agent-harness, agents, architecture, context, model-routing, models, retrieval, tools |
architecture/ | How the system is built | authentication, backend, background-jobs, backups, caching, ci-cd, disaster-recovery, environments, frontend, hosting, observability, realtime, search, services, state-management, storage, system |
business/ | The customer and the money | buying-trigger, customer, customer-value, defensibility, growth, pricing, revenue-model, unit-economics |
data/ | What is stored and how | analytics, audit, database, indexing, migrations, model, retention, schema |
deployment/ | Getting work to production | approval, live-verification, process, rollback |
design/ | How it looks and behaves | design-system, errors, feedback, interactions, layout, navigation, principles, responsive |
development/ | How code is written and merged | branching, code-quality, coding-standards, commits, merge-strategy, process, pull-requests |
experience/ | What using it should feel like | accessibility, aha-moment, anti-experience, friction, outcomes, principles, retention, sharing |
pitch/ | Why the product should exist | alternatives, assumptions, audience, concept, differentiators, outcomes, problem, product-market-fit, success-criteria, validation, value-proposition, vision |
scope/ | What is in, out and later | core, exclusions, future, launch, post-launch, priorities, quality-bar |
security/ | Keeping it safe | audit, data-access, logging, privacy, secrets, threat-model |
testing/ | How it is tested | end-to-end, integration, regression, security, strategy, test-data, unit |
uat/ | Checking we built the right thing | checks, strategy |
users/ | Who uses it and what they may do | permissions, roles, user-types |
workflows/ | How work moves | assignment, bugfix, dependencies, deployment, development, planning, review, uat |
Product-specific foldersโ
Decisions that only make sense for this one product go in their own folders:
| Folder | Holds |
|---|---|
product/ | What this product is and how its main parts work. Starts with ontology.md: the product's words and how it speaks |
integrations/ | One file per outside service the product connects to |
user-flows/ | One file per User Flow |
| A folder for the product's own subject | For example, Launchpad has tickets/ |
Which folder?โ
Before placing a doc in a reusable folder, ask: would this topic make sense as a standard decision category for a completely different software product?
- Yes โ a reusable folder.
- No โ a product-specific folder.
Keep these pairs distinct:
- Authentication (who are you?) belongs in
architecture/authentication.md. Permissions (what are you allowed to do?) belong inusers/permissions.md. data/model.mdis the conceptual model,data/database.mdis the technology and strategy, anddata/schema.mdis the concrete structure.
Every file exists from the startโ
A new project starts with every reusable file already in place, each marked Status: Not started. Copy the doc templates.
- When a decision is made, write it into the matching file.
- Create a new file only when a topic has no home.
A Not started file is a visible gap: it shows a decision that has not been made yet.
Keep every folder and file, even ones that do not apply yet. They keep every project's docs laid out the same way, and a small project such as a one-page site grows into them. Never delete one to tidy the menu.
Decision Docs belong to the personโ
Confirm with the person before creating, changing or deleting a Decision Doc, including deleting a folder. A decision is theirs to make, not the agent's. The exception is a project whose AGENTS.md names an agent that manages the docs, such as a planning agent: that agent follows its own instructions.
๐ The doc formatโ
Every doc has the same shape:
# <Group> โ <Menu item>
> One line: what this doc decides.
**Status:** Not started | Under evaluation | Current plan | Decided ยท **Updated:** YYYY-MM-DD
## Decision
## Why
## Details (optional)
## Alternatives considered (optional)
## Current implementation (only when the code differs)
## Related
## Retro Feedback (added as tasks complete)
Statusโ
| Status | Means |
|---|---|
| Not started | A template waiting for its first decision |
| Under evaluation | Not decided. The options are recorded |
| Current plan | The direction we are working to. It may change |
| Decided | An intentional current decision. Change it only with a Decision Doc update |
Sectionsโ
| Section | Holds |
|---|---|
Decision | What was decided |
Why | The reasons |
Details | Anything needed to act on the decision |
Alternatives considered | What was rejected, and why |
Current implementation | Only when the code differs from the decision: describe the gap |
Related | Links to related docs |
Retro Feedback | What went well and what did not, added as tasks linked to this doc are completed |
A doc states the decision, not the code. When the code does not match yet, the gap goes under Current implementation.
When a decision changesโ
Update the doc, change the Updated date, and add a ## History entry: what changed, why, when, and which work was affected. Keep the original decision and its reason in the history.
The Updated date tracks the decision, not the file. Moving, renaming, reformatting or converting a doc to this format, with no decision changed, leaves the date as it is.
๐งญ One file, one menu item, one routeโ
The docs menu is built straight from the docs/ folder, so every doc is in the menu and nothing else is.
| Rule | Example |
|---|---|
| The folder is the menu group | scope/ shows as Scope |
The title after the โ is the menu item | # Scope โ Future shows as Future |
| The file name is that title in kebab-case | # Scope โ Future lives in scope/future.md |
The route is the folder plus the file name, without .md | scope/future.md is served at /docs/scope/future |
- Overview comes first in the menu. Every other group is in alphabetical order, and items are alphabetical within their group.
- Link between docs with relative
.mdpaths โ[Future](../scope/future.md). The link works in the file and on the site. - Folder and file names are kebab-case, because they become the route. See Naming Conventions.
The viewer does this automatically. There is no menu file to maintain.
โ๏ธ Rules for writingโ
- Use the Ontology. Use its terms for code, and the project's own ontology for product words.
- One decision per file.
- Plain Markdown (
.md). No JSX or imports, so every file reads the same for an agent as it does on the page. - One
# Headingper file, at the top, in the form# Group โ Menu item. - Draw diagrams with Mermaid in a
```mermaidcode block, so the diagram is text and stays in the file. - Write for someone who has never seen the project. Full sentences, full English words, no shorthand.
Not finished until the docs are updatedโ
A change is not finished until the docs match it. If a change makes a doc wrong, the doc is fixed in the same change โ the same rule as test files.
This applies to everyone writing code, including AI agents. An agent that changes how something works updates the Decision Doc that describes it.
๐ The /docs routeโ
The docs appear at /docs inside the running project โ http://localhost:3000/docs โ in the same layout as this site.
They are switched on by one environment variable:
DOCS_URL | What happens at /docs |
|---|---|
Set (http://localhost:3001) | The docs are shown |
| Not set | 404 โ the route does not exist |
โ Never in productionโ
DOCS_URL is never set in production. With it unset, the project has no /docs route at all, so internal docs cannot be reached on a live site.
- Set it in
.env.localfor local development. - Set it on a staging or preview environment only if the team wants the docs there.
- Do not add it to the production environment.
The docs site also sets noIndex, so search engines are told not to index it wherever it is running.
What goes in Gitโ
The docs are committed. They are not published. Committing a file to the repository and serving it on the live site are two different things.
| Item | In Git? | Why |
|---|---|---|
docs/ | โ Committed | It is the team's shared record. Developers and AI agents on every machine need it, and it changes in the same pull request as the code |
docsSite/ config files | โ Committed | So everyone gets the same viewer |
docsSite/node_modules/, docsSite/build/, docsSite/.docusaurus/ | โ Ignored | Installed and generated files. The docsSite/.gitignore from the template covers them |
.env.local (holds DOCS_URL) | โ Ignored | Local settings are never committed |
Never add docs/ to .gitignore. Ignored docs exist on one machine only: the rest of the team, and every agent working from a fresh copy of the repo, would have none.
Nothing in docs/ is shipped with the app. The build only includes files the app imports, and the app never imports from docs/.
Anyone who can read the repository can read its docs. Keep internal projects in a private repository.
How the route is wiredโ
The project's next.config.mjs forwards /docs to the docs site, but only when DOCS_URL is set:
const DOCS_URL = process.env.DOCS_URL;
/**
@type {import("next").NextConfig}
*/
const nextConfig = {
async rewrites() {
// The docs are only served when DOCS_URL is set. It is never set in production.
if (!DOCS_URL) {
return [];
}
return [
{ source: "/docs", destination: `${DOCS_URL}/docs/` },
{
source: "/docs/:path*",
destination: `${DOCS_URL}/docs/:path*`,
},
];
},
};
export default nextConfig;
๐ Converting existing docsโ
How to turn a project's existing documentation into Decision Docs. Every word is kept: converting changes where things live and how they are laid out, never what they say. Confirm the plan with the person before starting.
Outside material, such as client briefsโ
A brief says what to build rather than recording a decision, but it is still a decision: to build what the brief says.
- Give the product its own folder, such as
docs/homepage/, with one doc per part of the product. - Decision: "Build it as the brief below says."
- Why: the client's reason, and which brief wins where two disagree.
- Details: the brief's full text, unchanged.
- A superseded brief goes under
## History, marked "Reference only". - The table of which brief wins goes in
scope/core.md.
Build decisions made along the wayโ
One decision per file. A decision made while building a part, such as "the hero cards become the rail's cards", gets its own doc beside that part's doc, in the same product folder. It is never folded into the part's doc.
Headingsโ
A doc has one # heading, its title. Push every heading in the old content down by the smallest step that frees #: if the old doc's top level is #, every heading moves down one level. Skip headings inside code blocks. If that pushes any heading past ######, split the doc into one doc per top-level part instead. The site's menu on the right shows levels 2 and 3 only, so keep the important structure there.
Imagesโ
Images go in docs/assets/, in a folder per product area, such as docs/assets/homepage/. Link each image from the doc that uses it, with a relative path. Refer to a folder of images as a code path, docs/assets/homepage/, never a link: the docs site cannot open a folder, so the link breaks the build.
Old viewer leftoversโ
Delete every _category_.json, the sidebar_position, sidebar_label, slug, status and lastReviewed front matter, and docs/index.md once its content has moved to overview/.
The Updated dateโ
Converting a doc does not change its decision, so the Updated date stays as it was. Use the date of the last real decision, from the old doc or the git history.
๐ Setting it upโ
-
Copy the docs. Copy the
docs/templates into the project'sdocs/folder. Converting docs from version 2 or earlier? Delete the old viewer's leftovers: every_category_.json, thesidebar_position,sidebar_label,slug,statusandlastReviewedfront matter, anddocs/index.mdonce its content has moved tooverview/. Renameoverview/what-is-it.mdafter the project (what-is-launchpad.md), update its title, and update the link to it inoverview/writing-docs.md. The docs build fails on a broken link. -
Copy the viewer. Copy the
docsSite/template into the project root. Renamepackage.json.txttopackage.jsonandgitignore.txtto.gitignore, setPROJECT_NAMEindocusaurus.config.mjs, and point the home redirect insrc/pages/index.tsxat the renamed overview file. -
Add the route. Add the rewrite above to
next.config.mjs. -
Add the scripts to the project's
package.json:{"scripts": {"docs:install": "pnpm --dir docsSite install","docs:dev": "pnpm --dir docsSite start","docs:build": "pnpm --dir docsSite build"}} -
Set the variable in
.env.local:DOCS_URL=http://localhost:3001 -
Run it:
pnpm docs:install # Oncepnpm docs:dev # Starts the docs site on port 3001pnpm dev # Starts the project on port 3000Open
http://localhost:3000/docs. -
Ask the person to review
docs/product/ontology.mdbefore work starts: the product's words and how it speaks. Every agent reads it, so a wrong word spreads. Tell them to ask their AI to make any changes.
docspnpm docs is a built-in pnpm command, so a script called docs never runs. Use docs:dev.
๐ค For AI agentsโ
- Read
docs/before starting work. Start with the threeoverview/docs, then the docs for the area being changed. - Read the files directly. Do not start the docs site to read them.
- Check the Status.
Decidedis settled.Current planmay change.Under evaluationandNot startedare not decisions โ do not treat them as one, and do not invent one. Ask. - Update the docs in the same change as the code, and change the Updated date.
- Record a check only after it has run. Never write a URL, commit, date or "passed" for a check that has not happened yet. Write what was decided, and add the result once it exists.
- Write into the matching file. Create a new file only when a topic has no home, in kebab-case, using the doc format.
- Do not edit anything in
docsSite/unless the task is about the docs viewer itself.