Skip to content
oss-kit
GitHubInstall

oss-writing

Agent instruction · canonical source

Technical register: neutral, specific, short. No personality injection, no marketing.

Before drafting, read the repository’s instructions, contribution guide, templates, nearby documents, and recent accepted examples of the same artifact. Local requirements decide commit structure, required pull request sections, terminology, line length, and audience. Preserve required template sections and legal or security wording. Verify every factual claim against the diff, source, command output, issue, or cited upstream source.

For commit messages, inspect git log --no-merges for the files in scope. If the repository requires Conventional Commits, use <type>[optional scope]: <description>, ! or a BREAKING CHANGE: footer for incompatible changes, and any required trailers. Do not infer a convention from this skill’s examples.

Sources: Git, Submitting patches, Conventional Commits 1.0.0, GitHub, Helping others review your changes, and Google developer documentation style guide.

Artifact Content
Commit The subject summarizes the change. The body explains the problem, intent, constraints, discarded alternatives, compatibility impact, and why this solution is appropriate. Skip implementation details the patch makes obvious.
Pull request State the purpose, user-visible or architectural result, important implementation boundary, risks, related context, and verification actually performed. For a large change, tell reviewers where to start.
Issue or bug report Give expected and observed behavior, minimal reproduction, relevant environment and versions, frequency or scope, and sanitized evidence. Separate facts from hypotheses.
Review comment Point to the concrete defect or question, explain its consequence, and state the required outcome. Use a suggestion block when the exact edit is known. Distinguish blocking findings from optional ideas.
ADR Record status, context, decision, rejected alternatives, consequences, and the conditions that would justify revisiting it.
Documentation Describe the current product for a defined audience and task. State prerequisites before steps, keep procedures ordered, and tell the reader how to verify the result.

Prose earns its place when it carries context the code or interface cannot:

  • the reason the behavior exists
  • the constraint that forced an unobvious choice
  • the alternative rejected and why
  • the compatibility, security, or operational consequence

A commit body that paraphrases the diff is noise. A pull request still needs an overview of the behavioral change so a reviewer can orient before reading the diff.

Length is not effort. Padding a trivial change into a structured document wastes the reader twice: once reading it, once distrusting the next one.

  • Subject line says everything? Write no body.
  • Headings earn their place when the reader needs to navigate, roughly past a screenful. A short PR body is two or three paragraphs, not ## Summary and ## Test plan.
  • Nothing was verified? Never imply that it was. If a template or the risk of the change calls for verification status, write Not run: <reason>.
  • A README section that repeats the code below it should be deleted, not rewritten.
Rule Do this
Prefer active voice parser drops trailing commas, not trailing commas are dropped. Keep passive voice when the actor is unknown, irrelevant, or would blame the reader.
Prefer positive form the cache expires after 60s, not the cache does not persist beyond 60s. Keep a negative requirement when prohibition is the point.
Specific and concrete fails on files over 2 MB, not fails on large inputs
Omit needless words Cut every word whose removal changes nothing
Related words together only the retry path calls this, not this is only called by the retry path
Emphatic word last End the sentence on the thing that matters
One topic per paragraph Each paragraph makes exactly one point
Parallel form Bullets in a list share one grammatical shape
Name the referent the loader caches the manifest, not it caches it. Replace it, this, and that with the noun when more than one antecedent is in scope
Cap noun stacks at three the timeout for the retry queue, not retry queue connection timeout value
One instruction per step A numbered step tells the reader to do one thing. Split a step that hides a second action behind and
Keep the articles the parser reads the file, not parser reads file. Dropping articles and sentence parts is false brevity: it saves two words and costs a reread

A sentence past roughly 20 words in an instruction, or 25 in an explanation, is a signal to split it, not a limit to count against.

Machine-written prose also carries a lexicon these rules do not cover: inflated significance, promotional adjectives, tacked-on -ing clauses, empty contrast, signposting, hedging stacks. When a draft reads as padded, generic, or promotional, check it against references/tells.md, which names each pattern and what to write instead.

