# Technical Documentation: mindfold-ai/Trellis

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/mindfold-ai/Trellis)

### Overview (README.md)

<p align="center">
<picture>
<source srcset="assets/trellis.png" media="(prefers-color-scheme: dark)">
<source srcset="assets/trellis.png" media="(prefers-color-scheme: light)">
<img src="assets/trellis.png" alt="Trellis Logo" width="500" style="image-rendering: -webkit-optimize-contrast; image-rendering: crisp-edges;">
</picture>
</p>

<p align="center">
<strong>An out-of-the-box engineering framework for AI coding.</strong><br/>
<sub>AI writes code fast, but every session it starts from scratch — no memory of your project, your conventions, or your team's requirements. Trellis persists specs, tasks, and memory into your repo, so any coding agent works to your engineering standards.</sub>
</p>

<p align="center">
<a href="./README_CN.md">简体中文</a> •
<a href="https://docs.trytrellis.app/">Docs</a> •
<a href="https://docs.trytrellis.app/start/install-and-first-task">Quick Start</a> •
<a href="https://docs.trytrellis.app/advanced/multi-platform">Supported Platforms</a> •
<a href="https://docs.trytrellis.app/start/real-world-scenarios">Use Cases</a>
</p>

<p align="center">
<a href="https://www.npmjs.com/package/@mindfoldhq/trellis"><img src="https://img.shields.io/npm/v/@mindfoldhq/trellis.svg?style=flat-square&color=2563eb" alt="npm version" /></a>
<a href="https://www.npmjs.com/package/@mindfoldhq/trellis"><img src="https://img.shields.io/npm/dw/@mindfoldhq/trellis?style=flat-square&color=cb3837&label=downloads" alt="npm downloads" /></a>
<a href="https://github.com/mindfold-ai/Trellis/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-16a34a.svg?style=flat-square" alt="license" /></a>
<a href="https://github.com/mindfold-ai/Trellis/stargazers"><img src="https://img.shields.io/github/stars/mindfold-ai/Trellis?style=flat-square&color=eab308" alt="stars" /></a>
<a href="https://docs.trytrellis.app/"><img src="https://img.shields.io/badge/docs-trytrellis.app-0f766e?style=flat-square" alt="docs" /></a>
<a href="https://discord.com/invite/tWcCZ3aRHc"><img src="https://img.shields.io/badge/Discord-Join-5865F2?style=flat-square&logo=discord&logoColor=white" alt="Discord" /></a>
<a href="https://github.com/mindfold-ai/Trellis/issues"><img src="https://img.shields.io/github/issues/mindfold-ai/Trellis?style=flat-square&color=e67e22" alt="open issues" /></a>
<a href="https://github.com/mindfold-ai/Trellis/pulls"><img src="https://img.shields.io/github/issues-pr/mindfold-ai/Trellis?style=flat-square&color=9b59b6" alt="open PRs" /></a>
<a href="https://deepwiki.com/mindfold-ai/Trellis"><img src="https://img.shields.io/badge/Ask-DeepWiki-blue?style=flat-square" alt="Ask DeepWiki" /></a>
<a href="https://chatgpt.com/?q=Explain+the+project+mindfold-ai/Trellis+on+GitHub"><img src="https://img.shields.io/badge/Ask-ChatGPT-74aa9c?style=flat-square&logo=openai&logoColor=white" alt="Ask ChatGPT" /></a>
</p>

<p align="center">
<img src="assets/trellis-demo.gif" alt="Trellis workflow demo" width="100%">
</p>

## Why Trellis?

| Capability | What it changes |
| --- | --- |
| **Auto-injected specs** | Write conventions once in `.trellis/spec/`, then let Trellis inject the relevant context into each session instead of repeating yourself. |
| **Task-centered workflow** | Keep PRDs, implementation context, review context, and task status in `.trellis/tasks/` so AI work stays structured. |
| **Project memory** | Journals in `.trellis/workspace/` preserve what happened last time, so each new session starts with real context. |
| **Team-shared standards** | Specs live in the repo, so one person's hard-won workflow or rule can benefit the whole team. |
| **Multi-platform setup** | Bring the same Trellis structure to 22 AI coding platforms instead of rebuilding your workflow per tool. |

## Prerequisites:

- **Node.js** >= 18
- **Python** >= 3.9

## Quick Start

```bash
# 1. Install Trellis
npm install @mindfoldhq/trellis@latest

# 2. Initialize in your repo
trellis init -u your-name

# 3. Or initialize with the platforms you actually use
trellis init --cursor --opencode --codex -u your-name
```

