bito 2.0.0

Quality gate tooling for building-in-the-open artifacts
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
# bito

[![CI](https://github.com/claylo/bito/actions/workflows/ci.yml/badge.svg)](https://github.com/claylo/bito/actions/workflows/ci.yml)
[![Crates.io](https://img.shields.io/crates/v/bito.svg)](https://crates.io/crates/bito)
[![docs.rs](https://docs.rs/bito/badge.svg)](https://docs.rs/bito)
[![MSRV](https://img.shields.io/badge/MSRV-1.89.0-blue.svg)](https://github.com/claylo/bito)

**bito** = **b**uilding **i**n **t**he **o**pen.

bito is part of the [building-in-the-open](https://github.com/claylo/building-in-the-open) approach to AI-assisted development — a set of practices, templates, and tools for teams that work with coding agents. It can be used entirely on its own; the broader framework just gives it more context to work with.

AI coding agents generate documentation as they work — ADRs, design docs, changelogs, handoff notes. The quality varies between sessions. Sometimes you get crisp, well-structured prose. Sometimes you get bloated walls of text that no one wants to review.

bito catches the problems before you commit. It runs 18 deterministic writing checks — readability scoring, token budgets, section completeness, grammar, dialect enforcement, and style analysis. No LLM, no API calls, no network. Same input, same result, every time.

The goal: agent-generated documents that are clean enough to ship.

```
$ bito analyze docs/architecture.md

docs/architecture.md

  Readability: Grade 12.4, 24 sentences, 390 words
  Grammar:     8 issues, 3 passive (12.5%)
  Sticky:      Glue index 21.5%, 2 sticky sentences
  Pacing:      Fast 62% / Medium 29% / Slow 8%
  Length:      Avg 15.8 words, variety 10.0/10
  Transitions: 0% of sentences, 0 unique
  Overused:    "template" (1.3%), "skill" (1.1%), "design" (1.1%)
  Diction:     2 vague words
  Style:       Score 92/100, 2 adverbs, 0 hidden verbs
```

## What it checks

**`analyze`** runs 18 checks in one pass:

| Category | What it catches |
|----------|----------------|
| Readability | Flesch-Kincaid grade level — flag documents that demand too much of the reader |
| Grammar | Passive voice, double negatives, subject-verb disagreement, missing punctuation |
| Sticky sentences | High "glue word" density — sentences stuffed with *is*, *the*, *of*, *in* |
| Pacing | Monotonous sentence rhythm — all short punches or all long slogs |
| Sentence variety | Length distribution — a score of 1/10 means every sentence is the same length |
| Transitions | Percentage of sentences using connective phrases — low means choppy reading |
| Overused words | Repeated non-trivial words that make the text feel circular |
| Repeated phrases | Bigrams and trigrams that recur too often |
| Echoes | Same word appearing in adjacent sentences (unintentional repetition) |
| Complex paragraphs | Paragraphs with too many ideas competing for attention |
| Conjunction starts | Sentences opening with *But*, *And*, *So* — fine in moderation, a tic in excess |
| Cliches | "At the end of the day," "move the needle," "low-hanging fruit" |
| Diction | Vague words (*things*, *stuff*, *very*) that add length without meaning |
| Sensory language | Percentage of concrete, sensory words — useful for judging descriptive writing |
| Consistency | Mixed US/UK spelling (*color* and *colour* in the same document) |
| Dialect enforcement | Flag spellings that violate your project's chosen dialect (en-us, en-gb, en-ca, en-au) |
| Acronyms | Tracks acronym usage for consistency |
| Style score | Combined metric: adverb density, hidden verbs (nominalizations), overall polish |

Every check is deterministic. No API calls, no LLM, no network. The same input produces the same output every time.

**Focused checks** run individually when you need a specific gate:

```bash
# Does this handoff fit in 2,000 tokens?
$ bito tokens handoff.md --budget 2000
PASS: handoff.md is 546 tokens (budget: 2000)

# Is this user guide accessible to a general audience?
$ bito readability getting-started.md --max-grade 8
Error: getting-started.md scores 14.7 (max: 8). Simplify sentences or reduce jargon.

# Does this ADR have all the sections it needs?
$ bito completeness docs/decisions/0001-my-decision.md --template adr
PASS: docs/decisions/0001-my-decision.md (adr completeness check)

# How's the grammar?
$ bito grammar changelog.md
changelog.md: 16 sentences analyzed
  Passive voice: 2 instances (12.5%)
  Grammar issues: 3
    [MEDIUM] Sentence 3: Possible comma splice
    [LOW] Sentence 9: Multiple consecutive spaces found
    [MEDIUM] Sentence 16: Sentence missing terminal punctuation
```

## Installation

### Homebrew (macOS and Linux)

```bash
brew install claylo/tap/bito
```

### From source

```bash
cargo install bito
```

### Pre-built binaries

Download from the [releases page](https://github.com/claylo/bito/releases). Binaries are available for macOS (Apple Silicon and Intel), Linux (x86_64 and ARM64), and Windows.

## Usage

### Config-driven linting

Define rules in your config file to map file paths to checks, then run them with one command:

```bash
bito lint docs/handoff.md
bito lint --json docs/handoff.md   # structured output for CI
```

If no rules match the file, it exits cleanly. See [docs/README.md](docs/README.md) for rules configuration, accumulation, specificity, and inline suppressions.

### Full analysis

```bash
bito analyze my-document.md
```

Add `--dialect en-gb` to enforce British spelling. Add `--checks readability,consistency` to run only specific checks. Add `--exclude style,jargon` to skip specific checks.

### Output format

`--format` takes `auto` (the default), `text`, or `json`. `auto` means text on a
terminal and JSON everywhere else, so redirecting or piping any command gives
you a machine-readable document without a flag:

```bash
bito analyze doc.md                 # text, you are at a terminal
bito analyze doc.md > report.json   # JSON, stdout is a file
bito --format text analyze doc.md > report.txt   # force text
```

`--json` remains as an alias for `--format json`. If you are upgrading and a
script parsed bito's text output from a pipe, see [docs/UPGRADING.md](docs/UPGRADING.md).

### Quality gates

Quality gates are pass/fail checks designed for CI, pre-commit hooks, and automation:

```bash
# Token counting with budget enforcement
bito tokens <file> --budget <max>

# Readability with grade ceiling
bito readability <file> --max-grade <max>

# Section completeness against a template
bito completeness <file> --template <name>

# Grammar and passive voice analysis
bito grammar <file>
```

Built-in completeness templates: `adr`, `handoff`, `design-doc`. Define your own in a bito config file.

Every command writes structured JSON when stdout is redirected, and works in pipes.

### Exit codes

| Code | Meaning | What to do |
|------|---------|------------|
| `0` | Every check passed | Continue |
| `1` | A check ran and the input missed a threshold | Read the output and fix the prose |
| `2` | bito could not run | Fix the invocation; retrying unchanged will not help |

Exit `2` covers a malformed config, unreadable or oversized input, an unknown
check name, and command-line errors. Nothing was measured, so there is no
result to act on. Findings print without an `Error:` prefix; failures keep it.

`bito schema` publishes this contract as machine-readable JSON.

### Diagnostics

```bash
bito doctor            # config sources, environment, resolved directories
bito doctor --json     # same report, machine-readable
bito doctor --bundle   # redacted bito-debug-<ts>.tar.zst for bug reports
bito info              # version, features, config file paths
```

`doctor` reports the resolved log file alongside the config, cache, and data
directories, so it answers "where are my logs?" directly. `--bundle` writes the
report to a compressed archive with secrets redacted; the archive path appears
in the JSON as `bundle` rather than on stdout, so the document stays parseable.

`info` and `doctor` are the only commands that reach the network, checking for
a newer release with a 24-hour cache. Set `BITO_NO_UPDATE_CHECK=1` to disable
it. A failed check never fails the command.

### Dialect enforcement

Set a project dialect and bito flags wrong-dialect spellings alongside mixed-spelling inconsistencies:

```bash
# Via flag
bito analyze README.md --dialect en-us

# Via environment variable
export BITO_DIALECT=en-gb

# Via config file (.bito.toml)
dialect = "en-ca"
```

Supported dialects: `en-us`, `en-gb`, `en-ca` (Canadian hybrid: US *-ize/-ise*, UK for the rest), `en-au`.

### MCP server

bito includes a built-in [MCP](https://modelcontextprotocol.io/) server, so AI coding assistants can call quality gates directly during writing sessions:

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

This exposes eight tools: `analyze_writing`, `count_tokens`, `check_readability`, `check_completeness`, `check_grammar`, `lint_file`, `get_info`, and `get_custom`. The `lint_file` tool resolves path-based rules from your config, so the agent can check quality before writing. See [docs/README.md](docs/README.md#mcp-tools) for per-tool details.

## Configuration

Drop a config file in your project and it takes effect automatically:

1. `.config/bito.toml` (or `.yaml`, `.json`) in the current directory or any parent
2. `.bito.toml` in the current directory or any parent
3. `bito.toml` (without dot prefix) in the current directory or any parent
4. `~/.config/bito/config.toml` (user-wide defaults)

Closer files win. All formats (TOML, YAML, JSON) work interchangeably.

Environment variables override a *discovered* config file. A file named
explicitly with `-c/--config` outranks them.

- `BITO_LOG_PATH` — log file path
- `BITO_LOG_DIR` — directory (file name defaults to `bito.jsonl`)
- `BITO_ENV` — environment tag (default: `dev`)
- `BITO_NO_UPDATE_CHECK` — set to `1` to disable release update checks
- `RUST_LOG` — log filter, e.g. `debug` or `bito=trace`

The two log variables are the exception to the rule above: they decide where
logs get written even when `-c` names a config file that sets `log_dir`. Where
a process writes its logs is an operational question, so an operator can
redirect them without editing anyone's config.

Every config field also has a `BITO_`-prefixed form: `BITO_DIALECT`,
`BITO_MAX_GRADE`, `BITO_TOKEN_BUDGET`, and so on. See
[docs/README.md](docs/README.md#all-fields) for the full list.

The live log keeps a stable name, so `tail -f bito.jsonl` follows it across
days. On the first write of a new day the previous day's log is renamed to
`bito.YYYY-MM-DD.jsonl` and compressed to `.zst`. Rotated logs are deleted
after seven days; set `log_retention_days` to change that window, or to `0`
to keep them forever.

```toml
# .bito.toml
dialect = "en-us"
token_budget = 2000
max_grade = 12.0
log_level = "warn"
```

## Shell completions

Included in Homebrew installs and release archives. For manual setup:

```bash
# Bash
bito completions bash > ~/.local/share/bash-completion/completions/bito

# Zsh
bito completions zsh > ~/.zfunc/_bito

# Fish
bito completions fish > ~/.config/fish/completions/bito.fish
```

## Development

```
crates/
├── bito/       # CLI binary
└── bito-core/  # Core library
```

### Prerequisites

- Rust 1.89.0+ (2024 edition)
- [just]https://github.com/casey/just (task runner)
- [cargo-nextest]https://nexte.st/ (test runner)

### Quick Start

```bash
just check       # fmt + clippy + test
just test        # tests only (nextest)
just cov         # coverage report
```

### Build Tasks

| Command | Description |
|---------|-------------|
| `just check` | Format, lint, deny, and test |
| `just fmt` | Format code with rustfmt |
| `just clippy` | Run clippy lints |
| `just test` | Run tests with nextest |
| `just doc-test` | Run documentation tests |
| `just cov` | Generate coverage report |

### xtask Commands

The project includes an xtask crate for build automation:

```bash
# Generate man pages
cargo xtask man

# Generate shell completions
cargo xtask completions

# Generate for specific shell
cargo xtask completions --shell zsh
```

## Architecture

### Crate Organization

- **bito** — The CLI binary. Handles argument parsing, command dispatch, MCP server, and user interaction.
- **bito-core** — The core library. Configuration loading, writing analysis, lint engine, and all 18 deterministic checks.

### Error Handling

- Libraries use `thiserror` for structured error types
- Binaries use `anyhow` for flexible error propagation
- All errors include context for debugging

### Configuration System

Configuration discovery is handled by `config::load`:

```rust
use camino::Utf8Path;
use bito_core::config;

let cwd = Utf8Path::new(".");
let (cfg, sources) = config::load(cwd, None)?;
```

Pass an explicit path as the second argument to override discovery:

```rust
let (cfg, sources) = config::load(cwd, Some(Utf8Path::new("my-config.yaml")))?;
```

Features:
- Walks up directory tree looking for config files
- Stops at repository boundaries (`.git` by default)
- Merges multiple config sources with clear precedence
- Supports explicit file paths for testing

## CI/CD

This project uses GitHub Actions for continuous integration:

- **Build & Test** — Runs on every push and PR
- **MSRV Check** — Verifies minimum supported Rust version
- **Clippy** — Enforces lint rules
- **Coverage** — Tracks test coverage

### Dependabot

This project uses Dependabot for security monitoring, but **not** for automatic pull requests. Instead:

1. Dependabot scans for vulnerabilities in dependencies
2. A weekly GitHub Actions workflow converts alerts into **issues**
3. Maintainers review and address updates manually

This approach provides:
- Full control over when and how dependencies are updated
- Opportunity to batch related updates together
- Time to test updates before merging
- Cleaner git history without automated PR noise

Security alerts appear as issues labeled `dependabot-alert`.

## Contributing

Contributions welcome. See [Development](#development) above for the build and test loop, and [docs/README.md](docs/README.md) for the full command and configuration reference.

### Commit Messages

This project uses [Conventional Commits](https://www.conventionalcommits.org/):

- `feat:` — New features
- `fix:` — Bug fixes
- `docs:` — Documentation changes
- `perf:` — Performance improvements
- `chore:` — Maintenance tasks

### Code Style

- Rust 2024 edition
- `#![deny(unsafe_code)]` — Safe Rust only
- Follow `rustfmt` defaults
- Keep clippy clean

## License

MIT ([LICENSE-MIT](LICENSE-MIT))