| name | docs-writing-style |
|---|---|
| description | Shared prose style rules for ZIO Blocks documentation. Include when writing any ZIO Blocks documentation page — reference pages, how-to guides, or tutorials. Also include docs-mdoc-conventions for code block modifiers. |
- Project name: "ZIO Blocks" (not "zio-blocks").
- Person: Use "we" when guiding the reader or walking through examples ("we can create...", "we need to..."). Use "you" when addressing the reader's choices ("if you need...", "you might want to...").
- Tense: Present tense ("returns", "creates", "modifies").
- Concision: Keep prose short. Let code examples do the heavy lifting. If you find yourself writing more than 4 sentences of prose without a code block, you're being too verbose.
- Don't pad: No filler phrases like "as we can see" or "it's worth noting that". Just state the fact.
- No emojis: Unless the user explicitly requests them.
- Capitalize bullet sentences: When a bullet point is a full sentence, start it with a capital letter.
- No manual line breaks in prose: Do not hard-wrap paragraph text at a fixed column. Write each paragraph as one continuous line.
- ASCII art: Use it for diagrams showing data flow, type relationships, or architecture. Readers find these very helpful for understanding how pieces fit together.
- No exhaustive API coverage in guides: Only document the methods and types that serve the guide's goal. Link to reference pages for full API details.
- Link to related docs: Use relative paths, e.g.,
[TypeName](./type-name.md).
Apply these conventions consistently in all prose, section headings, and inline code:
- Always qualify with the type name — never refer to a method or constructor by its bare name. Write
BindingResolver.empty, notempty; writeZIO#map, notmap. The type name is essential context for the reader. - Type name alone — when talking about the type itself, use only its name with no qualifier:
"derives automatically via
As", "Intois a one-way conversion". - Instance method — use
TypeName#methodName(the#convention signals a non-static member):As#from,As#into,As#reverse,Into#into. - Companion object operation or constructor — use
TypeName.methodName(the.convention signals a companion/static member):As.derived,As.apply,Into.derived,Into.apply.
- Heading hierarchy: Use
##for major sections,###for subsections, and####for subsubsections. All three levels are fully supported and encouraged. - No bare subheaders: Never place a
###or####subheader immediately after a##header with nothing in between. Always write at least one sentence of explanation before the first subheader. - No lone subheaders: Never create a subsection with only one child. If a
##section would have only one###, remove the subheader entirely and place the content directly under the parent heading. The same rule applies to###→####. - When to use
####: Group multiple related items (use cases, examples, sub-patterns) under a single###heading by using####for each item. This creates visual hierarchy and makes the section more scannable. Example:### Use Cases→#### Polyglot configuration systems→#### Schema-driven migrations. - Every code block must be preceded by an introductory prose sentence: The content immediately
before a code block's opening fence must always be a prose sentence — never a heading alone and
never blank space alone. This applies universally:
- After a heading: write at least one sentence before the first code block.
- Between two consecutive code blocks: write a short bridging sentence.
- The sentence must be surrounded by blank lines on both sides (standard Markdown spacing).
- The sentence must end with a colon (
:). A colon signals to the reader that code follows.
- Always include imports: Every code block must start with the necessary import statements.
- One concept per code block: Each code block demonstrates one cohesive idea.
- Prefer
valovervar: Use immutable patterns everywhere. - Never hardcode expression output in comments: Do not annotate expression results with inline
comments such as
// None,// Some(SchemaError), or// "hello"— these go stale and can be wrong. The fix is not to remove the comment and leave the block asmdoc:compile-only— that still hides the result. The fix is to restructure the block so mdoc evaluates and renders the output:- Move all type definitions and setup
vals into amdoc:silent:resetblock (ormdoc:silentif scope continuity is needed). Usemdoc:silent:resetin reference pages to avoid name conflicts between independent sections. - Add a short bridging sentence ending in
:. - Put the expressions whose results matter in a bare
mdocblock — mdoc renders them as REPL-style output automatically. Seedocs-mdoc-conventionsfor the complete modifier table and the Setup + Evaluated Output pattern.
- Move all type definitions and setup
- Code snippet description: When showing example code snippets, explain what they do and why they are relevant. Don't just show code without context.
All code in documentation and companion example files defaults to Scala 2.13.x syntax. When in doubt, check the companion example files — they are the source of truth for syntax style.
When a section shows syntax that genuinely differs between Scala 2 and Scala 3 (e.g., using
vs implicit, native union types vs backtick infix), use tabbed code blocks instead of
sequential prose. See docs-mdoc-conventions for the exact tab structure. Scala 2 is always
the default tab (defaultValue="scala2").