Best Practices Reference CLN v2.9

Well-Structured CLN

The difference between CLN that works and CLN that's just visually formatted noise. Operator selection discipline, nesting depth, density calibration, anti-patterns that quietly destroy value, and the quality tests every CLN document should pass.

Reading time: 18 min Level: Practical reference Updated: March 2026 Spec: CLN v2.9

The core test — one question

A CLN document is well-structured if a reader who knows CLN can scan the left column — operators only, no content — and accurately predict the shape of what they are about to read. Not the specific content, but the semantic type distribution: roughly how much of this document is action vs definition vs risk vs unknown vs rationale.

If the operator column is a meaningless scatter — ! where a * belongs, = used for everything that doesn't fit elsewhere — the document has failed at the structural level regardless of how accurate its content is. The operators are doing no cognitive work. The document is prose in disguise.

The fundamental rule

Every operator choice is a semantic commitment. When you write !, you are committing that this line is a risk or precaution — something that can cause harm if ignored. When you write =, you are committing that this line defines or scopes something. Writing the wrong operator is not a style error. It is a semantic error that degrades every future reader's ability to trust the column.

Operator selection — the decision tree

The most common CLN quality problem is operator misselection — particularly the overuse of . for everything that looks like "a point," and ! for everything that feels slightly important. The operators are not tone markers. They are semantic type declarations.

Op Name Write this when… Not when…
= Equals Defining scope, purpose, or a term. The content answers "what is this?" The content is an action or a fact that doesn't define anything
. Dot A discrete executable action. Starts with a verb. Produces a state change. Describing a fact, stating a risk, or explaining context — use =, !, or *
→ Arrow The expected outcome of a preceding action or condition. Verifiable state. Continuation of a thought. Arrow means "if done correctly, this is what you see."
! Bang A real risk, precaution, or prerequisite. If ignored, harm follows. Emphasis. Something merely important. Use ! only if skipping it causes damage.
~ Tilde A genuine unresolved tension between two valid approaches. Both have merit. Uncertainty about a fact (use ?), or a known tradeoff with a clear answer (use * with rationale)
? Question An open question, hypothesis, or something genuinely unknown at write time. Rhetorical questions. Questions the author knows the answer to. Use = for those.
@ At Metadata: owner, trigger, date, version, channel, SLA. Structural not content. Information about what something is (use =) or who should do something (use . with @mention inline)
| Pipe A tool, resource, credential, or dependency required by a preceding action. Context or rationale for an action — use * for that
* Star Context, rationale, elaboration, or insider knowledge. Explains why. A risk (use !), an action (use .), or a definition (use =)
+ Plus An advantage, argument in favour, signal of strength. Balanced pair with −. A general positive fact — + is for explicit comparative evaluation only

The ! vs * confusion — the most damaging misselection

The most frequently misused operator pair is ! and *. Authors reach for ! whenever they want to signal that something matters, rather than when they want to signal that something is dangerous. The consequence is critical: when ! is overused, readers stop treating it as a danger signal. The document's warning system has been inflated into noise.

overused-bang.cln
✕ bad
. deploy to staging ! the staging environment uses different env vars ! the deploy script takes about 4 minutes ! notify #deploys channel when done ! do NOT deploy on Fridays after 3pm !! ! this process was updated in November
calibrated-bang.cln
✓ good
. deploy to staging * staging uses separate env vars · see .env.staging * takes ~4 min · check #deploys for confirmation . notify #deploys channel ! never deploy on Fridays after 3pm — on-call sparse !! * updated process: November 2025

In the corrected version, the single ! line — the Friday prohibition — stands out because it is the only ! in the block. The reader's eye goes to it immediately. In the broken version, the real prohibition is buried in a list of five exclamation marks, two of which are trivial facts. The operator has been devalued.

Nesting — depth discipline

CLN nesting is the mechanism for expressing that one line elaborates, qualifies, or depends on another. It is one of CLN's most powerful features and one of its most abused. The rule is simple in principle and requires discipline in practice.

Nesting rule

A child line belongs under a parent line if and only if it only makes sense in the context of that parent. If the child line can stand independently — if it would be equally meaningful anywhere in the document — it should not be nested.

Maximum practical nesting depth: 3 levels. Beyond that, the document should be refactored — the nested content probably belongs in its own section or document.

The correct parent-child relationships