Uppercase MUST, SHOULD, and MAY carry their RFC 2119 and RFC 8174 meanings, and only where the document says so in its own text. Use them in a specification, a rule statement, or a conformance section. Everywhere else write the plain verb: a README that shouts MUST at a reader has invented a requirement nobody is checking.

Check these before returning any text:

  • No em dashes, en dashes, or --: in short technical prose they are a reliable machine-written tell, and a period, comma, colon, or pair of parentheses carries the same break.
  • No emoji anywhere, including headings and bullets: their width and glyph vary by terminal and font, so they break alignment in the fixed-width contexts a repository lives in.
  • No inline-header bullet lists (- **Performance:** it is faster): the bolded stub replaces the sentence that would have said what changed, so the reader gets a label instead of a claim.
  • Headings in sentence case, not Title Case: it is what the Google developer style guide prescribes, and mixing the two inside one document reads as text assembled from two sources.
  • No recap section restating what the text just said: the reader just read it, and a recap marks text written to a length rather than to a point.
  • No Generated with, Co-Authored-By: Claude, or tool attribution footers: a trailer records who is accountable for the change, and a tool cannot be.
  • No boilerplate caveats. State a precondition, limitation, or risk when it changes what the reader should do: a caveat that changes nothing trains the reader to skip the one that matters.
  • Straight ASCII quotes: curly quotes break a copy-paste into a shell or a config file, and the reader cannot tell by eye which they got.
  • Existing quoted code, error strings, log output, stack traces, and config samples: reproduce verbatim, including their dashes. This exception does not protect newly authored strings from review.
  • Another person’s words in a quote or a review thread reply.
  • Identifier names, CLI flags, and file paths.
  • Required legal, license, and externally mandated security-advisory wording.
  • When editing prose a human wrote, fix only what is broken. Their voice is not a defect.

These come from writing the message as a session log rather than a description of the change:

  • One bullet per changed file, or a list of every path touched. The diff has that.
  • A test plan describing verification that never ran.
  • The body narrating your working process: what you tried, what failed, what you then did.
  • Restating the subject line as the first line of the body.

Both are read by someone who is already stuck, so they answer a different question than descriptive prose does.

  • An error or log line names what failed, the safe part of the input or location, and a likely corrective action: config.yaml line 7: timeout must be a positive integer, got -1. One distinct message per actionable condition. A log event also carries a stable event name, a severity, and the structured identifiers needed to find the operation again: request ID, safe path, count, duration. Measured fields, not adjectives. Never emit passwords, tokens, personal data, full request bodies, or unencoded attacker-controlled text.
  • A comment explains why the code is surprising, not what it does. If it restates the line below it, delete it. The case that earns a comment is a constraint the code cannot show: a spec section, a vendor bug, a benchmark that ruled out the obvious approach.

Use literal terms in their primary sense. Avoid idioms, slang, humor, violent metaphors, culture-specific references, and unexplained abbreviations. Keep one name per concept and match product and UI terminology exactly. Use descriptive link text that still makes sense out of context. Put conditions before instructions, and repeat a noun when the repetition removes ambiguity.

Bad: refactor(auth): improve token handling
This commit refactors the token handling logic to be more robust and
maintainable, updating the refresh function and error handling.
Good: fix(auth): refresh tokens 30s before expiry
Clock skew against the IdP reached 12s, so tokens refreshed exactly
at expiry were rejected about 1 in 400 times. 30s covers the
observed skew with margin, and the extra refresh cost is negligible.
Bad: ## Summary
- Added a new caching layer
- Updated the service to use it
This significantly improves performance and enhances the user
experience by reducing load times.
Good: Search results were recomputed on every keystroke, which pinned a CPU
core during peak hours. Results are now cached per normalized query
for 5 minutes.
The cache is in-process, so a deploy clears it. That is fine at one
replica, and needs Redis if we scale out.
Verified with bench/load.sh: p99 drops from 1.4s to 210ms.
Bad: Great catch on the null check! One small thing to consider: it might
potentially be worth thinking about concurrent access here.
Good: Two goroutines can reach this branch at once, so the map write races.
A sync.Map or a mutex around lines 40-48 fixes it.

R-DOC-05: Documentation prose is plain, active, and free of marketing language