> ## Documentation Index
> Fetch the complete documentation index at: https://docs.slipway.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# STYLE

# slipway docs style guide

Every page in `docs/` is written to this guide. `npm run lint` enforces the mechanical
half; the rest is on the writer.

The target is Render's operational documentation: flat, declarative, boring in the way
good reference is boring. If a sentence sounds like it was written to be admired, cut it.

***

## Page anatomy

Every page has the same skeleton.

```mdx theme={"system"}
---
title: "Persistent disks"
description: "Preserve a service's filesystem across deploys and restarts."
---

You can attach a disk to a web or worker service. Data written under the mount path
survives deploys, restarts and rescheduling. Everything outside it does not.

## Adding a disk
...
```

### Frontmatter

`title` is a noun phrase, sentence case. `description` is a **one-line imperative
subtitle** that says what the reader can do. Both are required on every page.

The description is not decoration. It is the sidebar tooltip, the search result snippet,
and the line that represents this page in `llms.txt`.

Write descriptions like these:

* `Preserve a service's filesystem across deploys and restarts.`
* `Run multiple copies of a service to handle more load.`
* `Give every pull request a running copy of your project.`
* `Deploy a repo with no Dockerfile by picking a language runtime.`

Not like these:

* `An overview of disks.` (says nothing)
* `Disks are persistent storage for your services.` (restates the title)
* `Everything you need to know about scaling.` (scaffolding)

### Opening

Two or three declarative sentences. State the fact, then the constraint.

Never restate the title. Never announce what the page will cover. Never open with a
problem statement the reader is assumed to have.

```
Good:  You can attach a disk to a web or worker service. Data written under the mount
       path survives deploys and restarts. Everything outside it does not.

Bad:   Persistent disks are how slipway gives your service storage that outlives a
       deploy. In this page we'll cover how to add one, how to size it, and what the
       limitations are.
```

### Headings

Task-shaped, not topic-shaped. The reader is scanning for a verb.

| Write | Not |
| - | - |
| `Setting a root directory` | `Root directory` |
| `Connecting from another service` | `Internal connections` |
| `Skipping a preview` | `Preview skipping` |
| `Handling a failed probe` | `Probe failures` |

A field-reference section is the exception: there, the heading is the field name, exactly
as written in YAML (`## dockerfilePath`).

### Closing

The page ends when the last fact is stated. No summary, no "and that's it", no closing
paragraph explaining why the design is good.

***

## Banned constructions

These are the patterns that make the current docs read as machine-written. Each one is
drawn from a real line in this repo.

### 1. The closing justification aphorism

A rule is stated, then a sentence explaining that the rule is correct. This is the single
most frequent tell in the current docs, and the same aphorism often recurs across pages.

```
Bad:   A database without a disk loses its data on restart, which is a bug shaped like
       a default.
Bad:   Only one service can mount a disk. That's deliberate: two writers on one device
       is how data gets corrupted.
Bad:   A service that needs more should have to say so rather than quietly running up
       your bill.

Good:  A database service requires diskSizeGB.
Good:  A disk can be mounted by exactly one service.
Good:  If you omit cpu, slipway uses 500m.
```

If the reasoning is genuinely load-bearing, state it once as a plain clause, not as an
epigram: "A disk is a single block device, so only one service can mount it."

### 2. "X is a Y, not a Z"

The antithesis construction. Nine instances in the current docs, three of them as
section-closing flourishes.

```
Bad:   A static site is a build artifact, not a process.
Bad:   Sleep is a scale-to-zero, not a teardown.
Bad:   The archive is a record, not a backup.

Good:  A static site has no container and no compute allocation.
Good:  Sleep scales a service to zero replicas. The project, its disks and its config
       are untouched.
Good:  The archive keeps the service's config and deployment history. It does not keep
       its disk contents.
```

Say what the thing *is*. If a misconception genuinely needs correcting, use a `<Note>`
or an FAQ entry, not a rhetorical inversion in body prose.

### 3. Announced-list scaffolding

Eight instances of `Two things to know:` / `Two caveats:` / `Two limits worth knowing:`
in the current docs.

```
Bad:   Two things worth knowing before you change them.
       - ...
       - ...

Good:  - ...
       - ...
```

The list is visible. Do not narrate its arrival or its length.

### 4. Mic-drop section closers

```
Bad:   The template is a starting point, not a wrapper you're stuck inside.
Bad:   The lock is not the boundary. The API refuses independently.
Bad:   They aren't features you can unlock, they're features that don't apply.
```

Cut the sentence. If it carries a fact, restate it flatly earlier in the section.