nesting-patterns.cln — what goes under what
// Pattern: action + verification + resource + context . run database migration ☐ → migration completes · "X rows affected" message displayed | requires: db-admin credentials · staging access ! back up the database first if running against production !! * this migration is irreversible · no rollback script exists // Pattern: risk + rationale + exception ! never skip the integration tests !! * why: CI runs subset only · 6 edge cases not covered by CI * exception: hotfix path only · requires VP-Engineering sign-off // Pattern: tension + competing positions ~ aggressive caching vs real-time data freshness * current balance: 60s TTL · acceptable for reporting · not for trading ? does the new dashboard require sub-10s freshness? * if yes: cache invalidation strategy needed before launch // Pattern: definition + scope qualifiers = "production-ready": passes all tests · reviewed by 2 engineers · no open P1 issues ~ definition contested for experimental features — discuss with lead * introduced after incident INC-0043 · previously undefined

Nesting anti-pattern — the inverted pyramid

The inverted pyramid occurs when a document has more nested content than top-level content — when the scaffolding has become heavier than the structure it holds. This usually means the top-level structure is too fine-grained: too many single-item parents, each with a cloud of * children. The fix is to flatten the top-level structure into fewer, more substantial parents.

Document anatomy — what every CLN document needs

A well-formed CLN document has four structural zones, regardless of length or domain.

document-anatomy.cln — required zones
// Zone 1 — Header (required, first) TOPIC: [Domain or document title] @ owner: [person or team] @ created: [date] · updated: [date] @ trigger: [when this document is used] * optional: @version, @next-review, @audience // Zone 2 — Scope (required, after header) = [what this document covers — one line] = [what it explicitly does not cover — reduces scope creep] * optional: = goal (outcome), = non-goal (explicitly excluded objectives) // Zone 3 — Pre-flight (required if any preconditions exist) ! [hard prerequisite — must be true before starting] ! [hard prohibition — must not happen during execution] * all !! lines at the top · reader encounters them before action // Zone 4 — Body (the actual content) ⟶ Section name (optional, for longer documents) . [actions] → [expected results] ? [decision branches] ~ [tensions] * [context / rationale]

The scope zone is the most commonly omitted and the most frequently responsible for documentation failures downstream. A document without explicit scope attracts content that doesn't belong, becomes gradually incorrect as the domain evolves, and creates ambiguity about what its ! lines apply to.

The pre-flight zone front-loads all !! severity risks before the reader encounters any actions. This is not optional for high-stakes documents — a risk buried in step 7 that should have been read before step 1 is a design failure, not an authoring choice.

Line writing — what makes a single line good

The dot line — action clarity

A . line should be independently executable. A reader should be able to read it in isolation and know exactly what to do. Three tests:

weak-dot-lines.cln
✕ fails tests
. handle the deployment . make sure things are configured . do the usual checks . the migration needs attention
strong-dot-lines.cln
✓ passes tests
. run: make deploy ENV=production . verify: STRIPE_KEY and DB_URL set in .env.prod . run smoke tests: pytest tests/smoke/ -v . run: python manage.py migrate --plan · review output before confirming

Test 1: Does it start with a verb? "Handle the deployment" fails — "handle" is vague. "Run the deploy script" passes.

Test 2: Could a stranger execute it? "Do the usual checks" presupposes knowledge not in the document. "Run smoke tests: pytest tests/smoke/ -v" is executable by anyone with access.

Test 3: Is there one thing per line? Compound actions should be split. "Configure env vars and run tests" is two . lines.

The bang line — proportionality

A ! line should answer the question: "what specific harm occurs if this is ignored?" If you cannot answer that question, the line may belong in * instead. The severity suffix (!! for high, no suffix for moderate) should reflect the actual magnitude of the harm — not your confidence that the reader needs to see it.

The question line — honest unknowns only

A ? line should represent something the author genuinely does not know at write time, or a decision point that must be evaluated at execution time. ? lines with obvious answers ("? should we test this?" — yes, always) degrade the operator's signal. The question should be one whose answer is non-obvious and depends on runtime conditions.

Density calibration — how full is too full

CLN documents can fail by being too sparse (no cognitive work done, just a list of dot lines) or too dense (so many operators and children that the document is harder to scan than prose). The right density depends on the document's purpose and the operator distribution it needs.

