building-in-the-open

Routes documentation requests to the right writing skill and configures bito quality gates — path-based lint rules, tokenizer backends, dialect enforcement, and MCP server setup. Use when asked to write docs, set up documentation tooling, configure quality gates, produce a README, or when the documentation type is ambiguous.

Building in the Open

Overview

This is the entry point for the building-in-the-open plugin. If you know exactly what artifact to produce, use the specific skill directly. If the request is ambiguous ("write docs", "set up documentation", "configure quality gates"), start here.

Routing

User wants...Use this skill
Capture session context for the next person/agentcurating-context (handoff)
Record a technical decisioncapturing-decisions
Formalize a design before or during implementationwriting-design-docs
Write tutorials, guides, or API references for end userswriting-end-user-docs
Produce CHANGELOG entries or release announcementswriting-changelogs
Review an artifact before committingeditorial-review
Set up quality gates for the first timeRun bash ${CLAUDE_PLUGIN_ROOT}/skills/building-in-the-open/scripts/scaffold-config.sh to drop a .bito.yaml in the project root
Configure or troubleshoot bitoContinue below

bito Setup

The plugin's quality gates run through bito. Without it, skills still produce artifacts, but nothing is measured.

Installation

cargo binstall bito          # pre-built binary, fastest
brew install claylo/brew/bito # macOS / Linux
npm install -g @claylo/bito   # wraps the native binary

Verify: bito doctor

Scaffolding a config

The plugin ships a template at ${CLAUDE_PLUGIN_ROOT}/defaults/bito.yaml with rules pre-wired for handoffs, ADRs, designs, and general docs. Drop it into a project with:

bash ${CLAUDE_PLUGIN_ROOT}/skills/building-in-the-open/scripts/scaffold-config.sh

Behavior:

  • Exits cleanly if any .bito.yaml / .bito.toml / .bito.json (or .bito-lint.*) already exists. Pass --force to overwrite.
  • Writes to .config/bito.yaml if a .config/ directory exists, otherwise .bito.yaml at the project root.
  • Fills template placeholders from env vars with sensible defaults: DIALECT (en-us), DOC_OUTPUT_DIR (record), MAX_GRADE (12.0), PASSIVE_MAX_PERCENT (15.0). The CLAUDE_PLUGIN_OPTION_* equivalents are also accepted.

Edit the generated file afterwards — it's a starting point, not a permanent contract.

Configuration file

bito discovers config files by walking up from the current directory to the nearest .git boundary. Supported names: .bito.yaml, .bito.toml, .bito.json (also .bito-lint.* for backwards compatibility).

# .bito.yaml — project-wide defaults (all fields optional)

dialect: en-us            # en-us | en-gb | en-ca | en-au — spelling enforcement
token_budget: 2000        # default budget for `bito tokens`
max_grade: 12.0           # default Flesch-Kincaid ceiling for `bito readability`
passive_max_percent: 15.0 # max passive voice % for `bito grammar`
style_min_score: 70       # min style score for `bito analyze`
tokenizer: claude         # claude (conservative, overcounts ~4%) | openai (exact cl100k_base)

# Custom completeness templates beyond the built-in adr, handoff, design-doc
templates:
  runbook: ["## Overview", "## Prerequisites", "## Steps", "## Rollback"]

Discovery order (highest precedence first):

  1. --config <path> CLI flag
  2. .bito.yaml / .bito.toml / .bito.json (or .bito-lint.*) in current or ancestor directory (up to .git boundary)
  3. ~/.config/bito/config.toml (user-level defaults)

Environment variable overrides — any field can be set via BITO_ prefix:

BITO_DIALECT=en-gb
BITO_TOKEN_BUDGET=3000
BITO_TOKENIZER=openai

Path-based rules

Instead of hardcoding check logic in hook scripts, declare what checks run on what files in your config. The rules array maps glob patterns to checks with per-rule settings:

# .bito.yaml
rules:
  - paths: [".handoffs/*.md"]
    checks:
      completeness:
        template: handoff
      tokens:
        budget: 2000
      grammar:
        passive_max: 15.0

  - paths: ["record/decisions/*.md"]
    checks:
      completeness:
        template: adr
      analyze:
        max_grade: 10.0

  - paths: ["record/designs/*.md"]
    checks:
      completeness:
        template: design-doc
      readability:
        max_grade: 12.0

  - paths: ["docs/**/*.md", "README.md"]
    checks:
      readability:
        max_grade: 8.0
      grammar:
        passive_max: 20.0