### 5. Section intros that restate the heading

```
Bad:   ## ports
       Ports the container listens on:

Good:  ## ports
       **Optional.** Ports the container listens on. Only `type: web` may declare them.
```

### 6. Rule-of-three padding

```
Bad:   Local sandboxes lie: a different kernel, a different libc, half your stack, none
       of your data.
Bad:   Postgres, MySQL, Mongo, SQLite-on-disk, a Lucene index, or a plain uploads folder.

Good:  Anything that writes to the filesystem and expects to read it back.
```

Two examples is usually enough. Six is never necessary.

### 7. Reusing a phrase across pages

The current docs repeat "the first visitor is as fast as the thousandth" verbatim on
three pages, and "the verification loop agents otherwise lack" on three more. A phrase
that appears on more than one page reads as templated. Say it once, on the page that
owns the topic, and link.

***

## Mechanics

### Em-dashes

None. Use a period, a comma, a colon, or parentheses.

```
Bad:   A static site has no container, so there's nothing to pay for by the minute — you're
       only metered on bandwidth.
Good:  A static site has no container, so there is nothing to pay for by the minute. You
       are metered on bandwidth only.
```

### Bold

Bold carries a load-bearing prefix or a table row label. Nothing else.

Permitted:

* `**Required.**` / `**Optional.**` / `**Required unless…**` at the head of a field definition
* `**No.**` / `**Yes.**` at the head of an FAQ answer
* The first cell of a table row, when the table has no header column

Not permitted: bolding a phrase mid-paragraph for emphasis, or a standalone bolded
sentence as its own paragraph. Target at most one bold span per ten lines. Two current
pages run at five times that.

### Brand name

Always lowercase `slipway`, including at the start of a sentence. If that reads badly,
rewrite the sentence so the name is not sentence-initial.

```
Bad:   Slipway resolves the spec at deploy time.
Bad:   slipway resolves the spec at deploy time.   (sentence-initial)
Good:  The spec is resolved at deploy time.
Good:  At deploy time, slipway resolves the spec.
```

`slipway.yaml`, `slipway` and any other identifier keep their literal casing in code spans.

### Defaults

State a default as a conditional sentence, not as a bare table cell.

```
Good:  If you omit `cpu`, slipway uses `500m`.
Good:  **Optional.** If you omit this, the service name is used.
Bad:   | cpu | string | 500m |
```

A table may still carry a `Default` column as a scannable index, but the prose beneath
the table is where the default is actually stated.

### Required-ness

In reference pages, mark it as a bold prefix on the field's own paragraph:

```mdx theme={"system"}
## diskSizeGB

**Required, except on `redis`.** The disk size in GiB, from 1 to 1024. A database
without a disk does not retain data across restarts.
```

### Numbers

Prices, plan ceilings, retention windows and engine versions live in `snippets/` and are
transcluded. Never hardcode them in a page.

```mdx theme={"system"}
import Rates from '/snippets/rates.mdx';

<Rates />
```

The lint script fails on a hardcoded rate or plan ceiling outside `snippets/`.

Source of truth for every number:

| Fact | Source |
| - | - |
| Compute and storage rates | `internal/billing/rates.go` |
| Plan capabilities and limits | `internal/billing/seed.go`, `ent/schema/plan.go` |
| Engine versions | `internal/dbengines/registry.go` |
| Spec fields and validation | `internal/specs/wire.go`, `spec.go`, `resources.go` |
| Parse error text | `internal/specs/parseerrors.go` |
| Statuses and event kinds | `ent/schema/deployment*.go`, `ent/schema/project*.go` |
| Console routes and tabs | `ui/console/src/routes/`, `sidebar.svelte` |
| MCP tools | `internal/mcp/tools.go` |
| CLI commands | `cmd/sw/` |

### Callouts

`<Note>` and `<Warning>` are for sharp edges only: a thing that will bite a reader who
does not know it. Phrase as a bare imperative or a bare fact.

```mdx theme={"system"}
<Warning>Do not commit secret values to `slipway.yaml`. Reference them with `${secret.NAME}`.</Warning>
```

Three or more callouts on one page means the page is badly organised, not that the
feature is dangerous.

### Tabs

Anything configurable in both places gets both, side by side:

```mdx theme={"system"}
<Tabs>
  <Tab title="Console">
    ...
  </Tab>
  <Tab title="slipway.yaml">
    ...
  </Tab>
</Tabs>
```

This is not optional. A reader arrives with one of the two mental models and should never
have to translate.

### Second person, present tense

"You can attach a disk." "slipway rebuilds the service." Not "users may attach" and not
"a disk will be attached".