Sparse
Only . and → lines. No !, ~, ?, *. Describes a sequence without any semantic context.
Light
Actions + results + key risks. Suitable for familiar processes where context is shared.
Calibrated ✓
Full operator range. Risks, rationale, open questions, tensions present where they exist — not forced.
Dense
Too many child lines per parent. Rationale chains longer than 3 * lines per parent. Hard to scan.
Overloaded
!! on every third line. Multiple ~ tensions per paragraph. Feels urgent. Scanability collapses.

The calibrated zone is not defined by a line count — it is defined by operator necessity. Every ! line should be there because the risk is real. Every * child should be there because the parent is not self-explanatory. Every ~ should be there because the tension is genuine and unresolved. If you find yourself adding operators to fill structural slots rather than to express semantic reality, the document is drifting into noise.

Anti-patterns — the eight failure modes

The prose dump
= used for everything; no action structure

All lines use = or *. The document reads like prose with operator prefixes. The reader gains no scanability advantage — they must read every line sequentially to find what they need.

Fix: identify the actions (.·→), the risks (!), and the decisions (?) — restructure around those
Bang inflation
! used for emphasis, not danger

More than ~15% of lines use !. Most of them are not genuine risks — they are important facts, reminders, or context. The warning system is inflated to noise and readers stop scanning for !.

Fix: demote non-dangerous ! lines to * (context) or = (definition). Reserve ! for genuine harm conditions.
Orphaned arrows
→ without a preceding action

→ lines appear at the top level with no parent . or ? that they verify. The reader cannot tell what the → is the outcome of. "→ system is stable" floating in a document is meaningless without a preceding action.

Fix: → must always be a child of the action or condition it verifies. Move or restructure.
Phantom tension
~ used for preference, not genuine tradeoff

"~ we could use Postgres or MySQL" is not a tension — one is almost certainly better for the use case. ~ is for situations where both options have real merit and neither clearly dominates. Fake ~ lines degrade the operator's signal that something is genuinely unresolved.

Fix: if there's a preferred answer, state it with = and explain with *. ~ is reserved for genuine draws.
Star rationale sprawl
5+ * children under one parent

A parent line followed by a cascade of * children. The context has overwhelmed the content. If the rationale is longer than 3 lines, it likely belongs in its own = section or a separate document — referenced via ##anchor.

Fix: limit * chains to 2–3 per parent. Extract longer rationale into = sections.
Missing metadata
No @owner, no @date, no trigger

A CLN document without @ header metadata is an orphan. In 6 months, no one knows who owns it, when it was last reviewed, or whether its !! lines reflect current reality. Undated risks are more dangerous than no risks — they produce false confidence.

Fix: every document needs @owner, @created/@updated, and @trigger before any content line.
Noun-first dot lines
Actions written as descriptions

"The database needs to be backed up" is a description. ". back up the database" is an action. . lines must start with a verb in the imperative or a command. Noun-first . lines produce ambiguity about whether this is something to do or something to know.

Fix: rewrite. . lines always begin with an imperative verb: run, check, confirm, notify, review.
Scope creep without markers
= scope missing or vague

No = scope line at the top. The document gradually accumulates content from adjacent domains. Readers are unsure which ! lines apply to their context. The document becomes a grab-bag that is trusted by no one and maintained by everyone.

Fix: add explicit = covers and = does not cover lines at the top. Review and trim to scope.

The ~ and ? operators — using them correctly

These two operators are CLN's highest-value and most underused. They encode the content that no other documentation format has primitives for: genuine tension and genuine uncertainty. Their underuse produces documents that look comprehensive but lack the honest acknowledgment of what is contested and what is unknown — the two things that most damage a new reader's ability to develop genuine domain understanding.

tilde-and-question-examples.cln — when to use each
// ~ correct use: genuine draw between two approaches ~ deploy on Tuesday vs deploy on Thursday * Tuesday: more time to fix before weekend · risk: Monday releases untested * Thursday: issues caught before EOW · risk: weekend on-call if Friday problems * current policy: no fixed day · team decides per release // ~ wrong use: one answer is clearly better // Bad: ~ use SQL or NoSQL for user sessions // Fixed: = use Redis for sessions (sub-millisecond TTL required) // * rationale: SQL session table was I/O bottleneck in load test 2024-08 // ? correct use: genuinely unknown at write time ? does the new EU data residency regulation apply to our staging environment? * ask: legal · deadline: before Q3 infrastructure planning ? will the client require SSO before go-live? → if yes: add SAML integration to scope · add 3 weeks // ? wrong use: author knows the answer // Bad: ? should we write tests? // Fixed: ! all new code requires tests · minimum 80% coverage !! // ? as tacit knowledge marker (deliberately unresolved) ? when does a code review need a second reviewer vs one being sufficient? * articulable signals: touches auth · touches payments · cross-service change * judgment develops with experience · no rule fully specifies the boundary * see: tacit-knowledge.html §honest-gap