Rule resolution:

  • All matching rules accumulate — a file matching two rules gets the union of their checks
  • When two rules configure the same check, the more specific pattern wins (specificity = number of literal path segments)
  • {PROJECT_ROOT}/record/decisions/*.md (2 literal segments) beats record/**/*.md (1 literal)

Running rules: Use bito lint <file> to match a file against configured rules and run all resolved checks in one pass:

bito lint record/decisions/0001-my-adr.md        # human-readable output
bito lint record/decisions/0001-my-adr.md --json  # machine-readable

No matching rule = clean exit (exit 0). Any failing threshold = exit 1.

Available checks in rules

CheckSettingsDescription
analyzechecks, exclude, max_grade, passive_max, style_min, dialectFull 18-check writing analysis
readabilitymax_gradeFlesch-Kincaid grade level gate
grammarpassive_maxPassive voice percentage gate
completenesstemplate (required)Template section validation
tokensbudget, tokenizerToken count gate

Inline suppressions

Suppress specific checks for sections that intentionally break rules:

<!-- bito disable grammar -->
This section uses passive voice on purpose.
<!-- bito enable grammar -->

<!-- bito disable-next-line readability -->
This extraordinarily sesquipedalian sentence is intentional.

<!-- bito disable grammar,cliches -->
Multiple checks suppressed at once.
<!-- bito enable grammar,cliches -->

An unclosed disable suppresses for the rest of the file.

MCP server

For real-time quality feedback during writing sessions, configure bito as an MCP server. This lets writing skills call quality gate tools directly without shelling out.

Add to your project's .mcp.json:

{
  "mcpServers": {
    "bito": {
      "command": "bito",
      "args": ["serve"]
    }
  }
}

The MCP server exposes: count_tokens, check_readability, check_completeness, analyze, check_grammar, and lint_file (runs path-based rules). When available, writing skills should prefer MCP tool calls over shell commands.

Tokenizer backends

bito ships two tokenizer backends:

  • claude (default) — Uses a 38K verified Claude vocabulary with greedy longest-match. Overcounts by ~4% on prose. Safe for budget enforcement: you'll never silently exceed a limit.
  • openai — Exact BPE encoding using cl100k_base (GPT-4/GPT-3.5 vocabulary). Use only when targeting OpenAI models.

Set the backend via config (tokenizer: claude), env var (BITO_TOKENIZER=openai), or CLI flag (--tokenizer openai).

Quality Gate Quick Reference

CheckCommandWhat it measures
Lint (rules)bito lint <file>Run all checks matching file path rules
Token countbito tokens <file> --budget 2000Tokens vs budget (handoffs)
Readabilitybito readability <file> --max-grade 12Flesch-Kincaid grade level
Completenessbito completeness <file> --template adrRequired sections present
Grammarbito grammar <file>Passive voice, sentence issues
Full analysisbito analyze <file> --dialect en-usAll checks + style score

Built-in completeness templates: adr, handoff, design-doc. Define custom templates in config.

Personas and Skill Mapping

Each persona is a voice guide in ${CLAUDE_PLUGIN_ROOT}/personas/. The same artifact type always gets the same voice.

ArtifactSkillPersonaPersona file
Handoffcurating-contextContext Curatorcontext-curator.md
ADRcapturing-decisionsTechnical Writertechnical-writer.md
Design docwriting-design-docsTechnical Writertechnical-writer.md
End-user docwriting-end-user-docsDoc Writerdoc-writer.md
CHANGELOG entrywriting-changelogsTechnical Writertechnical-writer.md
Release announcementwriting-changelogsMarketing Copywritermarketing-copywriter.md
README (above the fold)Marketing Copywritermarketing-copywriter.md
README (below the fold)writing-end-user-docsDoc Writerdoc-writer.md

Multi-persona artifacts: The heading structure is the boundary. README transitions at ## Installation. CHANGELOG + release announcement are handled natively by writing-changelogs. Rule of thumb: "attract or instruct?" Attract = Marketing Copywriter. Instruct = Doc Writer or Technical Writer.

Skill chaining: writing-design-docscapturing-decisions (ADR extraction), curating-contextcapturing-decisions (session decisions), any writing skill → editorial-review (tone firewall).

Pre-commit Hook

The plugin includes a git pre-commit hook that runs quality gates on staged documentation files. To install it:

cp hooks/pre-commit-docs .git/hooks/pre-commit

Or source it from an existing hook:

# In your existing .git/hooks/pre-commit
source ~/.claude/plugins/building-in-the-open/hooks/pre-commit-docs

With path-based rules configured, the pre-commit hook can use bito lint instead of per-file check logic — the config becomes the single source of truth for what checks run where.