Style
How I like documentation and code comments to be written. Apply these to every project in this directory unless a specific project documents an exception.
Prose
No Em-Dashes
Don't use the em-dash character ("—") in prose, comments, or commit messages. Use a comma where a parenthetical pause fits, or split into two sentences when the thought is heavier. Em-dashes read as AI-generated; commas don't.
Plain, Conversational Wording
Write the way you'd explain something to a colleague, not the way an academic paper would phrase it. Prefer short, common verbs (use, help, run, set, check, show) over polysyllabic ones (utilize, facilitate, instantiate, leverage). Skip stilted constructions ("in the event that", "due to the fact that", "with respect to") in favor of plain words ("if", "because", "about"). Replace abstract or metaphorical phrasings with the literal version of what you mean: say what differs, what's missing, or what depends on what, rather than dressing it up. If a word wouldn't survive being read aloud in a meeting, swap it.
Direct Technical Wording
Choose concrete technical nouns and verbs over poetic or vague ones. Prefer specific nouns ("the Lambda", "the deploy role", "the bundle", "the code", "the infrastructure") over generic ones ("the thing", "the work", "it" when unanchored). Use literal verbs ("released", "deployed", "merged", "added", "removed", "created") instead of metaphorical ones ("lands", "ships", "lives", "comes online"). Documentation should read like a runbook or a release note, not narrative or marketing copy.
No Vague Hype Words
Don't justify a choice with marketing adjectives like "battle-tested", "robust", "powerful", "seamless", "blazing-fast", or "industry-leading". They sound like a reason but say nothing measurable. Give the concrete reason instead: "popular" or "commonly used" (when adoption is the point), "maintained" (when upkeep is the point), "faster than X at Y" (when speed is the point, with the comparison named). If you can't name what makes it good, leave the claim out rather than dressing it up.
Don't Say "for Free"
Don't describe what a library or tool provides as coming "for free". Everything a dependency gives you is "for free" in that sense, so the phrase adds nothing. State it plainly: "the library includes", "Pino provides", "the framework handles". Name what you get and who provides it, not that it was free.
Don't Minimize Effort
Don't use words that downplay how much work something takes: "the only thing", "just", "simply", "all you have to do", "trivial". They imply a task is easy, which sets a false expectation when it isn't and reads as dismissive when the reader is stuck. State what the task is without the size judgment: "the remaining piece is the log-code catalog" rather than "the only thing left is the log-code catalog". If scope genuinely matters, describe it concretely (how many files, what steps) instead of labeling it small.
Use Full Names, Not Shorthand
Spell identifiers and field names out in full: message not msg, context not ctx, request not req, response not res, event not evt. This applies to variable names, function names, log field names, and documentation. Abbreviations save a few characters and cost clarity on every read. There are two narrow exceptions. First, conventional short names for a caught error in a catch block, err or e, are fine, because the meaning is obvious and the scope is local. Don't stretch that license to anything ambiguous: never use e for an event, c for a context, r for a record. Second, keep established initialisms that are already the full name in practice (id, url, api, arn).
Title Case for Headings
Every Markdown heading (#, ##, ###, ...) uses Title Case: capitalize all major words, lowercase articles and short prepositions (a, an, the, in, on, at, by, for, of, to). Section titles inside long comment blocks follow the same rule.
Don't Hard-Wrap Markdown
In Markdown files, write each paragraph as one continuous line and let it soft-wrap. Don't insert a line break in the middle of a sentence to keep the line short. Markdown wraps the text automatically when it renders, so a manual break does nothing for the reader, it only adds lines that make edits and diffs noisier. Break only where the structure calls for it: between paragraphs, list items, and headings. This is the opposite of the rule for code comments (see Break Lines at Sentence or Clause Boundaries), where hard line breaks are needed and should fall at clause boundaries.
Structure
One Canonical Entry Doc
The README is the single entry point for a project. Other docs (CICD, DEPLOY, AGENTS, ...) are standalone references for specific topics. The README does not link out to them; readers find what they need from each doc's filename and contents.
Don't Number Sections
Markdown section headings are unnumbered. The exception: when the sections are a literal set of steps (a setup procedure, a multi-step migration), numbering makes the order load-bearing and is worth keeping.
Header Comment Blocks for Config Files
Source-controlled config files (workflow YAML, Terraform, Dockerfile, ...) start with a header comment block. Sections inside use ASCII dividers like ── Section Name ───────────. The block describes only what the file currently does, never what it might do later.
No Barrel Files
Don't create barrel files, an index.ts (or similar) whose only job is to re-export symbols from sibling modules. Always import each symbol directly from the module that defines it: import { isAllowed } from "./utils/action-validation", not import { isAllowed } from "./utils". Barrels hide where a symbol actually lives, make the import path say less than it could, and pull every re-exported module into the graph (and the bundle) whenever one of them is touched. Direct imports keep the source obvious and the dependency graph minimal.
Content
Explain the Why
Whenever a non-obvious choice is made (pinning an action to latest main, accepting a duplicate run on purpose, splitting a workflow into two files), document the reason in the doc or the comment near the code. A future reader should be able to judge whether the choice still applies.
Stay Scoped to What's Built
Don't document features, jobs, or sections that aren't implemented yet. If pass 1 releases test and build, the comment block for pass 1 talks about test and build, not the future terraform step. Use a separate "open questions" or "follow-ups" section for deferred work, never inline.
Remove Unused Content
A fixture file with no consumers, a doc reference to a file that no longer exists, a code path that no caller hits, delete it. Don't keep "just in case." If it becomes useful later, recover it from git.
Concrete Examples Over Abstract Descriptions
When documenting how something works, show the command, the file path, or the code sketch. Pseudocode and "imagine you have a..." are weaker than a real snippet that compiles.
Code
Separate Blocks with a Blank Line
Put a blank line after a block that ends with } (an if, for, while, switch, function, and so on) when another statement follows it. The blank line marks where one unit of logic ends and the next begins, so consecutive blocks don't read as one run-on wall. Skip it when the block is the last statement in its enclosing scope, or when the line continues the same statement (} else {, } catch {).
For example, two adjacent if statements run together:
if (condition) {
// do something
}
if (condition2) {
// do something
}
A blank line between them shows they are separate checks:
if (condition) {
// do something
}
if (condition2) {
// do something
}
Code Comments
Explain Non-Obvious Intent Only
Don't write comments that restate what the code already says. Write a comment when the code's purpose or constraint would surprise a reader: a workaround, an invariant, a deliberate inefficiency, a back-reference to an external requirement.
Keep Comments Short
Say it in as few words as the meaning allows. Cut filler like "the full rationale" or "in order to" and trailing throat-clearing. A comment that takes four lines to explain a one-line decision is too long; tighten it or move the detail to a doc.
Break Lines at Sentence or Clause Boundaries
Never wrap a comment in the middle of a phrase. Break at the end of a sentence, or at a natural clause boundary like a comma, so each line reads as a complete thought. "Owned in / this Terraform" splits a noun from its modifier; "It is created in this repo, / so the invoke permission can point at it" breaks where the sentence already pauses.
Be Concrete and Plain
Say the literal thing: what points at what, what would break, where something is created. Avoid vague gestures ("defined next to the grant", "handles the wiring") that make the reader guess. Avoid jargon that hides the meaning too; prefer "a user created somewhere else" over "a principal created outside Terraform". The language should be technical but plain, not overly technical.
For example, this comment is vague and wraps mid-phrase:
# IAM user whose static keys SomaHub uses to invoke action-router. Owned in
# this Terraform so the principal of the Lambda's invoke permission is known
# in advance and is defined next to the permission grant. See invoker/main.tf
# for the full rationale.
This one says the same thing concretely, breaks lines at clause boundaries, and is shorter:
# IAM user whose static keys SomaHub uses to invoke action-router.
# It is created in this repo so the invoke permission can point at this user's ARN,
# instead of a user created somewhere else. See invoker/main.tf for why.
Section Headers in Long Files
For files that grow long (a YAML workflow, a Terraform file), group related blocks under ASCII section headers like # ── Section Name ───────────. Keep the divider style consistent across files in the same project.
Pragmatism
Release in Passes
A first version that does less, completely, is better than a first version that does everything, badly. CI without deploy is releasable. A handler without real actions is releasable. Mark the rest as "pass 2" or "follow-ups" or "open questions" and move on.
Duplicate Before Abstracting
If two workflow files have the same test job, that's fine. If three handlers have the same retry helper, extract it. Two of something is not a pattern; three is.
Minimal First, Additions Later
For new features (a local server, a workflow, a doc section), implement the smallest useful version. Resist health endpoints, request timing logs, alternative invocation flags, multi-environment matrices, and similar bonus features until something explicitly needs them.