See the [Quick Start](https://docs.trytrellis.app/start/install-and-first-task) and [Supported Platforms](https://docs.trytrellis.app/advanced/multi-platform) guides for setup details.

## How to Use

The workflow is simple:

1. **Describe what you want** in natural language.
2. **Brainstorm** with the AI one question at a time until the PRD is clear, then implementation begins.
3. **Let it run** — the AI calls Trellis Implement and auto-checks the result against specs, lint, type-check, and tests.
4. **Type `/trellis:finish-work`** when the work is done or the session context fills up. Trellis archives the task and updates journals.

## How It Works

Trellis runs a 4-phase loop with auto-invoked skills and sub-agents:

1. **Plan** — `trellis-brainstorm` walks through requirements one question at a time and writes `prd.md`. Research-heavy items go to a `trellis-research` sub-agent. The result is curated specs + research files referenced from `implement.jsonl` / `check.jsonl`.
2. **Implement** — a `trellis-implement` sub-agent writes code from the PRD with the curated context auto-injected, no git commit.
3. **Verify** — a `trellis-check` sub-agent reviews the diff against specs and runs lint, type-check, and tests, self-fixing where it can.
4. **Finish** — a final check runs, then `trellis-update-spec` promotes new learnings back into `.trellis/spec/` so the next session starts smarter.

## Resources

| Need                            | Link                                                                           |
| ------------------------------- | ------------------------------------------------------------------------------ |
| Install Trellis in a repo       | [Quick Start](https://docs.trytrellis.app/start/install-and-first-task)        |
| Understand platform differences | [Supported Platforms](https://docs.trytrellis.app/advanced/multi-platform)     |
| See the workflow in practice    | [Real-World Scenarios](https://docs.trytrellis.app/start/real-world-scenarios) |
| Start from spec templates       | [Spec Templates](https://docs.trytrellis.app/templates/specs-index)            |
| Track releases                  | [Changelog](https://docs.trytrellis.app/changelog)                             |

## FAQ

<details>
<summary><strong>How is Trellis different from <code>CLAUDE.md</code>, <code>AGENTS.md</code>, or <code>.cursorrules</code>?</strong></summary>

Those files are useful entry points, but they tend to become monolithic. Trellis adds scoped specs, task PRDs, workflow gates, workspace memory, and platform-aware generated files around them.

</details>

<details>
<summary><strong>Is Trellis only for Claude Code?</strong></summary>

No. Trellis is a project layer that works across multiple coding agents and IDEs.

</details>

<details>
<summary><strong>Is Trellis for solo developers or teams?</strong></summary>

Both. Solo developers use it for memory and repeatable workflow. Teams get the larger benefit: shared standards, task boundaries, reviewable context, and platform portability.

</details>

<details>
<summary><strong>Do I have to write every spec file manually?</strong></summary>

No. Many teams start by letting AI draft specs from existing code and then tighten the important parts by hand. Trellis works best when you keep the high-signal rules explicit and versioned.

</details>

<details>
<summary><strong>Can teams use this without constant conflicts?</strong></summary>

Yes. Personal workspace journals stay separate per developer, while shared specs and tasks stay in the repo where they can be reviewed and improved like any other project artifact.

</details>

<details>
<summary><strong>Can I temporarily compare a project with and without Trellis?</strong></summary>

Yes. `trellis ablate` temporarily removes all supported project-owned Trellis
surfaces after creating a verified recovery transaction outside the project.
Start a fresh agent session for the comparison, then run `trellis restore` to
recover the exact prior state. Use `--dry-run` to preview either operation.
The private recovery transaction includes exact `.trellis` task, spec, and
workspace bytes, which may contain user-authored sensitive text, and is kept
until restore verifies successfully.

This is different from `trellis uninstall` (permanent removal) and
`TRELLIS_HOOKS=0` (hooks only). Ablation does not launch agents, manage
worktrees, hide Git changes, or remove the global CLI, channel logs, or host
transcripts. If a managed path changes while ablated, restore refuses all
writes until the conflict is resolved.

</details>

## Star History

[](https://star-history.dera.page/#mindfold-ai/Trellis&Date)

## Community & Resources

- [Official Docs](https://docs.trytrellis.app/)
- [GitHub Issues](https://github.com/mindfold-ai/Trellis/issues)
- [Discord](https://discord.com/invite/tWcCZ3aRHc)
- [Tech Blog](https://docs.trytrellis.app/blog)

<p align="center">
<a href="https://github.com/mindfold-ai/Trellis">Official Repository</a> •
<a href="https://github.com/mindfold-ai/Trellis/blob/main/LICENSE">AGPL-3.0 License</a> •
Built by <a href="https://github.com/mindfold-ai">Mindfold</a>
</p>

---

### .Trellis Spec Docs Site Docs Index (`.trellis/spec/docs-site/docs/index.md`)

# Mintlify Documentation Guidelines

> Best practices for writing and maintaining documentation in this Mintlify project.

---

## Overview

This project uses **Mintlify** as the documentation platform. All content is written in MDX (Markdown + JSX) and configured via `docs.json`.

---

## Guidelines Index

| Guide                                           | Description                              | Status |
| ----------------------------------------------- | ---------------------------------------- | ------ |
| [Directory Structure](./directory-structure.md) | File organization and naming conventions | Ready  |
| [MDX Guidelines](./mdx-guidelines.md)           | MDX syntax, frontmatter, components      | Ready  |
| [Config Guidelines](./config-guidelines.md)     | docs.json configuration patterns         | Ready  |
| [Plugin Guidelines](./plugin-guidelines.md)     | Claude Code plugin manifest patterns     | Ready  |
| [Style Guide](./style-guide.md)                 | Writing style + changelog/release-notes voice | Ready  |
| [ASCII-Art Alignment](./ascii-art-alignment.md) | Box-drawing & CJK alignment in diagrams  | Ready  |
| [Sync on Change](./sync-on-change.md)           | Which docs-site pages to update when Trellis workflow / platforms / commands / skills change | Ready  |
| [Release Lifecycle](./release-lifecycle.md)     | `docs-site/scripts/` lifecycle (release-only / +beta / +rc), when and how to use them        | Ready  |

---

## Quick Reference

### Local Development

```bash
# Start dev server
mintlify dev

# Custom port
mintlify dev --port 3333
```

### File Types

| Extension   | Purpose                                    |
| ----------- | ------------------------------------------ |
| `.mdx`      | Documentation pages                        |
| `.json`     | Configuration (docs.json) or OpenAPI specs |
| `.svg/.png` | Images and logos                           |

### Key Files

| File             | Purpose            |
| ---------------- | ------------------ |
| `docs.json`      | Main configuration |
| `index.mdx`      | Homepage           |
| `snippets/*.mdx` | Reusable content   |

---

## Deployment

- **Preview**: Automatic on PR creation
- **Production**: Push to `main` branch triggers deploy

---

**Language**: All documentation should be written in **English** unless specified otherwise.

---

### .Trellis Spec Docs Site Docs Ascii Art Alignment (`.trellis/spec/docs-site/docs/ascii-art-alignment.md`)

# ASCII-Art Diagram Alignment in Mintlify

> How to make box-drawing diagrams render correctly in browser, especially with CJK text.

---

## Problem Summary

ASCII-art diagrams using box-drawing characters (`─│┌┐└┘┬┤├┼`) break in the browser for two reasons:

| Problem                            | Root Cause                                                                               | Affected                |
| ---------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------- |
| Box-drawing chars wider than ASCII | JetBrains Mono (Mintlify default) renders `─│┌` at ~1.8× ASCII width                     | All languages           |
| CJK chars not exactly 2× ASCII     | Browser CJK fallback fonts render Chinese at ~1.7× ASCII instead of terminal-standard 2× | Chinese/Japanese/Korean |

---

## Solution 1: English-Only Diagrams (Font Override)

For diagrams with only ASCII text, switching the code block font to Menlo fixes everything — Menlo renders box-drawing chars at exactly 1× ASCII width.

**CSS in `styles.css`:**

```css
pre code {
  font-family: Menlo, Monaco, 'Courier New', monospace !important;
}
```

Use standard markdown code blocks (` ``` `). No other changes needed.

---

## Solution 2: Chinese CJK Diagrams (2ch Inline-Block)

For diagrams mixing Chinese text with box-drawing borders, **no font** can guarantee CJK = 2× ASCII in browsers. The solution is CSS-forced widths.

### Technique

1. Wrap each CJK character in `<b>` tags
2. CSS forces `<b>` to `display:inline-block;width:2ch` — exactly 2 monospace columns
3. Use `dangerouslySetInnerHTML` to bypass MDX parsing issues

**CSS in `styles.css`:**

```css
pre.cjk-diagram {
  display: block !important; /* Override Mintlify's display:flex on <pre> */
  padding: 14px 16px;
  border-radius: 16px;
  font-size: 14px;
  line-height: 24px;
  font-family: Menlo, Monaco, 'Courier New', monospace;
  overflow-x: auto;
  white-space: pre;
  margin: 16px 0;
  background: #f8f8f8;
  color: #1e1e1e;
}

.dark pre.cjk-diagram {
  background: #1e1e1e;
  color: #d4d4d4;
}

pre.cjk-diagram b {
  display: inline-block;
  width: 2ch;
  text-align: center;
  font-weight: normal;
}
```

**MDX usage:**

```mdx
<pre
  className="cjk-diagram"
  dangerouslySetInnerHTML={{
    __html: `┌──────────────┐
│  <b>用</b><b>户</b>          │
└──────────────┘`,
  }}
/>
```
/* Detailed source-code truncated for AI context efficiency. */
````
Need ASCII-art diagram in docs?
├── English only?
│   └── Use standard ``` code block + Menlo font override ✓
└── Contains CJK text?
    └── Use <pre class="cjk-diagram"> + dangerouslySetInnerHTML
        + wrap each CJK char in <b> tags ✓
````

---

### .Trellis Spec Docs Site Docs Config Guidelines (`.trellis/spec/docs-site/docs/config-guidelines.md`)

# Configuration Guidelines

> docs.json configuration patterns and conventions.

---

## File Location

Main configuration file: `docs.json` (project root)

---

## Schema Reference

```json
{
  "$schema": "https://mintlify.com/docs.json"
}
```

Always include the schema for editor autocomplete.

---

## Core Configuration

### Theme and Branding

```json
{
  "theme": "mint",
  "name": "Project Name",
  "colors": {
    "primary": "#16A34A",
    "light": "#07C983",
    "dark": "#15803D"
  },
  "favicon": "/favicon.svg",
  "logo": {
    "light": "/logo/light.svg",
    "dark": "/logo/dark.svg"
  }
}
```

### Color Guidelines

| Color     | Purpose           | Format                |
| --------- | ----------------- | --------------------- |
| `primary` | Main brand color  | Hex (e.g., `#16A34A`) |
| `light`   | Light mode accent | Hex                   |
| `dark`    | Dark mode accent  | Hex                   |

---

## Navigation

### Tab-Based Navigation

```json
{
  "navigation": {
    "tabs": [
      {
        "tab": "Guides",
        "groups": [
          {
            "group": "Getting Started",
            "pages": ["index", "quickstart", "development"]
          }
        ]
      },
      {
        "tab": "API Reference",
        "groups": [
          {
            "group": "Endpoints",
            "pages": ["api-reference/introduction"]
          }
        ]
      }
    ]
  }
}
```

### Group-Based Navigation

```json
{
  "navigation": {
    "groups": [
      {
        "group": "Getting Started",
        "pages": ["index", "quickstart"]
      },
      {
        "group": "Guides",
        "pages": ["essentials/settings", "essentials/navigation"]
      }
    ]
  }
}
```

### Page References

| Format           | Example                     |
| ---------------- | --------------------------- |
| Root page        | `"index"`                   |
| Nested page      | `"essentials/settings"`     |
| OpenAPI endpoint | `"openapi.json GET /users"` |

### Collapsible Nested Groups

To make a navigation group collapsible (collapsed by default), use the `expanded` property on **nested groups** (groups within groups):

```json
{
  "navigation": {
    "groups": [
      {
        "group": "Community",
        "pages": [
          "showcase/index",
          "contribute/index",
          {
            "group": "Blog",
            "expanded": false,
            "pages": ["blog/index", "blog/post-one", "blog/post-two"]
          }
        ]
      }
    ]
  }
}
```

> **Warning**: The `expanded` property **only works on nested groups** (groups within groups). Top-level groups are always expanded and cannot be collapsed. If you put `expanded: false` on a top-level group, it will be silently ignored.

**Common Mistake**: Trying to collapse a top-level group:

```json
// ❌ WRONG - This does NOT work
{
  "group": "Blog",
  "expanded": false, // Ignored! Top-level groups can't collapse
  "pages": ["blog/index", "blog/post-one"]
}
```

```json
// ✅ CORRECT - Nest it under a parent group
{
  "group": "Community",
  "pages": [
    "showcase/index",
    {
      "group": "Blog",
      "expanded": false, // Works! This is a nested group
      "pages": ["blog/index", "blog/post-one"]
    }
  ]
}
```

---

## Global Elements

### Anchors (Sidebar Links)

```json
{
  "navigation": {
    "global": {
      "anchors": [
        {
          "anchor": "Documentation",
          "href": "https://example.com/docs",
          "icon": "book-open-cover"
        },
        {
          "anchor": "GitHub",
          "href": "https://github.com/example",
          "icon": "github"
        }
      ]
    }
  }
}
```

### Navbar

```json
{
  "navbar": {
    "links": [
      {
        "label": "Support",
        "href": "mailto:support@example.com"
      }
    ],
    "primary": {
      "type": "button",
      "label": "Dashboard",
      "href": "https://dashboard.example.com"
    }
  }
}
```

### Footer

```json
{
  "footer": {
    "socials": {
      "x": "https://x.com/example",
      "github": "https://github.com/example",
      "linkedin": "https://linkedin.com/company/example"
    }
  }
}
```

---

## API Documentation

### OpenAPI Integration

```json
{
  "navigation": {
    "tabs": [
      {
        "tab": "API Reference",
        "groups": [
          {
            "group": "Endpoints",
            "openapi": "api-reference/openapi.json"
          }
        ]
      }
    ]
  }
}
```

---

## Contextual Options

Code block right-click menu options:

```json
{
  "contextual": {
    "options": ["copy", "view", "chatgpt", "claude", "perplexity", "mcp", "cursor", "vscode"]
  }
}
```

---

## Internationalization (i18n)

### Language-Based Navigation

For multi-language support, use `navigation.languages` instead of `navigation.tabs`:

```json
{
  "navigation": {
    "languages": [
      {
        "language": "en",
        "tabs": [
          {
            "tab": "Guides",
            "groups": [
              {
                "group": "Getting Started",
                "pages": ["index", "quickstart"]
              }
            ]
          }
        ]
      },
      {
        "language": "zh",
        "tabs": [
          {
            "tab": "指南",
            "groups": [
              {
                "group": "开始使用",
                "pages": ["zh/index", "zh/quickstart"]
              }
            ]
          }
        ]
      }
    ]
  }
}
```

### i18n File Structure

```
docs/
├── index.mdx           # English homepage
├── quickstart.mdx      # English quickstart
├── zh/
│   ├── index.mdx       # Chinese homepage
│   └── quickstart.mdx  # Chinese quickstart
└── docs.json           # Both languages configured
```

> **Important**: Each language needs its own complete navigation structure. Pages in `zh/` must be referenced as `"zh/pagename"` in the navigation.

### i18n Naming Conventions

Use consistent naming for common page types across languages:

| English      | Chinese    | Usage                            |
| ------------ | ---------- | -------------------------------- |
| `Overview`   | `概览`     | Index/landing pages for sections |
| `Guides`     | `指南`     | How-to documentation section     |
| `Quickstart` | `快速开始` | Getting started guides           |
| `FAQ`        | `常见问题` | Frequently asked questions       |

**Example frontmatter**:

```yaml
# English (templates/specs-index.mdx)
---
title: 'Overview'
description: 'Spec templates for common stacks'
---
# Chinese (zh/templates/specs-index.mdx)
---
title: '概览'
description: '常见技术栈的规范模板'
---
```

> **Rule**: Don't mix languages in titles. English pages use English titles, Chinese pages use Chinese titles.

### i18n for Content Sections (Blog, Changelog, etc.)

When a content section (like Blog) has language-specific posts, **separate the content by directory**:

```
docs/
├── blog/                        # English blog
│   ├── index.mdx                # Lists ONLY English posts
│   ├── post-one.mdx
│   └── post-two.mdx
├── zh/
│   └── blog/                    # Chinese blog
│       ├── index.mdx            # Lists ONLY Chinese posts
│       ├── post-one.mdx         # Same filename, different content
│       └── post-two.mdx
└── docs.json
```

**Navigation configuration**:

```json
{
  "navigation": {
    "languages": [
      {
        "language": "en",
        "groups": [
          {
            "group": "Blog",
            "pages": ["blog/index", "blog/post-one", "blog/post-two"]
          }
        ]
      },
      {
        "language": "zh",
        "groups": [
          {
            "group": "Blog",
            "pages": ["zh/blog/index", "zh/blog/post-one", "zh/blog/post-two"]
          }
        ]
      }
    ]
  }
}
```

> **Common Mistake**: Putting all blog posts (both languages) in one `blog/` folder and showing them all in both navigations. This clutters each language's view with posts they can't read.

**Key principle**: Each language's content section should be **self-contained** — its own directory, its own index, its own navigation entries.

---

## Custom Styling

### Override Default Styles

Create `styles.css` in project root to customize Mintlify appearance:

```css
/* Example: Hide language switcher flag icons */
img[src*='cloudfront.net/flags'] {
  display: none !important;
}

/* Example: Customize button styles */
button[aria-haspopup='menu'] > div:first-child {
  display: none !important;
}
```

> **Tip**: Use browser DevTools to inspect Mintlify elements and find the right selectors.

---

## Best Practices

### DO

- Include `$schema` for autocomplete
- Organize navigation logically (user journey)
- Use descriptive group names
- Keep tab count reasonable (2-4 tabs)

### DON'T

- Create deeply nested navigation
- Use inconsistent naming between pages and nav
- Forget to add new pages to navigation
- Mix different navigation patterns unnecessarily

---

## Checklist: Adding New Content

1. [ ] Create the `.mdx` file
2. [ ] Add frontmatter with title and description
3. [ ] Add page to appropriate group in `docs.json`
4. [ ] Verify navigation order makes sense
5. [ ] Test locally with `mintlify dev`

---

### .Trellis Spec Docs Site Docs Directory Structure (`.trellis/spec/docs-site/docs/directory-structure.md`)

# Directory Structure

> File organization and naming conventions for this Mintlify documentation project.

---

## ⚠️ Critical: Manual Navigation Update Required

**Mintlify does NOT auto-discover pages.** Every new page must be manually added to `docs.json`.

```json
// docs.json - Must update navigation when adding pages
{
  "navigation": {
    "languages": [
      {
        "language": "en",
        "groups": [
          {
            "group": "Spec Templates",
            "pages": [
              "templates/specs-index",
              "templates/specs-node", // ← Add new pages here
              "templates/specs-python"
            ]
          }
        ]
      },
      {
        "language": "zh",
        "groups": [
          // Same structure for Chinese
        ]
      }
    ]
  }
}
```

**Checklist for new pages:**

1. [ ] Create `.mdx` file
2. [ ] Add to English navigation in `docs.json`
3. [ ] Create Chinese version in `zh/` directory
4. [ ] Add to Chinese navigation in `docs.json`

---

## Project Structure

```
docs/
├── docs.json              # Main configuration
├── index.mdx              # Homepage
├── quickstart.mdx         # Quick start guide
├── development.mdx        # Development setup
│
├── essentials/            # Core documentation
│   ├── settings.mdx
│   ├── navigation.mdx
│   ├── markdown.mdx
│   ├── code.mdx
│   ├── images.mdx
│   └── reusable-snippets.mdx
│
├── api-reference/         # API documentation
│   ├── introduction.mdx
│   ├── openapi.json       # OpenAPI specification
│   └── endpoint/
│       ├── get.mdx
│       ├── create.mdx
│       ├── delete.mdx
│       └── webhook.mdx
│
├── ai-tools/              # AI tools guides
│   ├── cursor.mdx
│   ├── claude-code.mdx
│   └── devin.mdx
│
├── snippets/              # Reusable content fragments
│   └── snippet-intro.mdx
│
├── images/                # Image assets
│   └── *.png|jpg|gif
│
└── logo/                  # Brand assets
    ├── light.svg
    └── dark.svg
```

---

## Naming Conventions

### Files

| Type        | Convention       | Example               |
| ----------- | ---------------- | --------------------- |
| MDX pages   | `kebab-case.mdx` | `getting-started.mdx` |
| Directories | `kebab-case/`    | `api-reference/`      |
| Images      | `kebab-case.png` | `hero-image.png`      |
| Snippets    | `kebab-case.mdx` | `api-key-setup.mdx`   |

### Directory Organization

| Directory        | Purpose            | When to Use                             |
| ---------------- | ------------------ | --------------------------------------- |
| Root (`/`)       | Top-level pages    | Homepage, quickstart, main entry points |
| `essentials/`    | Core platform docs | Settings, navigation, markdown syntax   |
| `api-reference/` | API documentation  | Endpoints, OpenAPI specs                |
| `snippets/`      | Reusable content   | Content used in multiple pages          |
| `images/`        | Image assets       | Screenshots, diagrams                   |
| `logo/`          | Brand assets       | Light/dark mode logos                   |

---

## Rules

### DO

- Group related pages in directories
- Use descriptive, SEO-friendly file names
- Keep directory nesting shallow (max 2 levels)
- Place reusable content in `snippets/`

### DON'T

- Use underscores in file names (use hyphens)
- Create deeply nested directories
- Mix different content types in same directory
- Use spaces or special characters in names

---

## Internationalization (i18n) Structure

For bilingual documentation, follow this pattern:

```
docs/
├── index.mdx              # English homepage
├── quickstart.mdx         # English quickstart
├── guides/                # English guides
│   └── *.mdx
├── blog/                  # English blog (EN posts only)
│   ├── index.mdx          # Lists EN posts only
│   └── *.mdx
│
├── zh/                    # Chinese content root
│   ├── index.mdx          # Chinese homepage
│   ├── quickstart.mdx     # Chinese quickstart
│   ├── guides/            # Chinese guides
│   │   └── *.mdx
│   └── blog/              # Chinese blog (ZH posts only)
│       ├── index.mdx      # Lists ZH posts only
│       └── *.mdx
│
├── changelog.mdx          # Shared (no translation needed)
└── docs.json
```

### i18n Rules

| Content Type   | English Path       | Chinese Path                |
| -------------- | ------------------ | --------------------------- |
| Main pages     | `page.mdx`         | `zh/page.mdx`               |
| Section pages  | `section/page.mdx` | `zh/section/page.mdx`       |
| Blog posts     | `blog/post.mdx`    | `zh/blog/post.mdx`          |
| Shared content | `changelog.mdx`    | `changelog.mdx` (same file) |

### Common Mistake

**Don't**: Mix languages in one folder

```
blog/
├── post-en.mdx      # ❌ Clutters both language views
└── post-zh.mdx
```

**Do**: Separate by language directory

```
blog/
└── post.mdx         # ✅ English only
zh/blog/
└── post.mdx         # ✅ Chinese only
```

---

## Adding New Content

### New Page (Bilingual)

| Step | Action                   | File                                |
| ---- | ------------------------ | ----------------------------------- |
| 1    | Create English page      | `section/page.mdx`                  |
| 2    | Create Chinese page      | `zh/section/page.mdx`               |
| 3    | **Update EN navigation** | `docs.json` → `languages[0].groups` |
| 4    | **Update ZH navigation** | `docs.json` → `languages[1].groups` |
| 5    | Test locally             | `pnpm dev`                          |

> ⚠️ **Steps 3-4 are mandatory.** Pages won't appear in sidebar without navigation entries.

### New Section

1. Create new directory with descriptive name
2. Add pages inside the directory
3. Create a group in `docs.json` navigation (both EN and ZH)

### New Snippet

1. Create `.mdx` file in `snippets/`
2. Reference with `<Snippet file="filename.mdx" />`

---

### .Trellis Spec Docs Site Docs Mdx Guidelines (`.trellis/spec/docs-site/docs/mdx-guidelines.md`)

# MDX Guidelines

> MDX syntax, frontmatter, and component usage patterns.

---

## Frontmatter

Every MDX file must start with frontmatter:

```yaml
---
title: 'Page Title'
description: 'Brief description for SEO (150-160 characters)'
---
```

### Optional Frontmatter Fields

| Field          | Purpose                   | Example         |
| -------------- | ------------------------- | --------------- |
| `sidebarTitle` | Shorter title for sidebar | `"Quick Start"` |
| `icon`         | Navigation icon           | `"rocket"`      |
| `tag`          | Badge/label               | `"NEW"`         |
| `mode`         | Page mode                 | `"wide"`        |

### Example with All Fields

```yaml
---
title: 'Getting Started with the API'
description: 'Learn how to authenticate and make your first API call'
sidebarTitle: 'Getting Started'
icon: 'play'
tag: 'Updated'
---
```

---

## Components

### Card

Use for navigation links and feature highlights:

```mdx
<Card title="Quick Start" icon="rocket" href="/quickstart">
  Get up and running in 5 minutes.
</Card>
```

**Horizontal variant:**

```mdx
<Card title="Start Here" icon="rocket" href="/quickstart" horizontal>
  Follow our quickstart guide.
</Card>
```

### Columns

Use for multi-column layouts:

```mdx
<Columns cols={2}>
  <Card title="First" icon="star" href="/first">
    First card content.
  </Card>
  <Card title="Second" icon="star" href="/second">
    Second card content.
  </Card>
</Columns>
```

### Tabs

Use for alternative content views:

````mdx
<Tabs>
  <Tab title="npm">```bash npm install package-name ```</Tab>
  <Tab title="yarn">```bash yarn add package-name ```</Tab>
</Tabs>
````

### Accordion

Use for collapsible content:

```mdx
<AccordionGroup>
  <Accordion title="What is Mintlify?">Mintlify is a documentation platform.</Accordion>
  <Accordion title="How much does it cost?">
    Free tier available, Pro starts at $300/month.
  </Accordion>
</AccordionGroup>
```

### CodeGroup

Use for multi-language code examples:

````mdx
<CodeGroup>
```javascript Node.js
const response = await fetch('/api/users');
```

```python Python
response = requests.get('/api/users')
```

```bash cURL
curl https://api.example.com/users
```

</CodeGroup>
````

### Snippet

Use for reusable content:

```mdx
<Snippet file="api-key-setup.mdx" />
```

---

## Code Blocks

### Basic Syntax

````markdown
```language filename
code here
```
````

### With Filename

````markdown
```javascript app.js
const express = require('express');
const app = express();
```
````

### Supported Languages

Common: `javascript`, `typescript`, `python`, `bash`, `json`, `yaml`, `sql`, `go`, `rust`

---

## Callouts

### Note

```mdx
<Note>This is important information.</Note>
```

### Warning

```mdx
<Warning>Be careful with this action.</Warning>
```

### Info

```mdx
<Info>Additional context here.</Info>
```

### Tip

```mdx
<Tip>Helpful suggestion here.</Tip>
```

---

## Common Mistakes

### Nested Code Blocks in Templates

**Problem**: Using escaped backticks to show code block syntax renders broken:

```mdx


\`\`\`bash
npm install
\`\`\`
```

**Solution**: Use `<CodeGroup>` component instead:

````mdx


<CodeGroup>```bash Install npm install ```</CodeGroup>
````

### Duplicate Headings in Template Examples

**Problem**: Showing multiple template examples with same headings triggers MD024 lint error.

**Solution**: Add lint disable comment at file start:

```mdx
---
title: 'Templates'
---



## Template 1

### Project structure

...

## Template 2

### Project structure 

...
```

### Mixed Block/Inline JSX Closing Tag

**Symptom**: Whole page renders as `A parsing error occurred. Please contact the owner of this website.` The title also falls back to the file slug (e.g. "Ch12 multi platform" instead of the frontmatter title), confirming MDX compilation failed for the entire file — not just the block.

**Cause**: Callout components (`<Note>`, `<Warning>`, `<Info>`, `<Tip>`) accept either inline form (tag + content + close on one line) OR block form (tags on own lines). Mixing the two breaks the MDX parser.

```mdx

<Note>
  Don't pick **Full re-initialize** — it overwrites existing config.</Note>


<Note>Don't pick **Full re-initialize** — it overwrites existing config.
</Note>
```

```mdx

<Note>Don't pick **Full re-initialize** — it overwrites existing config.</Note>


<Note>
  Don't pick **Full re-initialize** — it overwrites existing config.
</Note>
```

**Prevention**: Pick one form per callout and keep both tags consistent. When the body contains backtick code spans, bolded text, or more than one sentence, default to the block form for readability.

### Bulleted List Inside `<Note>` / `<Warning>` / `<Info>` / `<Tip>`

**Symptom**: Same as Mixed Block/Inline above — page renders as `A parsing error occurred`, title falls back to slug.

**Cause**: Prettier reformats Markdown inside JSX block bodies. Bulleted lists indented under the opening tag get pulled to column 0; the closing tag then gets indented 2 spaces. Mintlify sees the bullets as content outside the `<Note>` and the closing tag as misplaced. Parse fails.

```mdx

<Note>
  Hook support varies by platform:

  - **SessionStart** ships on Claude Code, Cursor, OpenCode...
  - **PreToolUse** ships on a smaller subset...
</Note>


<Note>
  Hook support varies by platform:

- **SessionStart** ships on Claude Code, Cursor, OpenCode...
- **PreToolUse** ships on a smaller subset...
  </Note>
```

**Prevention**: Don't put bulleted lists inside callouts. Keep the callout to a single inline summary line; place the list outside it.

```mdx

<Note>Hook support varies by platform and by event — see the per-event matrix below.</Note>

- **SessionStart** ships on Claude Code, Cursor, OpenCode...
- **PreToolUse** ships on a smaller subset...
```

If the bullets really must be inside the callout (rare — usually the inline-summary + list-outside form reads better anyway), use raw HTML `<ul><li>` instead of Markdown bullets so Prettier won't reformat them.

**Why this isn't caught by `prettier --check` or `markdownlint-cli2`**: both pass on the broken output. Only `mintlify broken-links` (or rendering the page in a Mintlify dev server) surfaces the parse failure. Worth wiring into CI.

### Table Column Alignment

**Problem**: markdownlint MD060 requires consistent table pipe alignment.

**Solution**: Ensure all columns align:

```markdown


| Command  | What it does                                      |
| -------- | ------------------------------------------------- |
| `/start` | Start session. Loads context, shows current task. |



| Command  | What it does                                      |
| -------- | ------------------------------------------------- |
| `/start` | Start session. Loads context, shows current task. |
```

---

## Best Practices

### DO

- Always include `title` and `description` in frontmatter
- Use components for visual structure (Cards, Tabs)
- Keep descriptions under 160 characters for SEO
- Use appropriate callout types (Note, Warning, Tip)
- Include code examples with language identifiers
- Use `<CodeGroup>` when showing code block syntax in examples

### DON'T

- Skip frontmatter
- Use raw HTML when components exist
- Write overly long descriptions
- Mix component styles inconsistently
- Leave code blocks without language hints
- Use escaped backticks to show nested code blocks

---

### .Trellis Spec Docs Site Docs Plugin Guidelines (`.trellis/spec/docs-site/docs/plugin-guidelines.md`)

# Plugin Guidelines

> Claude Code plugin manifest patterns and conventions.

---

## File Location

Plugin configuration directory: `.claude-plugin/` (project root)

```
.claude-plugin/
├── marketplace.json   # Marketplace manifest (required)
├── plugin.json        # Plugin definition (required)
└── README.md          # Installation docs (recommended)
```

---

## marketplace.json Schema

This file defines the marketplace and lists available plugins.

### Required Fields

| Field      | Type   | Description                     |
| ---------- | ------ | ------------------------------- |
| `name`     | string | Marketplace identifier          |
| `owner`    | object | Owner info with `name`, `email` |
| `metadata` | object | Contains `description`          |
| `plugins`  | array  | List of plugin definitions      |

### Plugin Entry Fields

| Field         | Type   | Required | Description               |
| ------------- | ------ | -------- | ------------------------- |
| `name`        | string | Yes      | Plugin identifier         |
| `source`      | string | Yes      | Path to plugin (relative) |
| `description` | string | No       | What the plugin does      |
| `author`      | object | No       | Object with `name` field  |
| `homepage`    | string | No       | Plugin homepage URL       |
| `repository`  | string | No       | Source repository URL     |
| `license`     | string | No       | License identifier        |
| `keywords`    | array  | No       | Search keywords           |
| `category`    | string | No       | Plugin category           |
| `tags`        | array  | No       | Descriptive tags          |

### Example

```json
{
  "name": "my-marketplace",
  "owner": {
    "name": "Your Name",
    "email": "you@example.com"
  },
  "metadata": {
    "description": "Description of your marketplace"
  },
  "plugins": [
    {
      "name": "my-plugin",
      "source": "./path/to/plugin",
      "description": "What this plugin does",
      "author": {
        "name": "Your Name"
      },
      "category": "workflow",
      "tags": ["tag1", "tag2"]
    }
  ]
}
```

---

## plugin.json Schema

This file defines the plugin itself.

### Required Fields

| Field         | Type   | Description          |
| ------------- | ------ | -------------------- |
| `name`        | string | Plugin identifier    |
| `version`     | string | Semantic version     |
| `description` | string | What the plugin does |

### Optional Fields

| Field        | Type   | Description                  |
| ------------ | ------ | ---------------------------- |
| `author`     | object | Object with `name` and `url` |
| `homepage`   | string | Plugin homepage URL          |
| `repository` | string | Source repository URL        |
| `license`    | string | License identifier           |
| `keywords`   | array  | Search keywords              |
| `skills`     | array  | Paths to skills              |
| `agents`     | array  | Paths to agent files         |
| `commands`   | array  | Paths to commands            |

### Example

```json
{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "What this plugin does",
  "author": {
    "name": "Your Name",
    "url": "https://github.com/you"
  },
  "homepage": "https://example.com",
  "repository": "https://github.com/you/repo",
  "license": "MIT",
  "keywords": ["keyword1", "keyword2"],
  "skills": ["./skills/my-skill"]
}
```

---

## Common Mistakes

### Mistake: author as string

**Symptom**: `plugins.0.author: Invalid input: expected object, received string`

```json
// ❌ WRONG
{
  "author": "Your Name"
}

// ✅ CORRECT
{
  "author": {
    "name": "Your Name"
  }
}
```

### Mistake: Missing source field

**Symptom**: `plugins.0.source: Invalid input`

```json
// ❌ WRONG - No source
{
  "plugins": [
    {
      "name": "my-plugin",
      "description": "..."
    }
  ]
}

// ✅ CORRECT - Include source
{
  "plugins": [
    {
      "name": "my-plugin",
      "source": "./path/to/plugin",
      "description": "..."
    }
  ]
}
```

### Mistake: Missing root-level fields

**Symptom**: `name: expected string, received undefined` or `owner: expected object, received undefined`

```json
// ❌ WRONG - Missing name and owner
{
  "plugins": [...]
}

// ✅ CORRECT - Include all root fields
{
  "name": "marketplace-name",
  "owner": {
    "name": "Owner Name",
    "email": "email@example.com"
  },
  "metadata": {
    "description": "..."
  },
  "plugins": [...]
}
```

### Mistake: Missing version in plugin.json

**Symptom**: Validation fails silently or during marketplace install

```json
// ❌ WRONG - No version
{
  "name": "my-plugin",
  "description": "..."
}

// ✅ CORRECT - Include version
{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "..."
}
```

### Mistake: Component fields as strings instead of arrays

**Symptom**: `agents: Invalid input` or similar

```json
// ❌ WRONG - String value
{
  "skills": "./skills"
}

// ✅ CORRECT - Array value
{
  "skills": ["./skills/my-skill"]
}
```

### Mistake: Directory paths for agents

**Symptom**: Validation fails for agents

```json
// ❌ WRONG - Directory path
{
  "agents": ["./agents/"]
}

// ✅ CORRECT - Explicit file paths
{
  "agents": [
    "./agents/planner.md",
    "./agents/reviewer.md"
  ]
}
```

> **Note**: `skills` and `commands` can use directory paths, but `agents` must use explicit file paths.

### Mistake: Adding hooks field

**Symptom**: `Duplicate hooks file detected`

```json
// ❌ WRONG - Explicit hooks declaration
{
  "hooks": ["./hooks/hooks.json"]
}

// ✅ CORRECT - No hooks field
{
  // hooks/hooks.json is auto-loaded by convention
}
```

> **Warning**: Claude Code v2.1+ automatically loads `hooks/hooks.json` by convention. Adding it explicitly causes a duplicate error.

---

## Validation

Before publishing, validate your plugin:

```bash
claude plugin validate .claude-plugin/plugin.json
```

Or from within Claude Code:

```
/plugin validate .
```

---

## Best Practices

### DO

- Include `version` in plugin.json
- Use object format for `author` (not string)
- Always include `source` in plugin entries
- Use arrays for component fields (`skills`, `agents`, `commands`)
- Use explicit file paths for `agents`
- Add a README.md with installation instructions

### DON'T

- Use string values for `author`
- Omit required root fields (`name`, `owner`)
- Use directory paths for `agents`
- Add explicit `hooks` field (auto-loaded by convention)
- Forget to validate before publishing

---

## Reference

- [Claude Code Plugin Docs](https://code.claude.com/docs/en/plugin-marketplaces)
- [everything-claude-code example](https://github.com/affaan-m/everything-claude-code/tree/main/.claude-plugin)

---

### .Trellis Spec Docs Site Docs Release Lifecycle (`.trellis/spec/docs-site/docs/release-lifecycle.md`)

# Docs-Site Release Lifecycle

> How `docs-site/` is structured across `release-only`, `release+beta`, `release+rc` states, and the three scripts that drive transitions.

---

## Convention: root = current stable

The directory layout pins one role per location:

| Path                                    | Role                                     |
| --------------------------------------- | ---------------------------------------- |
| `docs-site/{start,advanced,...}` (root) | **Current stable** (latest GA). Default. |
| `docs-site/beta/{start,advanced,...}`   | Active **beta** cycle (when one exists). |
| `docs-site/rc/{start,advanced,...}`     | Active **RC** cycle (renamed from beta). |

Non-versioned trees (`blog/`, `showcase/`, `contribute/`, `skills-market/`, `templates/`, `use-cases/`, `marketplace/`, `concepts/`, `essentials/`, `api-reference/`, `ai-tools/`, `guides/`, `snippets/`, `images/`, `logo/`) live only at root and are read by every version.

## Version path invariant

Before editing versioned docs, determine which release line the content belongs
to and verify the file path matches that line:

| Target line         | Edit path                                | Do not edit                          |
| ------------------- | ---------------------------------------- | ------------------------------------ |
| Current stable / GA | `docs-site/{start,advanced,...}`         | `docs-site/beta/**` or `rc/**`       |
| Active beta         | `docs-site/beta/{start,advanced,...}`    | root `docs-site/{start,advanced}`    |
| Active RC           | `docs-site/rc/{start,advanced,...}`      | root `docs-site/{start,advanced}`    |
| Chinese stable      | `docs-site/zh/{start,advanced,...}`      | `docs-site/zh/beta/**` or `rc/**`    |
| Chinese beta        | `docs-site/zh/beta/{start,advanced,...}` | root `docs-site/zh/{start,advanced}` |
| Chinese RC          | `docs-site/zh/rc/{start,advanced,...}`   | root `docs-site/zh/{start,advanced}` |

Do not use the version dropdown label in a rendered page as proof of source
scope. Mintlify renders all versions from one repository and `docs.json`, so the
only reliable source-of-truth is the MDX path plus the matching `docs.json`
version block.

When beta-only content accidentally lands in root, release users see beta
behavior under the Release selector. Treat that as a release-docs incident, not
as a rendering issue.

### Pre-commit audit for versioned changes

Run a path-scope audit before committing workflow, phase, artifact, install, or
platform behavior changes:

```bash
cd docs-site
git diff --name-only --cached

# For beta-only behavior, changed files must be under beta/ or zh/beta/.
# For stable behavior, changed files must be root versioned paths or zh/ root
# versioned paths.
```

Then grep for version-specific markers in the opposite tree. Example for a beta
workflow change:

```bash
rg -n "task-creation consent|codex-mode|<trellis-workflow>|planning artifact|`design\\.md`|`implement\\.md`" \
  start advanced guides zh/start zh/advanced zh/guides -g "*.mdx"
```

The command should return no hits except unrelated filename mentions such as
`trellis-implement.md`.

---

## 4 lifecycle states

```
T0  release-only          ← steady state between cycles
        │   docs.json: versions = ["Release"]
        │   files:     root/{start, advanced, ...}
        │
        ▼   start a beta cycle
T1  release + beta
        │   docs.json: versions = ["Release", "Beta"]
        │   files:     root/...    +  beta/{start, advanced, ...}
        │
        ▼   beta → rc
T2  release + rc
        │   docs.json: versions = ["Release", "RC"]
        │   files:     root/...    +  rc/{start, advanced, ...}     (rename beta/ → rc/)
        │
        ▼   rc → release (GA promote)
T3  release-only           ← back to T0; root is the new GA
        │   docs.json: versions = ["Release"]
        │   files:     root/...    (rc/* content folded into root, rc/ deleted)
        ▼
```

---

## Scripts

Three POSIX shell scripts in `docs-site/scripts/`:

| Script               | Transition | What it does                                                                                                                           |
| -------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `docs-beta-start.sh` | T0 → T1    | Copy versioned content (`start/`, `advanced/`, `index.mdx`) from root → `beta/`. Mirrors `zh/`.                                        |
| `docs-beta-to-rc.sh` | T1 → T2    | `git mv beta rc` (and `zh/beta` → `zh/rc`). Bulk text replace `@beta` → `@rc` inside `rc/*` content.                                   |
| `docs-promote.sh`    | T2 → T3    | Detect dev tree (`rc/` preferred over `beta/`), overwrite root versioned content with dev content, mirror in `zh/`, `git rm` dev tree. |

All three are **content-copy / rename only**. They never touch `docs.json` or the banner — those follow as manual edits because they're decision-driven.

### Manual followups

Each script ends with a checklist of `docs.json` edits and content scrubs the maintainer must apply before committing. Always:

| After                | Edit `docs.json`                                                                               |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| `docs-beta-start.sh` | Add `"Beta"` version block to `versions[]`. Add banner. Bump beta install commands to `@beta`. |
| `docs-beta-to-rc.sh` | Rename `"Beta"` label → `"RC"`. Update each page entry `beta/* → rc/*`. Update banner.         |
| `docs-promote.sh`    | Drop the `"Beta"` / `"RC"` version block from `versions[]`. Drop banner. Update navbar `href`. |

---

## When to use each

| Scenario                                                | Script                                | Trigger                                       |
| ------------------------------------------------------- | ------------------------------------- | --------------------------------------------- |
| First beta of a new minor / major (e.g. `0.6.0-beta.0`) | `docs-beta-start.sh`                  | Right before `pnpm release:beta` for the `.0` |
| Beta cycle stabilizing → first RC                       | `docs-beta-to-rc.sh`                  | Before `pnpm release:rc` for the `-rc.0`      |
| RC stable → cut GA                                      | `docs-promote.sh`                     | Before `pnpm release:promote`                 |
| Subsequent beta / rc patches (`-beta.1`, `-rc.1`, ...)  | (none — just write the changelog mdx) | Per-patch; no structural change needed        |

**Per-patch flow** (`-beta.1` → `-beta.2`, `-rc.1` → `-rc.2`, ...): just create `changelog/v<version>.mdx` (en + zh), add to top of pages list in `docs.json`, bump navbar href. No script invocation.

---

## One-time historical flip (0.5.0 GA)

Before 0.5.0, the layout was inverted: `root/` held the **dev** content (RC), and `release/` held the **previous GA** archive (0.4.0). At 0.5.0 GA we flipped to the convention above:

- Root content (was `0.5.0-rc.X`) became the new stable `0.5.0` GA in place
- `release/` (0.4.0 archive) was deleted (`git rm -r`); 0.4.x docs remain accessible via the `v0.4.0` git tag
- `docs.json` collapsed from 2 versions to 1 (`Release` only)
- The 3 scripts were introduced to keep the lifecycle reproducible going forward

After this flip, every future cycle uses the scripts; no further manual restructure should be needed.

---

## First real-cycle run: 0.6.0 GA (2026-06-15)

The 0.5.0 flip created the scripts; **0.6.0 GA was the first cycle that actually exercised the full T0→T1→T2→T3 chain end-to-end with `docs-promote.sh`**. Notes captured below to disambiguate the 0.5.0 precedent (which itself diverges from the standard flow because it was a one-time historical flip).

### `docs.json` transformation differs from 0.5.0

| Cycle | Pre-flip state | Right edit pattern |
|---|---|---|
| 0.5.0 (historical flip) | `RC` block had **root** paths, `Release` block had `release/*` paths (old GA archive) | Rename `RC` → `Release` label, **drop** the old `Release` block, `git rm -r release/` |
| 0.6.0 (standard flow) | `RC` block has `rc/*` paths, `Release` block has **root** paths (current GA) | **Drop** the `RC` block (its `rc/*` paths die when `docs-promote.sh` deletes the rc/ directory), keep `Release` as-is (its root paths now serve promoted v0.6 content), set `Release.default = true` |

Concrete edit list for the standard flow (post-`docs-promote.sh`, both languages):

1. `delete d['banner']`
2. Drop the `RC` version block from `versions[]` entirely
3. Set `Release.default = true` (the flag was on `RC`)
4. Insert `changelog/v<NEW_GA>` and `zh/changelog/v<NEW_GA>` at the top of each `Release` block's `Changelog` pages list
5. Update `navbar.links[label=Changelog].href` to `/changelog/v<NEW_GA>`

### First dual-package GA promote

0.6.0 was the first GA where both `@mindfoldhq/trellis` (CLI) and `@mindfoldhq/trellis-core` (SDK) ship in lockstep. `bump-versions.js promote` rewrites both `package.json` files and the CLI's `dependencies["@mindfoldhq/trellis-core"]` from `workspace:*` to the exact version at release time. `release-preflight verify-packed-cli` exists specifically to catch a divergence here — always run it before `pnpm release:promote`.

### Stale navbar Changelog `href` gotcha

The 0.6.0 cycle shipped 24 betas + 1 RC, and the navbar `Changelog` href in `docs.json` was never updated through any of them — it sat at `/changelog/v0.6.0-beta.22` at GA prep time. Per-patch beta/rc commits add the new mdx to the nav pages list, but they routinely forget the navbar href. Decision rule: **the GA promote PR is the last chance to fix the navbar href**, since GA is when readers actually start clicking the top-bar Changelog link.

### Pre-ship adversarial verify is load-bearing

The 0.6.0 GA prep flow ran a 10-agent pre-ship verify before `pnpm release:promote` and it caught 2 RED blockers that would have shipped:

1. `@mindfoldhq/trellis@beta` left in a bundled-skill markdown table after the lifecycle flip
2. Manifest's `**Bundled skills**` section listed 3 of the 4 actually-shipping bundled skills

Both blockers were prose-only (no code defect); both would have only embarrassed-not-broken users. Still, the adversarial verify earned its keep — recommend running an equivalent check on every future GA. The 10 angles (bundled skills + manifest + changelogs en/zh + docs.json + root content + preflight + tests + dogfood + npm-ready) generalize to any subsequent minor.

---

## Gotchas

### `docs.json` doesn't auto-update

Scripts only touch content trees. Forgetting the `docs.json` followup leads to:

- `T1 → T2`: pages still resolve at `beta/...` URLs but dropdown labels `RC` (404 on click)
- `T2 → T3`: stale `RC` dropdown remains while content is gone (404 on every page)

Always run `mintlify dev` locally after the script + manual edits to catch routing drift before push.

### Banner is sticky

The RC banner has been `"📦 Reading **RC** docs (0.5.0-rc.0)..."` literally across rc.0–rc.7 because nothing auto-bumps the version inside it. Either:

- Treat the banner as "RC docs in general — check `trellis --version` for your install" (current pattern), or
- Bump it as part of `docs-beta-to-rc.sh` followup (current scripts do not — they only print a reminder)

### MDX `<Note>` / `<Warning>` closing tags must NOT be indented

When a `<Note>` block contains a markdown list, prettier auto-indents the closing tag to align with the list:

```mdx
<Note>
- bullet
  </Note>   ← BREAKS Mintlify parser: "Expected closing tag </Note> after end of listItem"
</Note>     ← correct: closing tag at column 0
```

If you commit through `lint-staged` + prettier, expect re-indentation. Manually re-fix and commit, or add a `// prettier-ignore` if the project later supports it. Always run `pnpm dev` (mintlify) before pushing changelog mdx with these blocks.

### Stash workflow when RC and GA prep overlap

If you're staging GA content (`changelog/v0.5.0.mdx`, scripts/, `release/` deletions) while still needing to ship one more rc.X:

```bash
cd docs-site
git stash push -u -m "GA promote prep"  # park GA changes
# ... work on rc.X (changelog mdx + docs.json bump) ...
git commit && git push
git stash pop                            # restore GA prep; resolve docs.json conflict
```

The `docs.json` conflict at pop is expected — the rc.X commit added `v0.5.0-rc.X` at the top of pages list, while the stash had `v0.5.0` at the top. Keep both, with `v0.5.0` first (GA), then `v0.5.0-rc.X`, then older entries.

---

### .Trellis Spec Docs Site Docs Style Guide (`.trellis/spec/docs-site/docs/style-guide.md`)

# Style Guide

> Writing style and content standards for documentation.

---

## Voice and Tone

### Guidelines

| Aspect     | Guideline                                               |
| ---------- | ------------------------------------------------------- |
| **Voice**  | Professional, friendly, direct                          |
| **Tense**  | Present tense ("Click the button" not "You will click") |
| **Person** | Second person ("You can..." not "Users can...")         |
| **Mood**   | Imperative for instructions ("Run the command")         |

### Examples

**Good:**

> Run the following command to start the server.

**Avoid:**

> The user should run the following command to start the server.

---

## Page Structure

### Standard Page Template

```mdx
---
title: 'Clear, Action-Oriented Title'
description: 'What the reader will learn or accomplish (150 chars)'
---

Brief introduction paragraph explaining what this page covers.

## First Major Section

Content here...

### Subsection if needed

More detail...

## Second Major Section

Content here...

## Next Steps

Links to related content or next actions.
```

### Heading Hierarchy

| Level | Usage                                    |
| ----- | ---------------------------------------- |
| H1    | Never use (title comes from frontmatter) |
| H2    | Major sections                           |
| H3    | Subsections                              |
| H4    | Rarely needed, avoid if possible         |

---

## Writing Guidelines

### Titles

| Type            | Format        | Example                               |
| --------------- | ------------- | ------------------------------------- |
| Page title      | Title Case    | "Getting Started with the API"        |
| Section heading | Sentence case | "Configure your settings"             |
| Description     | Sentence      | "Learn how to set up authentication." |

### Technical Architecture Openings

Open technical architecture pages with the system thesis, then immediately ground it in concrete scope, modules, and source-of-truth files. Product positioning is acceptable when it names the architecture being documented; audience storytelling is not.

**Good:**

> Trellis is a Team-level Agent Harness with built-in LLM wiki. In implementation terms, that means two systems share the same project files: the agent harness controls workflow execution, and the LLM wiki stores specs, tasks, research, and journals.

**Avoid:**

> This page is for contributors and fork modders: engineers extending Trellis itself, not end users.

**Why**: Architecture docs should preserve the conceptual model, but the opening must quickly become a technical map. Audience labels and unsupported positioning prose make the page feel like a pitch instead of a technical contract.

### Lists

**Use bullet lists for:**

- Non-sequential items
- Feature lists
- Requirements

**Use numbered lists for:**

1. Step-by-step instructions
2. Ordered processes
3. Prioritized items

### Code References

- Use backticks for inline code: `npm install`
- Use code blocks for multi-line code
- Always specify language for syntax highlighting

---

## Content Types

### Conceptual Content

Explains what something is and why it matters.

```mdx
## What is Authentication?

Authentication verifies the identity of users accessing your API.
It ensures that only authorized users can perform actions.
```

### Procedural Content

Step-by-step instructions for completing a task.

```mdx
## Set Up Authentication

1. Navigate to the Dashboard
2. Click **Settings** > **API Keys**
3. Click **Generate New Key**
4. Copy the key and store it securely
```

### Reference Content

Technical specifications and API details.

```mdx
## API Response Codes

| Code | Meaning      |
| ---- | ------------ |
| 200  | Success      |
| 400  | Bad Request  |
| 401  | Unauthorized |
| 500  | Server Error |
```

### Architecture Content

Architecture and system-overview pages should explain the request or
workflow path before listing components.

```mdx
## From one request

Explain how a user action moves through the system:
input -> state lookup -> context selection -> execution -> verification
-> persistence.

## Component recap

Summarize each component after the reader understands why it appears.
```

**Why**: Component-first pages force readers to memorize names before
they understand the problem each component solves. A workflow-first path
shows when each file, hook, script, or role becomes necessary, then the
recap table reinforces the model.

**Reference detail**: Put exhaustive field tables, path matrices, and
per-platform configuration in reference pages or appendices. The
architecture page should summarize and link to those references instead
of duplicating them.

---

## Formatting Standards

### Emphasis

| Style    | Usage                        | Markdown     |
| -------- | ---------------------------- | ------------ |
| **Bold** | UI elements, important terms | `**text**`   |
| _Italic_ | Introducing new terms        | `*term*`     |
| `Code`   | Commands, file names, code   | `` `code` `` |

### Links

**Internal links:**

```mdx
See the [quickstart guide](/quickstart) for setup instructions.
```

**External links:**

```mdx
Read the [official documentation](https://example.com/docs).
```

### Images

```mdx

```

Always include descriptive alt text.

---

## Best Practices

### DO

- Start with the most important information
- Use concrete examples
- Keep paragraphs short (3-4 sentences max)
- Include code samples for technical content
- Link to related content

### DON'T

- Assume prior knowledge without linking to prerequisites
- Use jargon without explanation
- Write walls of text without visual breaks
- Skip alt text on images
- Use vague language ("simply", "just", "easily")

---

## Changelog / Release Notes Voice

Release notes (`docs-site/changelog/v*.mdx` and `docs-site/zh/changelog/v*.mdx`) are read by operators deciding whether to upgrade and by AI agents answering version questions. They are **reference docs**, not product storytelling. Match the tone of `kubectl` / Rust release notes, not marketing copy.

### Convention: Technical voice

**What**: Each section opens with one sentence stating what changed, followed by concrete identifiers (file paths, function names, flags, migration entries). Prefer tables, code blocks, and bullets over paragraphs. No rhetorical questions, no emotional language, no filler adverbs.

**Why**: A user scanning a changelog wants to answer "does this affect me, and what do I do?" in seconds. Narrative background ("then what? then nothing") pushes the actual change further down the page and tells readers how to feel rather than what changed. It also ages badly — in six months the only reader is an AI grepping for `phase.py` or `init.ts:1370`, not someone reliving the UX story.

**Example (changelog entry)**:

```markdown
### Joiner onboarding task

`trellis init` now dispatches on two filesystem flags:

| `.trellis/` | `.trellis/.developer` | Generated task |
|---|---|---|
| missing | n/a | `00-bootstrap-guidelines` (creator, unchanged) |
| present | missing | `00-join-<slug>` (new: joiner flow) |
| present | present | none (same-dev re-init) |

`.trellis/.developer` is the per-checkout signal because it's listed in
`.trellis/.gitignore` and therefore absent on fresh clones.
`.trellis/workspace/<name>/` cannot serve this role — it's committed to git.
```

**Related**: `Best Practices > DON'T > use vague language` above. Changelog narrative flourishes are the same anti-pattern at document level.

### Don't: Narrative storytelling in changelogs

**Problem**:

```markdown
### Joiner 引导任务——新开发者不再进来一脸懵

这个版本之前，新开发者在一个已有 Trellis 项目上第一次跑 `trellis init` 几乎啥都不做：
只往 `.trellis/.developer` 写了个身份文件，然后呢？然后就没然后了。打开 AI 工具面对
的是一片空白，不知道 Trellis 是什么、团队约定在哪、自己该做什么。队友只能反复在
群里解释工作流。

beta.9 起，`trellis init` 按两个文件的存在状态分三种场景派发：
```

**Why it's bad**:

- Rhetorical questions ("然后呢？然后就没然后了") and emotional framing ("一脸懵", "反复在群里解释") don't help an upgrade decision.
- The actual change (dispatch on two flags → three branches) is buried three paragraphs in.
- Language ages badly. In six months "一脸懵" reads as noise; the dispatch table still holds.
- Title is an outcome statement ("不再进来一脸懵"), not a feature name. Hard to grep for.

**Instead**:

```markdown
### Joiner onboarding task

`trellis init` now dispatches on (`.trellis/`, `.trellis/.developer`) presence
to generate three task types: creator bootstrap, joiner onboarding, or no task.
```

Lead with the change. Background (if any) goes into a second paragraph or a collapsed "Why" subsection — not in the opening sentence.

### Don't: section bloat

**Don't ship these sections in a changelog:**

- `## Tests` / `## Test Coverage` — "847/847 pass" / "5 new regression tests" is commit-message material. Users care about behavior, not test counts.
- `## Internal` (default) — refactor function-renames, internal flag flips, spec-file edits. Only include an Internal entry if it changes user-observable behavior in a multi-platform / multi-version setup. Otherwise drop it.
- `## Why` / `## Background` / `## Rationale` — multi-sentence justifications. If the change isn't clear from a one-sentence opener + table/code, the entry is too vague — split it or trim it. Long-form rationale belongs in the task PRD or commit body.

**Length cap**: each `###` section ≤ ~120 words. Going over means you're explaining instead of describing — trim.

**Allowed top-level sections** (ordered, skip empty ones): `Enhancements` (`feat`), `Bug Fixes` (`fix`), `Internal` (only if user-observable), `Upgrade`. No empty headings.

### Section heading rules

- **Use feature names, not outcomes**: `### Joiner onboarding task`, not `### New developers aren't thrown into a black box anymore`.
- **Stable across translations**: same technical nouns in both `docs-site/changelog/` and `docs-site/zh/changelog/`.
- **Greppable**: include exact identifiers users might search for (`task.json`, `trellis init`, `/trellis:finish-work`).

### Backstory goes elsewhere

Product narrative ("why we're doing this", user quotes, design rationale) belongs in:

- **Task PRD** (`.trellis/tasks/<task>/prd.md`) during development
- **Blog post** (`docs-site/blog/`) for marketing
- **Spec decision record** (`spec/*/` design-decision sections) for lasting architectural choices

The changelog just records what shipped and how users upgrade.

---

## Source-of-Truth Discipline for Code-Level Docs

When a page documents **code-level contracts** — JSON schemas, CLI subcommand tables, config field lists, file path references, default values — **open the source file first** and copy the list verbatim (field order, names, defaults) before writing a single line of prose. Don't document from memory, and don't propagate what existing docs already say without re-verifying.

### Why

Docs drift silently. `task.json` schema docs claimed `task.py create-pr` and `rejected` status existed for multiple releases — neither was ever in the source. The schema field order was shuffled, comments described behavior the code doesn't implement ("commit hash filled on archive" when `archive` only writes `completedAt`). Every one of these is a ~30-second verification away from the truth.

### Rule

Before writing or editing code-level reference docs:

1. Identify the **canonical source** — usually a single file (e.g. `task_store.py`, `init.ts`, a Zod schema). Link to it in the doc so reviewers can cross-check.
2. **Copy field order** from source. Don't alphabetize, don't reorder "for readability".
3. **Quote source line numbers** in commit messages (`task_store.py:147-172`) so the provenance is traceable.
4. When comments describe "when is this populated" — grep for every writer. If the only writer is `create()`, say "written as null; no other code paths update it" — don't invent imaginary lifecycle events.
5. When multiple writers exist with divergent shapes (e.g. `task_store.py` vs `init.ts` vs `update.ts`), either document all variants or document the canonical one and file a code-cleanup task to converge them. **Don't paper over divergence with optimistic prose.**

### Common Mistake: Documenting from prior docs

**Symptom**: Doc says field X or subcommand Y exists. Reader tries it. Nothing happens.

**Cause**: The doc was copied from a previous version of itself. The previous version was wrong. The field / subcommand was aspirational, removed, or never merged.

**Fix**: For every code-level claim, grep the source. If no code path writes/reads it, delete the claim.

**Prevention**: When editing an existing reference page, treat the prior content as unverified. The only trustworthy version is the source file.

---

## JSONL Context Injection Content

When writing docs, skills, commands, or templates that teach users about `implement.jsonl` / `check.jsonl` / `research.jsonl` entries, enforce this content rule:

### Rule

JSONL entries point at **spec files** (`.trellis/spec/**`) or the task's **research outputs** (`{TASK_DIR}/research/**`). They do NOT point at raw source files (`src/services/foo.ts`) or raw source directories (`packages/<pkg>/`).

### Why

Sub-agents already have `Read` / `Grep`. They pull code on demand. Injecting source files into the prompt:

- Burns tokens in every sub-agent spawn for code that may not even be relevant to this turn
- Makes JSONL entries decay fast (code moves; a path pinned by JSONL is stale the moment you refactor)
- Gives AI a false impression that the injected files are the "authoritative" code, biasing toward them even when better code exists elsewhere

Specs and research, by contrast, *are* the rules and background the sub-agent needs before touching code. They're the right payload.

### Example

```jsonl
# Good — specs + research
{"file": ".trellis/workflow.md", "reason": "Workflow contract"}
{"file": ".trellis/spec/backend/api-module.md", "reason": "API module conventions"}
{"file": ".trellis/tasks/02-27-user-login/research/", "type": "directory", "reason": "Upstream research outputs"}

# Bad — raw code
{"file": "src/services/auth.ts", "reason": "Existing auth patterns"}
{"file": "src/services/", "type": "directory", "reason": "Existing service patterns"}
```

### Writer's check

When you add a JSONL example or write a skill that calls `task.py add-context`:

- [ ] Is the path under `.trellis/spec/` or `{TASK_DIR}/research/`?
- [ ] If you're tempted to point at `src/` or `packages/`, ask: is this really a *rule* the agent needs up-front, or just code it could grep for itself when needed?

---

## Tombstone Sections: Delete, Don't Archive

When content becomes obsolete because a feature was removed, **delete the content outright**. Don't leave a "What was removed in vX.Y" table or a standalone "Appendix X: feature (removed)" page.

### Why

Tombstone sections:

- Pollute the TOC and in-page sidebar
- Repeat migration guidance that belongs in the changelog / migration manifest, not the reference docs
- Teach readers to skim-ignore sections — the "noise sections" train them to tune out legit content too
- Accumulate across versions (every release adds one; none ever removes one)

### Rule

When a feature is removed:

1. Delete the sections / pages that documented it.
2. Put the "what to do instead" guidance in **one place** — the release changelog or migration manifest's `notes` field. Link to it from the top-of-page `<Note>` for the one release that removes it, then drop the note the release after.
3. If a former section is heavily cross-referenced, check for incoming links and redirect them; don't keep the tombstone just to preserve URLs.

### Example

**Wrong** (actual regression seen in 0.5 audit):

```markdown
## Appendix E: worktree.yaml (removed)

This appendix previously documented…  Both the pipeline and this file
were removed in 0.5.0-beta.0 along with…
```

**Right**: delete `appendix-e.mdx`, remove it from `docs.json`. Note in the 0.5.0-beta.0 changelog that Multi-Agent Pipeline was removed and `worktree.yaml` is no longer read.

---

## Managing the Release / Beta Dual Track

The docs-site has two version tracks: **Beta** (tracks the latest `@beta` npm release, currently 0.5.x) and **Release** (tracks the latest stable, currently 0.4.0 GA). Users pick one from the version dropdown. Only part of the content is version-coupled.

### What's dual, what's single-source

| Lives in `release/` and `zh/release/` too | Single-source (top-level only) |
|---|---|
| `guide/ch01` – `ch13` (concepts, commands, platform matrix) | `use-cases/` |
| `guide/appendix-a` – `appendix-f` | `showcase/` |
| `guide/index.mdx`, `index.mdx` (landing) | `blog/` |
| `changelog/` (version entries) | `skills-market/` |
|  | `templates/` |
|  | `contribute/` |

**Rule of thumb**: anything that describes *how Trellis works right now* is dual (because that changes per version). Anything marketing, community, or resource-discovery stays single-source — those pages don't change per version, so maintaining two drift-prone copies burns effort for no user benefit.

When in doubt, ask: "Would a 0.4 user genuinely see something different on this page than a 0.5 user?" If no, it's single-source.

### Source of truth for platform counts

Platform count drifts across releases (0.4 = 14 platforms, 0.5 = 13 after iFlow removal). **Always derive the count from the CLI source for the version you're documenting, not from prior docs.**

```bash
# For Release track (documents 0.4.0 GA)
git ls-tree v0.4.0 packages/cli/src/configurators/ | grep '\.ts$' \
  | awk -F'[\t/]' '{print $NF}' | grep -v 'index\|shared\|workflow'

# For Beta track (documents current HEAD)
ls packages/cli/src/configurators/*.ts | xargs -n1 basename \
  | grep -v 'index\|shared\|workflow'
```

The count is `(number of configurator files) - (index.ts + shared.ts + workflow.ts)`.

### Per-platform directory layout for a specific version

To document what `trellis init --<platform>` actually writes in a given version:

```bash
git show v0.4.0:packages/cli/src/configurators/qoder.ts | head -60
git ls-tree -r v0.4.0 packages/cli/src/templates/qoder/
```

Don't infer from memory or from current beta templates — 0.5 adds `hooks/` and `rules/` to platforms that didn't have them in 0.4, so a current-beta listing will mis-describe 0.4.

### Orphan changelog files

When a `release/changelog/v*.mdx` file exists on disk but has no entry in `docs.json`'s Release dropdown, it's dead content — Mintlify doesn't render it in any nav, users can only reach it by guessing a URL. Delete it.

```bash
# List orphans (files on disk, not in docs.json)
cd docs-site
for f in release/changelog/*.mdx; do
  base=$(basename "$f" .mdx)
  grep -q "\"release/changelog/$base\"" docs.json || echo "$f"
done
```

Common source: when the track was forked from beta with `cp -r`, pre-release changelog files came along but the Release dropdown was manually whitelisted to stable versions only. Result: 30+ orphan MDX per locale.

### What each track is called

- **Beta track** = `guide/`, `changelog/`, `index.mdx` (at the top level) — latest `@beta` content
- **Release track** = `release/guide/`, `release/changelog/`, `release/index.mdx` — snapshot of the latest stable
- `docs.json` navigation has separate blocks for Beta and Release. Each language (EN, ZH) has both, so there are **4 navigation blocks total**.

Switching content between tracks is a `cp -r` with manual `docs.json` updates — there's no automation. Remember to update **all four navigation blocks** (EN Beta, EN Release, ZH Beta, ZH Release) when restructuring.

### When the stable GA bumps

When 0.5 reaches GA:

1. Decide whether to promote beta content → release (overwriting the frozen 0.4 snapshot) or keep both tracks. Usually promote.
2. `cp -r guide/ release/guide/` (EN) and `cp -r zh/guide/ zh/release/guide/` (ZH)
3. Update the release-track Changelog whitelist in `docs.json` to include the new stable version
4. Update the version-switcher label in the docs.json navbar (Release = "latest stable" not "0.4")
5. Delete pre-release changelog files from `release/changelog/` that shouldn't be in the stable-only whitelist
6. Beta track continues evolving toward the next major (0.6)

### Common Mistake: Documenting Release track from current templates

**Symptom**: You write Release-track docs (documenting 0.4.0 GA) and grab details from the current tree — e.g. `cat packages/cli/src/configurators/qoder.ts` or `ls packages/cli/src/templates/qoder/`. Result: the docs claim 0.4.0 generates paths that only exist on 0.5 betas (`.qoder/rules/`, `.qoder/hooks/`), or platforms that are 0.5-only get documented as 0.4. User tries to `trellis init --qoder` on 0.4.0 and sees a completely different layout.

**Cause**: The current tree is always beta-current. Release track docs must reflect the tagged stable version, which is what users on `@stable` actually get.

**Fix**: Always query the tagged version when writing Release docs. Every inline reference to a file path, config shape, or platform capability in the Release track should trace to `git show v<stable-version>:...` or `git ls-tree v<stable-version> ...`, never to the working tree.

**Prevention**: When you open a file to document a Release-track behavior, the first keystroke should be `git show v<version>:` not `cat`. If that feels like friction, keep a terminal tab pinned to `git log --oneline v<stable-version>^..v<stable-version>` so the tag is always in scope.

### Common Mistake: Counting platforms from existing docs

**Symptom**: Docs say Trellis supports N platforms, but the real count is different. Worst case: you inherit a wrong count from prior docs, propagate it, then spend a session re-fixing every mention. (Seen in 0.4.0 Release audit: prior docs claimed 6 platforms, next pass got to 12, actual was 14 — CodeBuddy and Antigravity were quietly shipped and never documented.)

**Cause**: Docs drift silently. When a platform is added to the CLI, documentation updates are manual and easy to forget. Counting from docs compounds every prior miss.

**Fix**: The canonical count is `git ls-tree v<version> packages/cli/src/configurators/ | grep '\.ts$' | grep -vE 'index|shared|workflow' | wc -l`.

**Prevention**: When a platform count appears in docs (tables, taglines, architecture diagrams, FAQs), cross-check it against the configurator directory for the target version before trusting prior docs. Treat every platform-count claim as unverified until you've run the count yourself.

---

## Quality Checklist

Before publishing:

- [ ] Title is clear and descriptive
- [ ] Description is under 160 characters
- [ ] Headings follow hierarchy (H2 > H3)
- [ ] Code examples are tested and correct
- [ ] Links are valid and point to correct pages
- [ ] Images have alt text
- [ ] Content is scannable (lists, tables, short paragraphs)
- [ ] For code-level reference pages: every field / subcommand / flag traces to a named source file you opened while writing
- [ ] JSONL examples inject specs or research, not raw code
- [ ] No "removed in vX.Y" tombstone sections for features already absent
- [ ] If you touched a dual-track page (`guide/*`, `appendix-*`, `index.mdx`), you updated both Beta and Release copies (EN and ZH each = 4 files to touch)
- [ ] If you touched a single-source page (`use-cases/`, `showcase/`, `blog/`, `skills-market/`, `templates/`, `contribute/`), you did NOT create a duplicate under `release/`
- [ ] Platform counts / lists trace to `git ls-tree v<target-version> packages/cli/src/configurators/`, not to prior docs or memory
- [ ] All four `docs.json` navigation blocks (EN Beta / EN Release / ZH Beta / ZH Release) are consistent

---

### .Trellis Spec Docs Site Docs Sync On Change (`.trellis/spec/docs-site/docs/sync-on-change.md`)

# Docs-Site Sync Matrix

> When Trellis changes **workflow**, **platforms**, **commands**, or **skills**, which docs-site pages must update in lockstep. A concrete "Audit ALL Writers" checklist for documentation.

---

## Why This Exists

Docs-site is a submodule that lags behind template code. Missing a doc-update on a shipping change produces false claims (docs say "run `init-context`" when the command has been removed). This has happened — see the init-context-removal task (2026-04-23) where 8 MDX pages still referenced the removed command after one implementation pass.

Rule of thumb: **if the change touches `packages/cli/src/templates/` or `packages/cli/src/migrations/`, grep the matrix below before merging.**

## Version Scope Gate

Before applying any trigger below, decide whether the changed behavior belongs
to stable, beta, or RC docs. The file path must match that decision:

- Stable / GA content: root versioned paths such as `start/**`, `advanced/**`,
  and their `zh/**` mirrors.
- Beta content: `beta/**` and `zh/beta/**` only.
- RC content: `rc/**` and `zh/rc/**` only.

Never copy a beta workflow, artifact model, platform contract, or install
instruction into the root versioned paths before GA promotion. Root is what the
Release selector serves.

### Required opposite-tree grep

For version-specific changes, grep the tree that should **not** contain the new
behavior before committing. For example, after a beta-only workflow change:

```bash
cd docs-site
rg -n "task-creation consent|codex-mode|<trellis-workflow>|planning artifact|`design\\.md`|`implement\\.md`" \
  start advanced guides zh/start zh/advanced zh/guides -g "*.mdx"
```

If this finds the new beta terms in root release docs, stop and move the change
to `beta/**` / `zh/beta/**` instead.

---

## Trigger 1: Phase Structure Changes

Scope: any edit to `packages/cli/src/templates/trellis/workflow.md` that adds/removes a step, renames a phase, or changes required/optional/once tags.

| File (en + zh)                      | What to sync                                                                                                                        |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `start/install-and-first-task.mdx`  | Phase 1/2/3 walkthrough block (around line 215-240 in en) — keep step numbers + action verbs in sync with `workflow.md` phase index |
| `start/everyday-use.mdx`            | Task lifecycle ASCII diagram + any per-phase bash examples                                                                          |
| `advanced/architecture.mdx`         | Phase overview diagrams (if present)                                                                                                |
| `concepts/workflow.mdx` (if exists) | Phase definition sections                                                                                                           |

### Grep command (docs-site)

```bash
cd docs-site && grep -rln "Phase 1\|Phase 2\|Phase 3\|phase-1\|phase-2\|phase-3\|workflow\.md" \
  --include="*.mdx" | grep -v "release/\|changelog/\|blog/"
```

### In-template routing references (CRITICAL — grep bare step numbers, not just "Phase N.N")

When a step is deleted/renumbered, references to it live in MORE than `workflow.md`. They use **bare-number routing syntax** that a `"Phase 3.1"` grep misses. Past drift: 0.6.1 deleted Phase 3.1 but left `continue.md` routing `check passed → **3.1**` (caught by a user, fixed in 0.6.2).

Audit ALL of these, in BOTH the source and any independent copies:

| File | Reference form |
| --- | --- |
| `packages/cli/src/templates/common/commands/continue.md` | resume-routing table: `status=... → **<step>**` |
| `packages/cli/src/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md` | resume-at status-transition table: `Phase <step> (...)` |
| `packages/cli/src/templates/copilot/prompts/finish-work.prompt.md` | Phase 3 ASCII flow list |
| `marketplace/workflows/{native,tdd,channel-driven-subagent-dispatch}/workflow.md` | full independent workflow copies — same step body + Phase Index + breadcrumb scope ranges |

Grep patterns that catch bare-number routing (run from repo root):

```bash
# bare-number routing arrows / bold step refs / step-N.N anywhere in templates + marketplace
grep -rnE "→ \*\*[0-9]\.[0-9]+\*\*|-> \*\*[0-9]\.[0-9]+\*\*|step [0-9]\.[0-9]+|Phase [0-9]\.[0-9]+|\*\*[0-9]\.[0-9]+\*\*" \
  packages/cli/src/templates/ marketplace/ \
  --include="*.md" --include="*.toml" --include="*.prompt.md" \
  | grep -v "/dist/"
```

Also verify the script tolerates a now-missing step: `python3 .trellis/scripts/get_context.py --mode phase --step <deleted>` must return a friendly "Step not found", not crash.

---

## Trigger 2: Platform Add / Remove / Rename

Scope: any edit to `AI_TOOLS` in `packages/cli/src/types/ai-tools.ts`, `_SUBAGENT_CONFIG_DIRS` in `task_store.py`, or platform-tagged blocks in `workflow.md`.

### Add a new platform

| File (en + zh)                              | What to sync                                                                        |
| ------------------------------------------- | ----------------------------------------------------------------------------------- |
| `ai-tools/<platform>.mdx`                   | **NEW FILE** — platform-specific setup + quirks page                                |
| `ai-tools/index.mdx` (if exists)            | List entry for the new platform                                                     |
| `docs.json`                                 | Add navigation entry to **both** `languages[0]` (en) and `languages[1]` (zh) groups |
| `start/install-and-first-task.mdx`          | Platform table (hook-inject vs pull-based vs agent-less)                            |
| `advanced/multi-platform.mdx`               | Class-1 / Class-2 / agent-less grouping table                                       |
| `advanced/appendix-d.mdx` (platform quirks) | Add quirks row if any                                                               |
| `release/` mirror copies                    | Release-frozen copies update on next release-cut, not immediately                   |

### Remove a platform

| File                                                                                         | What to sync                               |
| -------------------------------------------------------------------------------------------- | ------------------------------------------ |
| `ai-tools/<platform>.mdx`                                                                    | Delete the page                            |
| `ai-tools/index.mdx`                                                                         | Remove list entry                          |
| `docs.json`                                                                                  | Delete navigation entries (both languages) |
| `start/install-and-first-task.mdx`, `advanced/multi-platform.mdx`, `advanced/appendix-d.mdx` | Remove references                          |
| `changelog/<version>.mdx`                                                                    | Changelog entry documenting the removal    |

### Rename (e.g. "iFlow" removed) — same as remove + migration note in changelog.

### Grep command

```bash
cd docs-site && grep -rln "<platform-name>" --include="*.mdx" --include="*.json"
```

---

## Trigger 3: `task.py` Command Add / Remove / Rename

Scope: any edit to `task.py` subparser registrations or the split modules it dispatches to (`task_store.py`, `task_context.py`).

| File (en + zh)            | What to sync                                                     |
| ------------------------- | ---------------------------------------------------------------- |
| `advanced/appendix-b.mdx` | **`task.py` subcommand reference table** — add/remove row        |
| `start/everyday-use.mdx`  | Task lifecycle flow arrow + per-step bash examples               |
| `advanced/appendix-c.mdx` | If the change affects `task.json` fields, update schema comments |

### Evidence of past drift

The `init-context` removal (2026-04-23) touched all three files above; the first-pass sweep missed them. Only a follow-up review question ("哪些文档站地方需要更新") caught them.

### Grep command

```bash
cd docs-site && grep -rln "task\.py <subcommand-name>\|`<subcommand-name>`" --include="*.mdx" \
  | grep -v "release/\|changelog/"
```

---

## Trigger 4: Skill Add / Remove / Rename

Scope: any edit to `packages/cli/src/templates/common/skills/` or `packages/cli/src/templates/{platform}/skills/`.

| File (en + zh)                           | What to sync                                                                   |
| ---------------------------------------- | ------------------------------------------------------------------------------ |
| `start/everyday-use.mdx`                 | Skill table at top (around line 15-18) + individual skill description sections |
| `advanced/appendix-b.mdx`                | Skill reference table (if present)                                             |
| `start/install-and-first-task.mdx`       | Phase walkthrough skill names                                                  |
| Skill Routing table across workflow docs | Must match `workflow.md` Skill Routing per-platform splits                     |

### Grep command

```bash
cd docs-site && grep -rln "trellis-<skill-name>" --include="*.mdx" \
  | grep -v "release/\|changelog/\|blog/"
```

---

## Trigger 5: JSONL / Task Metadata Schema Changes

Scope: any edit to `implement.jsonl` / `check.jsonl` seed format, `task.json` schema, or consumer contracts (hook / prelude / `read_jsonl_entries`).

| File (en + zh)              | What to sync                                                                                        |
| --------------------------- | --------------------------------------------------------------------------------------------------- |
| `advanced/appendix-c.mdx`   | `task.json` schema block — every field has a comment; keep in sync with `task_store.py`             |
| `start/everyday-use.mdx`    | "Seeded on Create, AI Curates in Phase 1.3" section (or whatever replaces it) + sample JSONL blocks |
| `advanced/architecture.mdx` | Context injection diagrams if present                                                               |
| `concepts/*.mdx`            | Seed vs curated row distinction if any conceptual page explains jsonl                               |

### Contract to keep in sync

- **Created state**: on sub-agent-capable platforms `task.py create` writes empty
  `implement.jsonl` / `check.jsonl` — no placeholder row. Platforms that load specs
  through skills instead of JSONL (Codex inline mode, Kilo, Antigravity, Devin) get
  neither file
- **Curated row schema**: `{"file": "<path>", "reason": "<why>"}`
- **Consumer behavior**: row without `file` is skipped by every consumer (hook, prelude, list-context)
- **Legacy placeholder row** `{"_example": "..."}`: rejected by `task.py validate` and by PR preflight — delete it
- **READY gate**: jsonl with no curated rows → NOT ready (must have at least one curated row)

See `.trellis/spec/cli/backend/platform-integration.md` → "Agent-Curated JSONL Contract (Phase 1.3)" for the code-side contract.

---

## Trigger 6: Changelog & Migration

Every released version must have:

| File (en + zh)             | What to sync                                                                       |
| -------------------------- | ---------------------------------------------------------------------------------- |
| `changelog/v<version>.mdx` | Release notes — list user-visible changes, breaking-change warnings, upgrade steps |
| `docs.json`                | Navigation entry for the new changelog page (both languages)                       |
| `release/` tree            | Release-frozen copy — only updated on release-cut, not during develop              |

Migration manifests in `packages/cli/src/migrations/manifests/` need matching changelog entries. The manifest's `changelog` + `aiInstructions` fields are the authoritative text; changelog MDX should link to or paraphrase them.

## Trigger 7: `.trellis/config.yaml` Template or Reader Changes

Scope: any edit to `packages/cli/src/templates/trellis/config.yaml`, config readers under `packages/cli/src/templates/trellis/scripts/common/`, or `configSectionsAdded` behavior in update manifests.

| File (en + zh, release + beta) | What to sync |
|---|---|
| `advanced/configuration.mdx` | Add/remove/rename config keys, defaults, accepted values, and update behavior |
| `advanced/appendix-a.mdx` | Update the `.trellis/config.yaml` one-line purpose if the file's responsibility changes |
| `start/everyday-use.mdx` | Update only if the key affects day-to-day task/session operations |
| `changelog/v<version>.mdx` | Document user-visible config behavior or migration delivery |

### Grep command

```bash
cd docs-site && grep -rln "config.yaml\|session_auto_commit\|codex.dispatch_mode\|update.skip" \
  --include="*.mdx" --include="docs.json" \
  | grep -v "node_modules/"
```

**Rule**: The template is the source of truth for shipped examples, but `advanced/configuration.mdx` is the user-facing reference. If a key is supported by code but intentionally absent from the current template (for example, legacy compatibility), the configuration page should say so explicitly instead of silently omitting it.

---

## Bilingual Discipline

**Every update under `*.mdx` must be done in BOTH `en/` and `zh/` paths.** The zh/ tree mirrors the en tree exactly — same file names, same section headings, same order.

### Common drift sources

1. Edited en, forgot zh → `zh/start/everyday-use.mdx` falls behind by weeks
2. Navigation entries added to `languages[0]` only → page renders in English sidebar only
3. Code blocks translated (don't translate code — only prose)

### Detection

```bash
cd docs-site
# Find pages that exist in en but not zh (or vice versa)
diff <(find . -name "*.mdx" -not -path "./zh/*" -not -path "./release/*" -not -path "./node_modules/*" | sed 's|^\./||' | sort) \
     <(find zh -name "*.mdx" | sed 's|^zh/||' | sort)
```

Non-zero output = orphan pages. Triage before merge.

---

## Non-Triggers (Don't Update Docs)

| Change                                                 | Why no doc update                              |
| ------------------------------------------------------ | ---------------------------------------------- |
| Internal refactor with no user-visible behavior change | No user-facing contract changed                |
| Bug fix that restores documented behavior              | Docs already describe correct behavior         |
| Test additions                                         | Tests aren't user-facing                       |
| Migration manifest content changes                     | Already captured by `changelog/v<version>.mdx` |

---

## Audit Process Before Merging

1. Run the grep command from the trigger section that matches your change
2. Open each hit — is the page still accurate after your change?
3. For any hit that's stale: update both `en` and `zh` versions
4. If you added/removed pages: update `docs.json` navigation in both language trees
5. If the change impacts multiple triggers (e.g. a removed command + a removed platform), run all relevant greps

Mechanical > heroic. Don't rely on memory or review to catch drift.

---

--- METRICS ---
- Files Extracted: 10
- Estimated Token Budget: ~24141 tokens
- Canonical Reference: https://codewiki.google/github.com/mindfold-ai/Trellis