Quality checklist — before you share a CLN document

Structure
☐
Header zone present: TOPIC title + @owner + @created/@updated + @trigger
☐
Scope zone present: at least one = covers line, ideally one = does-not-cover line
☐
All !! lines appear before the first . action line
☐
Nesting depth does not exceed 3 levels anywhere
Operator discipline
☐
Every ! line describes a real harm condition — not merely something important
Test: "what breaks if this is skipped?" — if no clear answer, demote to *
☐
Every . line starts with an imperative verb and is independently executable
☐
Every → line is a child of the action or condition it verifies
☐
Every ~ line represents a genuine unresolved tension, not a preference
☐
Every ? line is genuinely unknown at write time, or a real runtime decision point
☐
! frequency: below ~15% of all lines. If higher, audit each — most are probably *
Completeness signals
☐
Every significant ! has a * why: child explaining the harm mechanism
A bare !! with no rationale is a risk future readers cannot evaluate or update
☐
Open ? lines are either: resolvable with action (owner named) or honest tacit gaps (marked as such)
☐
The domain's live disputes appear as ~ lines — not smoothed over into settled = statements
☐
Single-person @ ownership lines have a backup contact or escalation path
Scanability test
☐
Cover the content column. Read only operators. The document's semantic shape is readable from the operator column alone.
☐
A new reader could identify every !! risk in under 10 seconds
☐
The action sequence (. lines) is unambiguous when read in order, without reading any * or | children

Revision discipline — keeping documents alive

A CLN document that is never revised is a liability. ! lines from 2022 that were accurate then may be wrong now. ? lines that were open unknowns may have been resolved and never updated. ~ tensions that were genuine may have been settled by a decision that no one recorded.

Three practices keep CLN documents alive:

Date the metadata. Every @ line has a date. Every structural update increments @updated. A document whose @updated is more than six months old is a candidate for audit regardless of its content.

Resolve or expire open questions. Every ? line should have a @deadline or @owner. At review time: either the question is answered (convert to = or delete), still genuinely open (keep and update), or no longer relevant (delete with a brief @archive note). A document with unreviewed ? lines accumulates false unknowns that degrade the reader's trust in the real ones.

Audit !! lines at every incident. Every time something goes wrong in a domain, check the relevant CLN documents. If the incident was caused by a condition not marked !!, add it. If an existing !! line was already there and was ignored, investigate why — was the risk buried? Was the operator inflated? The post-mortem feeds directly into the CLN revision.

revision-workflow.cln — keeping documents current
TASK: CLN document quarterly review @ cadence: quarterly · owner: document @owner @ trigger: @next-review date reached · or post-incident · or major domain change ⟶ Risk audit . scan all !! lines · for each: is the risk still real? is the severity correct? ☐ ? any !! lines from incidents not yet reflected here? → add from post-mortem records . scan all bare !! with no * why: child — add rationale or delete ☐ ⟶ Open question audit . for each ? line: resolved / still open / expired / wrong question? ☐ . resolved: convert to = and delete ? · add @resolved date in * . still open: confirm @owner and @deadline still correct . expired: delete with @archived note . wrong question: replace with better-framed ? ⟶ Tension review . for each ~ line: is the tension still unresolved? ☐ ? was a decision made that resolved it? → yes: delete ~ · add = with the decision + * rationale + @date ⟶ Ownership check . for each single-person @ ownership: is that person still in role? ☐ ! departed owner with no backup = knowledge gap about to happen !! . update @updated date · increment @version · commit ☐

The quality of a CLN knowledge base is not measured by its size — it is measured by the ratio of lines a reader can trust to lines that are stale, inflated, or misoperatored. A 50-line CLN document with correct operators, current metadata, and genuine !! lines is more valuable than a 500-line document where the !! has been inflated, the ? lines were never resolved, and the @updated date is two years ago.