### Hedging

Do not hedge. If there is an exception, name it.

```
Bad:   This generally takes a few seconds.
Good:  This takes a few seconds. A service with a large image can take longer on its
       first pull.
```

***

## Images

> A screenshot exists to locate a control. A diagram exists to show a sequence or a
> decision. Nothing else gets a picture.

**A screenshot is justified** when the reader has to find something on screen and the
prose cannot say where it is more cheaply than the picture can. "Click **Add registry**
in the top right" needs no screenshot. A node editor, a gallery, a chart, or a panel with
six controls does.

**A screenshot is not justified** when it shows a filled-in form the prose already
describes, a list of rows, a terminal prompt, or the page the reader is already looking
at.

Reference pages, concept pages, FAQ pages and plan/limits pages carry **zero** images.

**Use a mermaid diagram**, not a screenshot, when the subject is a flow or a decision:
deploy phases, probe outcomes, choosing a service type, how a preview resolves a sibling.

### Diagram standard

Diagrams are animated and use the brand palette. Render does the same, and it is what
makes a flow read as a flow rather than a static box chart.

Name each edge, then animate it. This is Mermaid 11.3+ syntax:

```
flowchart LR
  a["Build"] e1@--> b["Deploy"]
  b e2@--> c["Healthy"]
  e1@{animation: slow}
  e2@{animation: slow}
```

Use `animation: slow` for steady-state flows (a probe loop, a request path) and
`animation: fast` only where the point is that something is quick. Do not animate a
decision tree's every branch if the diagram is large enough that it becomes noise.

Colour comes from two `classDef` rules, reused on every diagram. Both use an alpha-blended
fill so they read correctly in light and dark mode, with text colour left to inherit:

```
classDef choice fill:#0D857714,stroke:#0D8577,stroke-width:1.5px
classDef result fill:#2DD4BF22,stroke:#0D8577,stroke-width:2px
class nodeA,nodeB choice
class nodeC,nodeD result
```

Add a third only where a diagram genuinely encodes success versus failure:

```
classDef bad fill:#dc262614,stroke:#dc2626,stroke-width:1.5px
```

Never hardcode a text colour or an opaque light fill. Mintlify renders diagrams in both
themes and an opaque `#fff` fill turns into black-on-black in dark mode.

Use `{{"..."}}` for a question or decision node and `["..."]` for a concrete thing.

Every image is a `<Frame>` with a caption that adds information rather than repeating the
alt text. Images are ≤1440px wide and WebP. An image used on more than one page is a sign
that at least one of those pages did not need it.

***

## Page types

### Conceptual page

Opening, task-shaped sections, and an `## Appendix: glossary` at the foot defining the
nouns the page used. Link the glossary entries to `/reference/glossary`.

### Reference page

Grouped by applicability. Each group opens with a `Field | Description` table linking down
to per-field anchors. Each field then gets its own heading and a paragraph beginning with
its bold required-ness marker. Long examples go in a collapsible `<Expandable>`.

### Procedural page

Numbered steps. One action per step. A screenshot only on steps where the control is hard
to find. End at the last step, not with a summary.

### Quickstart

600 to 900 words. What you will deploy, prerequisites, the complete `slipway.yaml`,
deploy, what you got, next-steps cards. At most one image.

### Troubleshooting entry

Keyed by the symptom or the literal error text the reader sees, because that is what they
will search for. Cause, then fix.

```mdx theme={"system"}
### `403 Forbidden` on a working deploy

Your framework rejected the request's `Host` header. slipway records this as a
`public_host_rejected` event on the deployment.

Add the service's hostname to your framework's allowed-hosts setting:
...
```

***

## FAQ sections

Add one where the same misconception keeps arriving. Answers may be one line. Lead with
`**Yes.**` or `**No.**` when the question is a yes/no.

```mdx theme={"system"}
## FAQ

**Does renaming a service keep its disk?**

**No.** A disk is bound to the service name. Renaming the service creates a new one and
archives the old.
```

***

## Checklist before committing a page

1. `description` is a one-line imperative subtitle.
2. Opening is two or three declarative sentences and does not restate the title.
3. Every H2 is task-shaped.
4. No closing aphorism, no `X is a Y, not a Z`, no `Two things:`, no mic-drop closer.
5. No em-dashes. `slipway` lowercase everywhere.
6. Bold only on required-ness prefixes and row labels.
7. Every number comes from a snippet.
8. Every fact re-verified against the source file in the table above.
9. Every image locates a control; every flow is a mermaid diagram.
10. `npm run lint` and `npm run broken-links` are clean.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.