---
layout: base.njk
title: CLI
nav: cli
prose: true
permalink: /cli/
---
# CLI
The `qualifier` crate installs a binary called `qualifier`.
```bash
cargo install qualifier
```
## Commands
**Write records:**
```
qualifier record <kind> <location> [message] Record an annotation
qualifier reply <target> <message> Reply to an existing record
qualifier resolve <target> [message] Resolve (close) an existing record
qualifier emit <type> <subject> --body JSON Emit a raw record of any type
```
`<kind>` accepts the built-in kinds (`pass`, `fail`, `blocker`, `concern`,
`comment`, `praise`, `suggestion`, `waiver`, `resolve`) or any custom string.
`<location>` is a path with an optional span (e.g., `src/auth.rs:42`).
`<target>` is an id-prefix (≥4 chars) or a `<location>`.
**Inspect:**
```
qualifier show <artifact> Show annotations for an artifact
qualifier ls [--kind K] List artifacts (optionally by kind)
qualifier praise <artifact> Show who annotated and why (alias: blame)
qualifier review [subject] Check freshness of span-bound annotations
```
**Maintain:**
```
qualifier compact <artifact> [options] Compact a .qual file
```
All commands that produce output accept `--format json` for machine-readable output.
<svg class="topo topo-wide" viewBox="0 0 900 40" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<line x1="0" y1="20" x2="900" y2="20" stroke="#818cf8" stroke-width="0.5" opacity="0.1"/>
<line x1="0" y1="0" x2="0" y2="40" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="180" y1="10" x2="180" y2="30" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="360" y1="0" x2="360" y2="40" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="540" y1="10" x2="540" y2="30" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="720" y1="0" x2="720" y2="40" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="900" y1="0" x2="900" y2="40" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
</svg>
## Typical workflows
### Record and resolve an issue
```bash
# Record a concern at a specific line
qualifier record concern src/parser.rs:42 "Panics on malformed input"
# See it
qualifier show src/parser.rs
# Reply (id-prefix, min 4 chars — or a location)
qualifier reply a1b2 "Good catch, fixed in latest commit"
qualifier reply src/parser.rs:42 "Good catch, fixed in latest commit"
# Close it
qualifier resolve a1b2
```
### Threaded conversations
```bash
qualifier show src/parser.rs
src/parser.rs
Records (4):
concern L42 "Panics on malformed input" alice 2026-03-01 a1b2c3d4
├── comment "Good catch, fixed in latest commit" bob 2026-03-01 b2c3d4e5
└── resolve "Resolved" alice 2026-03-01 c3d4e5f6
praise "Excellent property-based test coverage" bob 2026-02-24 e5f6a7b8
```
Replies and resolves are threaded under their parent with tree-drawing characters.
### Show details for one artifact
```bash
qualifier show src/parser.rs
src/parser.rs
Records (3):
concern L42–58 "Panics on malformed UTF-8 input" alice 2026-02-24 a1b2c3d4
praise "Excellent property-based test coverage" bob 2026-02-24 e5f6a7b8
suggestion "Consider adding fuzzing targets" carol 2026-02-24 f1f2f3f4
```
Use `--all` to include resolved/superseded records. Use `--pretty` to force colored output.
### Record a quality concern with full options
```bash
qualifier record concern src/parser.rs "Panics on malformed UTF-8 input" \
--suggested-fix "Replace .unwrap() on line 42 with error propagation" \
--tag robustness --tag error-handling \
--issuer "mailto:alice@example.com" \
--span 42:58
```
`--span` overrides any span parsed from `<location>`. When the source file is
readable, `content_hash` is auto-computed.
### Emit a raw record (raw or non-annotation types)
```bash
# A SPDX license record
qualifier emit license src/lib.rs --body '{"spdx":"MIT"}'
# A custom URI-typed record (round-trips via Record::Unknown)
qualifier emit https://example.com/lint/v1 src/parser.rs \
--body '{"rule":"no-panic","matches":3}'
```
`emit` is a low-level passthrough: the body is preserved verbatim. For
`--type annotation`, the body is validated against the annotation schema;
other types are not validated.
### Compact old annotations
```bash
# Preview what compaction would do
qualifier compact src/parser.rs --dry-run
# Prune superseded annotations
qualifier compact src/parser.rs
# Collapse everything to a single epoch annotation
qualifier compact src/parser.rs --snapshot
# Compact every .qual file in the repo
qualifier compact --all
```
### List artifacts
```bash
qualifier ls --kind blocker
qualifier ls --unqualified # artifacts with no annotations
```
### Batch annotation (for agents)
```bash
# Pipe overrides JSONL from stdin: {kind, location, message, ...}
# Or pipe complete records (envelope + body)
<svg class="topo topo-wide" viewBox="0 0 900 40" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<line x1="0" y1="20" x2="900" y2="20" stroke="#818cf8" stroke-width="0.5" opacity="0.1"/>
<line x1="0" y1="0" x2="0" y2="40" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="225" y1="10" x2="225" y2="30" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="450" y1="0" x2="450" y2="40" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="675" y1="10" x2="675" y2="30" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
<line x1="900" y1="0" x2="900" y2="40" stroke="#818cf8" stroke-width="0.5" opacity="0.06"/>
</svg>
## Configuration
Qualifier uses layered configuration (highest wins):
| 1 | CLI flags | `--issuer mailto:me@example.com` |
| 2 | Environment | `QUALIFIER_ISSUER` |
| 3 | Project config | `.qualifier.toml` |
| 4 | User config | `~/.config/qualifier/config.toml` |
| 5 | Built-in defaults | |