diff --git a/.agents/guidelines/english-style.md b/.agents/guidelines/english-style.md new file mode 100644 index 00000000..c8df9173 --- /dev/null +++ b/.agents/guidelines/english-style.md @@ -0,0 +1,421 @@ +# English style + +Grammar, punctuation, and spelling rules for English prose in source-code +comments and documentation. Layout and flow rules live in the +[writer skill](../skills/writer/SKILL.md); this page covers the language itself. + +The catalog below is the single source of truth for three kinds of consumers: + +- **Fixers** — the `proofread` skill edits existing text, applying a fix + only when no leave-alone guard matches. +- **Reviewers** — documentation reviews flag catalog violations on changed lines. +- **Authors** — repository writing skills follow the same rules for new prose. + +## Principles + +1. **Fix errors, not taste.** Correct only what the catalog names as an + error. Do not reword sentences that are already correct, and do not + impose stylistic preferences the catalog does not state. +2. **Minimal edits.** Preserve the author's wording, meaning, and voice. + The smallest change that fixes the error wins. +3. **When uncertain, leave it and report it.** A missed error is cheaper than + a wrong fix. Record ambiguous occurrences for a human to decide rather than + editing them automatically. +4. **Never touch code or machine-read text.** See the per-language list below. +5. **Consistency is per file.** Where correct alternatives exist (spelling + dialect, serial comma), the unit of consistency is the file: align a + clear outlier with the file's dominant convention; when no convention + dominates, leave the text unchanged and report the mix. + +## Where English prose lives + +| Language | Prose to check | +|-------------------------|------------------------------------------------------------------------| +| Kotlin / Java | KDoc/Javadoc bodies and tag descriptions; block and line comments | +| Protobuf | `//` doc comments for types and fields, and file headers | +| TypeScript / JavaScript | TSDoc/JSDoc bodies and tag descriptions; block and line comments | +| Go | Doc comments immediately above declarations and other comments | +| Markdown / AsciiDoc | Body prose and headings | + +Within a doc comment, only the *description text* is prose. Tag machinery +is not: in `@param {string} userId The identifier of the user.`, only +"The identifier of the user." may be edited. + +## Never edit + +Some comment content is read by compilers and tools, or must stay verbatim for +other reasons. A purported fix there can change build behavior or break tooling. +Skip the following content: + +**In every language** + +- Code in any form: string literals, identifiers, fenced and indented code + blocks, inline code spans, `{@code}` / `{@literal}` tags, `
` /
+ `` HTML, `@sample` references, and documented commands.
+- License and copyright headers — they are generated from the copyright
+ profile and are outside project-owned prose.
+- Quoted text (quotations stay verbatim), URLs, email addresses, version
+ strings, and file paths.
+- The machine-read TODO prefix; the description after it is ordinary prose.
+- Editor and tool modelines (`// vim: …` and similar).
+
+**Kotlin / Java**
+
+- Inspection suppressions: `//noinspection …`.
+- Javadoc/KDoc reference targets: the arguments of `{@link}`,
+ `{@linkplain}`, and `@see`, and KDoc `[Symbol]` references.
+
+**Protobuf**
+
+- Lint directives such as `// buf:lint:ignore …`.
+
+**TypeScript / JavaScript**
+
+- Compiler directives: `// @ts-ignore`, `// @ts-expect-error`,
+ `// @ts-nocheck`, and `/// ` triple-slash directives.
+- Tool directives: `// eslint-disable*`, `// prettier-ignore`, coverage
+ markers (`/* istanbul ignore … */`, `/* c8 ignore … */`,
+ `/* v8 ignore … */`), webpack magic comments
+ (`/* webpackChunkName: … */`), and `//# sourceMappingURL=…`.
+- JSDoc machinery: tag names, `{Type}` braces, and parameter names.
+
+**Go**
+
+- Compiler and tool pragmas: any `//go:…` comment (`//go:build`,
+ `//go:generate`, `//go:embed`, `//go:linkname`, …), the legacy
+ `// +build` constraints, and `//nolint` directives. The absence of a
+ space after `//` marks a pragma — never "fix" that spacing.
+- cgo preambles: the comment block immediately above `import "C"` is
+ compiled C code, not prose.
+- The parsed `Deprecated:` marker word; its explanation is prose.
+- The leading identifier of a doc comment: godoc requires the comment to
+ start with the declared name (`// ServeHTTP handles …`). Never reword,
+ lowercase, or move it; the catalog applies from the second word on.
+
+**Markdown**
+
+- YAML front matter, link-reference definitions, badge markup, and HTML
+ comments used as directives (``,
+ ``).
+
+**AsciiDoc**
+
+- Document attributes (`:attribute-name: value`) and `include::` macros.
+- Conditional directives: `ifdef::`, `ifndef::`, `endif::`.
+- Delimited blocks — listing (`----`), literal (`....`), and `[source]`
+ blocks: the "fenced and indented code blocks" rule above covers Markdown
+ fencing, not these AsciiDoc delimiters.
+
+## Error catalog
+
+Fixers group their reports by the topic headings below.
+
+### Restrictive "which" vs. "that"
+
+As a project writing rule, use "that" for a relative clause that *restricts
+or identifies* its antecedent. Use "which", preceded by a comma, for a clause
+that merely *adds information*. Russian *который* covers both restrictive and
+non-restrictive senses, so direct transfer can blur this distinction.
+
+| Before | After |
+|--------------------------------|--------------------------------------------|
+| a plugin which forces versions | a plugin that forces versions |
+| the file, which is generated | the file, which is generated — leave alone |
+
+Replace "which" with "that", matching the original capitalization, only
+when **none** of these guards applies:
+
+- A comma (with optional whitespace) precedes "which" — non-restrictive.
+- An opening parenthesis or a dash precedes it: `(which …`, `— which …`,
+ `– which …`, `-- which …` — equally non-restrictive.
+- A preposition precedes it: "in which", "of which", "with which",
+ "by which", "to which", "at which", "from which", "on which",
+ "for which", "into which", "upon which", "under which", "within which",
+ "through which", "against which", "without which", and the like.
+- Interrogative or determiner use, direct or embedded: "Which plugin…?",
+ "decide which plugin", "depending on which mode", "no matter which", and
+ "which of the following".
+- Sentence-initial "Which".
+- A hyphen abuts it — kebab-case names such as `which-fixer` are
+ identifiers, not pronouns.
+- Fixed phrases: the fused relative "that which" and the idiom "which is which".
+
+### Articles
+
+Russian has no articles, so missing or wrong articles are the most common
+error class. Add the missing article inside full sentences; choose "a" vs.
+"an" by the *sound* that follows, not the letter.
+
+| Before | After |
+|------------------------------------------|-------------------------------------------------|
+| Returns value of given field. | Returns the value of the given field. |
+| Throws exception if file does not exist. | Throws an exception if the file does not exist. |
+| a HTTP request | an HTTP request |
+| an user, an unique key | a user, a unique key |
+| a SDK, an URL | an SDK, a URL |
+
+Leave alone:
+
+- Plural and uncountable nouns used generically: "returns metadata",
+ "handles errors", "provides support for logging".
+- Deliberately telegraphic contexts: headings, table cells, and changelog-style
+ list fragments. Articles are enforced only in full sentences.
+- Initialisms whose pronunciation varies: "a SQL query" (*sequel*) and
+ "an SQL query" (*es-cue-el*) are both correct — align with the file's
+ existing usage, otherwise leave.
+- Bare identifiers used as names need no article, as in
+ "Calls `close` after use".
+
+### Subject–verb agreement
+
+The verb agrees with the grammatical subject — watch the head noun of a
+long subject, and "there is/are".
+
+| Before | After |
+|-------------------------------------|------------------------------------|
+| The methods returns a copy. | The methods return a copy. |
+| Each of the listeners are notified. | Each of the listeners is notified. |
+| The list of errors are cleared. | The list of errors is cleared. |
+| There is several options. | There are several options. |
+
+Leave alone:
+
+- "data" as singular or plural — both are accepted in technical writing;
+ keep each file consistent.
+- A backticked identifier as a subject names one object regardless of its
+ grammatical number: "`options` holds the parsed flags." is correct.
+- "a number of X are …" and "the number of X is …" have different subjects, so
+ both forms are correct.
+
+### Verb form in API summaries
+
+The summary sentence of a function or method describes what the call does,
+in the third-person singular: "Returns …", "Creates …", "Validates …".
+An imperative opener is the error.
+
+| Before | After |
+|------------------------------------|-------------------------------------|
+| `/** Return the current state. */` | `/** Returns the current state. */` |
+| `// Copy copy the buffer.` (Go) | `// Copy copies the buffer.` (Go) |
+
+Leave alone:
+
+- Go's leading identifier (see **Never edit**); fix only its following verb.
+- Imperative mood where it is the local convention: step-by-step instructions,
+ tutorials, README commands, commit messages, and CLI help text.
+- Type summaries written as noun phrases ("A thread-safe cache of …") or
+ with "Represents …" — both correct.
+- "This method returns …" is wordy but not an error; leave the text unchanged.
+- A file that consistently uses another summary convention (imperative
+ summaries are common in some JavaScript codebases) — report the file
+ once instead of rewriting every summary.
+
+### Prepositions
+
+Fix only the pairs listed here; other verb–preposition pairings vary
+legitimately and stay unchanged.
+
+| Before | After |
+|-----------------------------------|-----------------------------------|
+| depends of | depends on |
+| independent from | independent of |
+| consists from | consists of |
+| capable to handle | capable of handling |
+| waits the result | waits for the result |
+| listens the event | listens to the event |
+| in runtime, in compile time | at runtime, at compile time |
+| on practice | in practice |
+| on the screenshot, on the diagram | in the screenshot, in the diagram |
+| typical for | typical of |
+| access of the file | access to the file |
+
+Leave alone:
+
+- Transitive verbs that take a direct object: "awaits the result",
+ "accesses the file", "enters the block", "discusses the design" are
+ correct without a preposition.
+- "listens for the event" — correct when the sense is awaiting a specific
+ occurrence rather than subscribing; do not swap "for" to "to".
+- Idioms: "in search of", "on the basis of".
+- Dialect-linked variants: "different from" (universal), "different to"
+ (British), "different than" (American, informal) — do not convert.
+
+### Verb complementation
+
+"Allow", "enable", and "permit" need an object before a to-infinitive;
+without one, use a gerund or rephrase. "Recommend" and "suggest" take a
+gerund, not a bare infinitive. (The Russian construction «позволяет сделать»
+can transfer as the ungrammatical "allows to do".)
+
+| Before | After |
+|-------------------------------|------------------------------|
+| allows to configure the build | allows configuring the build |
+| enables to run tests | enables running tests |
+| permits to access the field | permits access to the field |
+| We recommend to use the DSL. | We recommend using the DSL. |
+| suggest to add a test | suggest adding a test |
+| It is worth to note | It is worth noting |
+
+Leave alone:
+
+- An object is present: "allows the caller to configure …" is correct.
+- "allows for" + noun: "allows for customization" is correct.
+- "It is recommended to use …" is correct because the infinitive complements
+ the passive "recommended".
+- "helps (to) do" — both forms are correct.
+- "provides the possibility to …" — calque-flavored and wordy, but its
+ grammaticality is disputed rather than settled: prefer "makes it
+ possible to …" when writing new text, and report rather than auto-fix.
+
+### Comparatives
+
+A comparison carries its own function word: "greater **than** X", "equal
+**to** X". Coordinating the two keeps both — "greater than or equal to X".
+Dropping one or both yields "greater or equal X", a calque of the Russian
+«больше или равно X». This direct transfer omits the English function words
+because the Russian comparative instead governs the case of the noun.
+
+| Before | After |
+|--------------------------------------|--------------------------------------------|
+| the day is less or equal zero | the day is less than or equal to zero |
+| a value greater or equal the limit | a value greater than or equal to the limit |
+| the size is equal or greater than 10 | the size is greater than or equal to 10 |
+
+Leave alone:
+
+- "greater than or equal to" and "less than or equal to" — already complete.
+- Comparison operators inside code spans, such as `>=`, `<=`, and `a >= b`, are
+ code tokens rather than prose.
+- "no less than", "no more than", "at least", "at most" — idiomatic and
+ complete without "or equal".
+- "equals" used transitively: "the result equals zero" takes no "to".
+
+Writing "then" for "than" is a separate error — see *Confusables*.
+
+### Commas
+
+Only the mechanical cases below are errors; most comma placement remains the
+author's judgment and stays unchanged.
+
+| Before | After |
+|-------------------------------------------|-------------------------------------------|
+| If the file is missing the build fails. | If the file is missing, the build fails. |
+| The value is cached, it is computed once. | The value is cached; it is computed once. |
+| The value that is returned, is cached. | The value that is returned is cached. |
+
+- An **introductory subordinate clause** ("If …", "When …", "While …",
+ "Unless …", "Because …", "Although …" followed by a subject and verb)
+ takes a comma before the main clause. Short adverbial openers
+ ("By default", "In this case") conventionally take one too, but adding
+ it is optional — leave existing text alone.
+- A **comma splice** joins two independent clauses with a bare comma.
+ Prefer the minimal repair: a semicolon when the clauses are closely
+ related, otherwise a period.
+- **No comma between a subject and its verb**, however long the subject.
+- The **serial (Oxford) comma** is a style choice, not an error: keep each
+ list internally consistent, add one only when its absence is genuinely
+ ambiguous, and never churn existing lists.
+
+Leave alone: commas inside quoted text; the comma before "which" — the
+which/that topic owns that decision; and "e.g." and "i.e." with or without a
+following comma, which is dialect-linked.
+
+### Hyphenated compound modifiers
+
+Two words acting as one adjective *before* a noun are hyphenated.
+
+| Before | After |
+|---------------------------|---------------------------|
+| read only mode | read-only mode |
+| well known issue | well-known issue |
+| case sensitive comparison | case-sensitive comparison |
+| third party library | third-party library |
+| long running task | long-running task |
+
+Leave alone:
+
+- Predicative position — after the noun and a linking verb ("the mode is
+ read only") the hyphen is optional; do not edit either way.
+- Adverbs in "-ly" never hyphenate: "fully qualified name" and
+ "publicly available API" are correct.
+- A number with a unit symbol ("a 5 GiB limit") takes no hyphen by convention.
+
+### Confusables
+
+Word pairs that spell-checkers miss because both are real words.
+
+| Before | After |
+|--------------------------------------|---------------------------------------|
+| The method returns it's result. | The method returns its result. |
+| Let's you configure the build. | Lets you configure the build. |
+| This value maybe null. | This value may be null. |
+| more efficient then the default | more efficient than the default |
+| Use this method to setup the server. | Use this method to set up the server. |
+| Users can login with a token. | Users can log in with a token. |
+| The server can not recover. | The server cannot recover. |
+
+- The noun or adjective is one word; the verb is two: setup / set up,
+ login / log in, backup / back up, shutdown / shut down,
+ checkout / check out. ("Run the setup." vs. "Set up the server.")
+- "cannot" is the standard form; "can not" is reserved for the rare
+ emphatic "is able not to".
+- "e.g." (for example) vs. "i.e." (that is), and "affect" vs. "effect",
+ change meaning. Fix only when the context makes the intent unambiguous;
+ otherwise report the occurrence.
+
+### Punctuation and spacing
+
+| Before | After |
+|---------------------------|--------------------------|
+| `/** Returns the ID */` | `/** Returns the ID. */` |
+| the value.··The next step | the value.·The next step |
+| the value ; the next | the value; the next |
+| ends here.. | ends here. |
+| ( the default ) | (the default) |
+
+(`·` marks a space character.)
+
+- A doc-comment summary sentence ends with a period — Javadoc and Dokka
+ use it to delimit the summary.
+- One space between sentences; no space *before* `.`, `,`, `;`, `:`, `?`,
+ `!`; no space just inside parentheses or brackets in prose.
+- No duplicated terminal punctuation ("..", "!!", "??"). The three-dot
+ ellipsis "..." and the character "…" are legitimate; only a stray
+ two-dot sequence is a typo.
+- Sentences start with a capital letter — but **never change the case of
+ a code identifier** to achieve this. Reword instead: "`timeout` limits
+ the wait." → "The `timeout` value limits the wait."
+- Missing apostrophes in contractions are spelling errors, such as "dont" → "don't".
+- List items may be fragments without terminal periods — punctuate each
+ list consistently and leave the chosen style alone.
+
+### Spelling and dialect
+
+Fix genuine misspellings outright:
+
+| Before | After |
+|-----------------------------|------------------------------|
+| recieve, occured, seperate | receive, occurred, separate |
+| existance, paramter, lenght | existence, parameter, length |
+| successfull, usefull | successful, useful |
+| compatable, preferrable | compatible, preferable |
+
+For words where American and British English differ, **the unit of consistency is the file**:
+
+- A clear outlier aligns with the file's dominant dialect: one
+ "behaviour" in a file that otherwise writes "behavior" becomes
+ "behavior" — and vice versa.
+- When no dialect clearly dominates (the file is split), leave the text
+ unchanged and report the mix.
+- Judge dominance by strong markers: -or/-our (color/colour), -er/-re
+ (center/centre), the licence/license noun, gray/grey. Treat -ise/-ize
+ as a weak signal — British Oxford spelling legitimately uses "-ize", so
+ "-ize" beside "behaviour" is not an inconsistency.
+- Never change dialect in identifiers or code (a `Color` API stays
+ `Color`), in quoted text, in proper nouns, or in prose that names the
+ concept an identifier spells: a field called `colour` is described as
+ "the colour", whatever the file's dialect.
+
+There is no organization-wide dialect; if one is adopted later, the
+conversion becomes a separate, mechanical sweep.
+
diff --git a/.agents/guidelines/project-owned-files.md b/.agents/guidelines/project-owned-files.md
new file mode 100644
index 00000000..a50687e4
--- /dev/null
+++ b/.agents/guidelines/project-owned-files.md
@@ -0,0 +1,97 @@
+# Project-owned files
+
+## Rule for this repository
+
+This repository has no `.gitmodules`, so it has no submodule contents or
+`config`-distributed files to exclude. Treat every tracked path as
+project-owned, including root documentation, `.agents/`, `.github/`,
+`scripts/`, `showcase/`, and `test/resources/`.
+
+Do not apply the reusable skip rules below in this repository.
+
+## Why ownership matters
+
+Some skills edit or stamp files across a whole repository. For example,
+`proofread` rewrites prose. These skills must touch only the files the
+repository **owns**. Editing an upstream file is worse than a no-op: the
+next `./config/pull` (or submodule update) overwrites the change or turns it
+into a merge conflict, and the same edit is needed again.
+
+This page defines *project-owned* and the two kinds of upstream-owned paths to
+skip. Each consuming skill applies the rule to its file types; this page defines
+the shared mechanism, while the file filter remains in the consuming skill.
+
+## Reusable rules for repositories with submodules
+
+Apply these rules only when `.gitmodules` declares the relevant submodule.
+Determine submodule ownership from `.gitmodules`, never from a directory name.
+A repository does **not** own the two kinds of tracked files below. Skip them
+in every mode: full sweeps, scoped sweeps, and incremental branch-diff runs alike.
+
+### 1. Submodule contents
+
+Skip every path declared as a submodule in `.gitmodules`, and everything
+beneath it — the `config` submodule (usually `config/`), the shared-agents
+submodule at `.agents/shared`, and any others a repo adds (for example
+`BuildSpeed/`, or example projects mounted under `docs/`).
+
+When a skill enumerates files with `git ls-files`, submodules are already
+excluded — a submodule appears to the parent repo as a single gitlink, not
+as its files. Apply the skip explicitly anyway, so a diff-based run (which
+lists changed *paths*) drops a submodule entry the same way.
+
+### 2. Files distributed by the `config` repository
+
+When a repository consumes `config` (its `.gitmodules` declares a submodule
+with `path = config`), `config`'s `migrate` step copies shared files *out
+of* the submodule into the project tree, where they become ordinary tracked
+files. `git ls-files` and `git diff` therefore surface them even though the
+project does not own them, and `./config/pull` overwrites them on every pull.
+
+Skip the config-distributed set below. A consuming skill only encounters
+the members that match its own file filter — a prose skill meets the
+Markdown and source members; a header-stamping skill meets the
+copyright-bearing members — so each skill skips the relevant subset without
+needing its own copy of this list.
+
+- **`buildSrc/`** — the entire Gradle build-logic tree (hundreds of Kotlin
+ files with KDoc); by far the largest source of false edits.
+ **Exception:** `buildSrc/src/main/kotlin/module.gradle.kts` is
+ project-owned — `migrate` saves and restores it, so `./config/pull` never
+ overwrites it. Only that exact file is project-owned; its
+ `*-module.gradle.kts` siblings (for example `jvm-module.gradle.kts`) *are*
+ distributed and stay skipped.
+- **Root documentation** — `AGENTS.md`, `CLAUDE.md`, `CODE_OF_CONDUCT.md`.
+- **Root configuration** — `gradle.properties`, `.codecov.yml`, `lychee.toml`.
+- **Agent and IDE files** — `.junie/guidelines.md`,
+ `.github/copilot-instructions.md`, and `.idea/`.
+- **`.github/workflows/`** when the `config` submodule carries a
+ workflow of the same basename in its `.github/workflows/` (or
+ `.github-workflows/`) directory. Repo-specific workflows — including
+ variants that replace a distributed workflow via a `config:replaces`
+ directive and so ship under a different basename — stay project-owned.
+ When the submodule is not checked out, the comparison is impossible; treat
+ the workflow as project-owned.
+- **`CONTRIBUTING.md`** only when it is the unmodified org-wide copy —
+ byte-for-byte identical to the submodule's `config/CONTRIBUTING.md`.
+ `config` writes it **only into a repo that lacks one** (an
+ *initialize if absent* step), so a repo shipping its own contributor
+ guide owns it. If it differs, or the `config` submodule is not checked
+ out so you cannot confirm, treat it as project-owned.
+
+This set mirrors what `config`'s `migrate` script copies. If that script
+changes what it distributes, update this page (and any skill that encodes
+the set in a script) to match.
+
+## The `config` and `agents` source repositories
+
+The `config` and `agents` repositories declare no `config` submodule, so rule 2
+is inert there: their own `AGENTS.md`, `buildSrc/`, `gradle.properties`, and the
+rest are project-owned and stay in scope. This is correct: a fix or stamp must
+originate at the source that floats to every consumer.
+
+Do **not** instead skip a path merely because a same-named file exists
+under the `config/` submodule. `config` carries files it does *not*
+distribute (for example its own `README.md`), and skipping by name would
+wrongly exclude a project's own `README.md`.
+
diff --git a/.agents/skills/README.md b/.agents/skills/README.md
index 3eef978e..af4fa222 100644
--- a/.agents/skills/README.md
+++ b/.agents/skills/README.md
@@ -8,3 +8,5 @@ the routing source of truth.
- `writer`: documentation authoring, editing, restructuring, and claim checks.
- `review-docs`: documentation review for prose, examples, comments, and
agent instructions.
+- `proofread`: English grammar, punctuation, and spelling fixes in
+ project-owned comments and documentation.
diff --git a/.agents/skills/proofread/SKILL.md b/.agents/skills/proofread/SKILL.md
new file mode 100644
index 00000000..4083bf9d
--- /dev/null
+++ b/.agents/skills/proofread/SKILL.md
@@ -0,0 +1,134 @@
+---
+name: proofread
+description: >-
+ Use when proofreading project-owned comments or documentation for English
+ grammar, punctuation, and spelling. Follow the shared English catalog,
+ preserve code and machine-read text, and report ambiguous cases instead of guessing.
+---
+
+# Proofread
+
+Fix English-language errors in the prose of comments and documentation,
+applying the catalog in `.agents/guidelines/english-style.md`. That
+guideline is the single source of truth for *what* is an error and *when*
+to leave an occurrence alone; this skill is the *how* — scoping, scanning,
+and reporting. Do not restate or reinterpret the catalog's rules; follow them.
+
+The guiding bias is the catalog's own: **a missed error is cheaper than a
+wrong fix.** When a fix is not clearly correct, leave the text and report it.
+
+## Workflow
+
+1. **Choose the mode from the caller's argument.**
+ - **No argument → branch-diff mode.** Scan only the files changed on the
+ current branch, *including uncommitted and brand-new edits* — agents
+ here often work before an explicit commit, so a committed-only diff
+ would miss the very comments under review. Resolve a base ref, then take
+ the union of three lists:
+ - `git diff --name-only --diff-filter=ACMR ...HEAD` — committed
+ changes since the branch diverged from ` ` (three-dot, not a
+ tip-to-tip diff);
+ - `git diff --name-only --diff-filter=ACMR HEAD` — staged and unstaged
+ edits to tracked files; and
+ - `git ls-files --others --exclude-standard` — untracked, non-ignored
+ files (brand-new prose not yet `git add`ed).
+
+ Resolve ` ` to the first ref that exists: `origin/master`, else
+ `master`. `origin/master` is the base used across this repo's skills and
+ resolves in most clones and CI; the `master` fallback covers a checkout
+ that fetched only `master` with no remote-tracking ref. If neither
+ resolves, use the two working-tree lists alone and note the missing base
+ in the report. `--diff-filter=ACMR` excludes deleted paths, so step 3
+ never reads a file that no longer exists.
+ On a stacked branch, this fallback can include changes inherited from a
+ parent branch. Use path mode when a path cleanly isolates this branch's
+ prose; otherwise review the expanded file list before editing.
+ - **Argument is exactly `all` → full-sweep mode.** Scan every
+ project-owned file in the repository. Enumerate candidates with
+ `git ls-files`. (To scope a directory literally named `all`, pass it
+ as `./all`.)
+ - **Argument is a path → scoped-sweep mode.** Scan the project-owned
+ files under that directory or file: `git ls-files -- `. Use this
+ to stage a full sweep over a very large repository one module at a time.
+
+2. **Identify target files.** Apply this file-type filter in every mode:
+ - `**/*.kt`, `**/*.kts`, `**/*.java` — Kotlin and Java
+ - `**/*.proto` — Protobuf
+ - `**/*.ts`, `**/*.tsx`, `**/*.js`, `**/*.jsx`, `**/*.mjs`, `**/*.cjs`
+ — TypeScript and JavaScript
+ - `**/*.go` — Go
+ - `**/*.md` — Markdown
+ - `**/*.adoc` — AsciiDoc
+
+ In full-sweep and scoped-sweep modes, scan **git-tracked files only**:
+ `git ls-files` lists tracked files, so untracked build output and ignored
+ artifacts stay out; as a safeguard, also drop any `build/` and `.gradle/`
+ paths explicitly. In branch-diff mode, the step-1 list already includes
+ untracked, non-ignored files (new prose not yet `git add`ed) alongside tracked
+ changes. Keep them, then intersect the whole list with the file-type filter.
+
+ **Apply the repository-specific ownership conclusion.** This repository has
+ no `.gitmodules`, so it has no project-ownership exclusions. Keep every
+ candidate that survives the file filter, including root documentation,
+ agent guidance, showcase pages, test fixtures, and eligible Go source files.
+
+ If this skill is reused in another repository, follow
+ `.agents/guidelines/project-owned-files.md`. Drop submodule contents only
+ when `.gitmodules` declares them, and drop `config`-distributed files only
+ when `.gitmodules` declares the `config` submodule.
+
+3. **Scan and fix each file.** Restrict edits to **prose only**, per the
+ “Where English prose lives” and “Never edit” sections of
+ `.agents/guidelines/english-style.md`:
+ - In `.kt`, `.kts`, `.java`, `.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`,
+ `.cjs`, `.go`, and `.proto` files, edit only comment text — KDoc,
+ Javadoc, TSDoc, JSDoc, Go doc comments, block comments, and line
+ comments. Leave every string literal, identifier, and executable token untouched.
+ - In `.md` and `.adoc` files, edit only body prose and headings.
+ - In both, skip every code form (fenced and inline code, `{@code}` /
+ `` blocks, `@sample` references) and every machine-read comment
+ directive named under “Never edit” — Go pragmas (`//go:…`, `// +build`,
+ `Deprecated:`, the leading identifier of a doc comment), TS/JS
+ directives (`// @ts-…`, `// eslint-…`, `// prettier-ignore`, coverage
+ and webpack magic comments, triple-slash references), Protobuf
+ `// buf:lint:ignore`, Kotlin/Java `//noinspection` and doc-link
+ targets, copyright headers, and the machine-read TODO prefix.
+
+ Within the prose, apply **every topic** in the catalog's error catalog,
+ making the fix only when no leave-alone guard for that topic matches.
+ Keep edits minimal — the smallest change that fixes the error, preserving
+ the author's wording and voice. Apply per-file consistency (spelling
+ dialect, serial comma) as the catalog's principle 5 specifies.
+
+ Apply edits in place, file by file, batching a file's occurrences into
+ one edit per file rather than one edit per occurrence.
+
+ **When uncertain** whether a given occurrence is an error, leave it
+ unchanged and add it to `Skipped[]` with the catalog topic and reason
+ `ambiguous` (see **Report**).
+
+4. **Report.** Produce the summary in the **Report** section below.
+
+## Repo notes
+
+- The catalog and its rationale live in `.agents/guidelines/english-style.md`;
+ the project-owned scoping lives in `.agents/guidelines/project-owned-files.md`.
+ This skill adds no independent rules.
+- Prefer a missed case over a wrong fix. If a sentence is ambiguous, record
+ it in `Skipped[]` and let a human decide.
+- For large repositories in full-sweep mode, process files directory by
+ directory to stay within context limits. The path argument stages the
+ same work across sessions.
+
+## Report
+
+Return:
+
+- `Mode` — `branch-diff` | `all` | `path:`
+- `FilesScanned`, `FilesChanged`
+- `Changes[]` grouped by catalog topic; each entry: file, line, before → after
+- `Skipped[]` — file, line, catalog topic, reason (usually `ambiguous`)
+
+Grouping `Changes[]` by catalog topic is the learning loop: it shows which
+error classes recur, which feeds back into the catalog.
+
diff --git a/.agents/skills/proofread/agents/openai.yaml b/.agents/skills/proofread/agents/openai.yaml
new file mode 100644
index 00000000..09deabd3
--- /dev/null
+++ b/.agents/skills/proofread/agents/openai.yaml
@@ -0,0 +1,9 @@
+interface:
+ display_name: "Proofread"
+ short_description: "Proofread comments and docs against the English catalog"
+ default_prompt: >-
+ Use $proofread to fix English grammar, punctuation, and spelling errors in
+ the comments and documentation of this repository. Pass `all` for a full
+ sweep, a path to scope the review, or no argument to check the current
+ branch's changes.
+
diff --git a/.claude/commands/proofread.md b/.claude/commands/proofread.md
new file mode 100644
index 00000000..2cf9aa60
--- /dev/null
+++ b/.claude/commands/proofread.md
@@ -0,0 +1,14 @@
+---
+description: >
+ Fix English grammar, punctuation, and spelling errors in the comments and
+ documentation of this repository, per the shared error catalog.
+argument-hint: "[all | ]"
+allowed-tools: >-
+ Read, Edit, Grep, Glob, Bash(git diff:*), Bash(git ls-files:*),
+ Bash(git status:*), Bash(cmp:*)
+model: sonnet
+---
+
+Follow the [proofread skill](../../.agents/skills/proofread/SKILL.md) exactly,
+passing `$ARGUMENTS` as its argument.
+
diff --git a/AGENTS.md b/AGENTS.md
index 9f1e4795..42e43835 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -9,6 +9,8 @@ agent operating policy and repository-wide rules.
- Read [PROJECT.md](PROJECT.md) for the project overview and project map.
- Use matching discovered skills when they are available. Each skill's
frontmatter is the routing source of truth.
+- Run `golangci-lint run ./...` before handing off any workspace changes. Do
+ not consider a task complete while the linter reports failures.
- Ask clarifying questions before implementation, review, or documentation work
when scope, acceptance criteria, or constraints are not explicit.
- Never create commits, push, tag, merge, rebase, cherry-pick, or rewrite Git
diff --git a/PROJECT.md b/PROJECT.md
index 658add55..f4a1efa8 100644
--- a/PROJECT.md
+++ b/PROJECT.md
@@ -49,6 +49,11 @@ them inside code fences, and checks whether existing snippets are up-to-date.
- `PROJECT.md`: project map, package ownership, documentation ownership, and CI
notes for contributors and agents.
- `AGENTS.md`: repository operating policy for agents.
+- `.agents/skills/`: repository-specific implementation, testing, writing,
+ review, and proofreading workflows.
+- `.agents/guidelines/`: shared English-language and file-ownership rules
+ used by repository skills.
+- `.claude/commands/`: thin command delegates to repository skills.
Keep usage details in the showcase. Keep architecture and ownership details in
this file. Keep the root README short.
diff --git a/README.md b/README.md
index 16f67086..21a5a97f 100644
--- a/README.md
+++ b/README.md
@@ -84,12 +84,12 @@ require a language compiler or parser.
## Gradle Plugin
Gradle users can apply the [Embed Code Gradle plugin][gradle-plugin] to download
-the released executable for their platform and add tasks that check and embed
+the released executable for their platform and add tasks that check and embed
code snippets.
## Download
-Download the asset for your platform from [GitHub Releases][releases].
+Download the asset for your platform from [GitHub Releases][releases].
You do not need to install Go to use a release binary.
| Platform | Release asset | Executable |
@@ -101,15 +101,15 @@ You do not need to install Go to use a release binary.
## Build From Source
-Using Embed Code does not require Go.
+Using Embed Code does not require Go.
To build the application from this repository, install Go `1.26.4` and run:
```bash
go build -trimpath -o embed-code main.go
```
-This creates an executable named `embed-code`.
-On Windows, use`-o embed-code.exe` to give it the standard `.exe` suffix.
+This creates an executable named `embed-code`.
+On Windows, use `-o embed-code.exe` to give it the standard `.exe` suffix.
The `-trimpath` flag prevents local absolute paths from appearing in stack traces.
You can also run the application directly from the source checkout:
diff --git a/cli/cli.go b/cli/cli.go
index 1e1b46ad..cce39f9c 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -43,7 +43,7 @@ import (
// Config contains user-specified embed-code settings.
type Config struct {
- // BaseCodePaths contains directories with source code files.
+ // BaseCodePaths contains directories with source-code files.
BaseCodePaths _type.NamedPathList `yaml:"code-path"`
// BaseDocsPath is the root directory containing documentation files.
@@ -82,7 +82,7 @@ type EmbeddingConfig struct {
// Name identifies the embedding target.
Name string `yaml:"name"`
- // CodePaths contains directories with source code files.
+ // CodePaths contains directories with source-code files.
CodePaths _type.NamedPathList `yaml:"code-path"`
// DocsPath is the root directory containing documentation files.
diff --git a/cli/cli_validation.go b/cli/cli_validation.go
index 6748ee98..fc1c6a4d 100644
--- a/cli/cli_validation.go
+++ b/cli/cli_validation.go
@@ -40,7 +40,7 @@ import (
// IllegalFolderNameChars contains characters that are not allowed in folder names.
const IllegalFolderNameChars = `/\ *?:"<>|`
-// IsUsingConfigFile reports whether user configs are set with file.
+// IsUsingConfigFile reports whether user configs are set with a file.
//
// Parameters:
// config - provides user CLI settings.
diff --git a/configuration/configuration.go b/configuration/configuration.go
index 1c6ba949..68a75eb7 100644
--- a/configuration/configuration.go
+++ b/configuration/configuration.go
@@ -42,7 +42,7 @@ var DefaultDocIncludes = []string{"**/*.md", "**/*.html"}
// Configuration contains embed-code processing settings.
//
// It is used to get data for scanning docs and resolving source files.
-// The example of creating the Configuration with default values:
+// An example of creating the Configuration with default values:
//
// var config = configuration.NewConfiguration()
type Configuration struct {
diff --git a/embedding/commentfilter/filter.go b/embedding/commentfilter/filter.go
index 259791f6..1de268ce 100644
--- a/embedding/commentfilter/filter.go
+++ b/embedding/commentfilter/filter.go
@@ -37,7 +37,7 @@ import (
// EmbeddingCommentFilter filters comments for one embed-code instruction.
type EmbeddingCommentFilter struct {
- // filePath is the path to the source code file.
+ // filePath is the path to the source-code file.
filePath string
// embeddingDocPath is the path to the documentation containing the instruction.
diff --git a/embedding/parsing/constants.go b/embedding/parsing/constants.go
index 2b75a5ad..bb69fd82 100644
--- a/embedding/parsing/constants.go
+++ b/embedding/parsing/constants.go
@@ -26,7 +26,7 @@
package parsing
-// EmbeddingTag is a name of a tag which marks where to embed the code.
+// EmbeddingTag is a name of a tag that marks where to embed the code.
const EmbeddingTag = "embed-code"
// TransitionMap is a type for mapping one State to a list of possible next States.
diff --git a/embedding/parsing/state.go b/embedding/parsing/state.go
index 4c38add3..2420a827 100644
--- a/embedding/parsing/state.go
+++ b/embedding/parsing/state.go
@@ -30,7 +30,7 @@ import (
"embed-code/embed-code-go/configuration"
)
-// State represent a transition of a single line in the parsing process.
+// State represents a transition of a single line in the parsing process.
type State interface {
// Accept updates the parsing context based on the transition.
diff --git a/embedding/processor.go b/embedding/processor.go
index 749e987e..c3fdf150 100644
--- a/embedding/processor.go
+++ b/embedding/processor.go
@@ -109,7 +109,7 @@ func newProcessor(
}
}
-// Embed constructs embedding and modifies the doc file if embedding is needed.
+// Embed constructs an embedding and modifies the doc file if embedding is needed.
//
// Returns:
// *parsing.Context - parsing context, empty when the file is excluded by configuration.
diff --git a/files/files.go b/files/files.go
index 553dd2c0..4d5a5f94 100644
--- a/files/files.go
+++ b/files/files.go
@@ -96,7 +96,7 @@ func IsDirExist(path string) (bool, error) {
return false, nil
}
-// Reports whether the given path is valid and exist in the file system. Also returns a FileInfo if
+// Reports whether the given path is valid and exists in the file system. Also returns a FileInfo if
// the path (relative or absolute) exists.
func validatePathExists(path string) (bool, os.FileInfo, error) {
// Getting matches for the given path if it is a glob format. Otherwise, does nothing.
diff --git a/fragmentation/partition.go b/fragmentation/partition.go
index 2d864160..816dbe77 100644
--- a/fragmentation/partition.go
+++ b/fragmentation/partition.go
@@ -44,7 +44,7 @@ type Partition struct {
// NewPartition returns a Partition with both positions unset as -1.
//
-// Returns empty partition ready to receive start and end positions.
+// Returns an empty partition ready to receive start and end positions.
func NewPartition() Partition {
return Partition{
-1,
@@ -52,7 +52,7 @@ func NewPartition() Partition {
}
}
-// Select returns the partition-related lines from given lines.
+// Select returns the partition-related lines from the given lines.
//
// Parameters:
// lines - provides source lines indexed by StartPosition and EndPosition.
diff --git a/indent/indent.go b/indent/indent.go
index e4edb22b..8f7ecd06 100644
--- a/indent/indent.go
+++ b/indent/indent.go
@@ -31,7 +31,7 @@ import (
"strings"
)
-// MaxCommonIndentation finds the maximal common indentation of given lines.
+// MaxCommonIndentation finds the maximal common indentation of the given lines.
//
// Parameters:
// lines - provides source lines to inspect.
@@ -56,7 +56,7 @@ func MaxCommonIndentation(lines []string) int {
return indent
}
-// CutIndent reduces indentation to given redundantSpaces amount.
+// CutIndent reduces indentation to the given redundantSpaces amount.
//
// It copies lines before trimming, so the input slice is not modified.
// If a line is shorter than redundantSpaces, the whole line is removed.
diff --git a/main.go b/main.go
index f71bd5b3..d2712a3d 100644
--- a/main.go
+++ b/main.go
@@ -47,7 +47,7 @@ var Version = strings.TrimSpace(versionFile)
// The entry point for embed-code.
//
-// There are two modes, which are chosen by 'mode' arg. If it is set to 'check',
+// There are two modes, which are chosen by the 'mode' arg. If it is set to 'check',
// then the checking for up-to-date is performed. If it is set to 'embed',
// the embedding is performed.
//
@@ -60,7 +60,7 @@ var Version = strings.TrimSpace(versionFile)
// Checking for up-to-date is the process that consists of the following steps:
// - the code fragments are extracted from the code files;
// - the docs files are scanned for tags;
-// - for each tag, the code fragments are compared to the code which is already embedded
+// - for each tag, the code fragments are compared to the code that is already embedded
// into the docs;
// - if there is a difference, the error is reported.
//
@@ -73,14 +73,14 @@ var Version = strings.TrimSpace(versionFile)
//
// If both options are missed, the embedding fails.
// If both options are set, the embedding fails as well.
-// If config file does not exist, or contains neither root 'code-path' and 'docs-path' fields nor
-// 'embeddings' entries, the embedding fails.
+// If the config file does not exist, or contains neither root 'code-path' and 'docs-path'
+// fields nor 'embeddings' entries, the embedding fails.
//
// All possible args:
// - code-path — a path to a root directory with code files;
// - docs-path — a path to a root directory with docs files;
// - config-path — a path to a yaml configuration file;
-// - mode — string which represents the mode of embed-code execution. If it is set to 'check',
+// - mode — string that represents the mode of embed-code execution. If it is set to 'check',
// then the checking for up-to-date is performed. If it is set to 'embed', the embedding
// is performed.
// - doc-includes — a comma-separated string of glob patterns for docs files to include.
@@ -90,7 +90,7 @@ var Version = strings.TrimSpace(versionFile)
// the embedding.
// For example:
// "old-docs/**/*.md,old-guides/*.html". It is not set by default;
-// - separator — a string which is used as a separator between code fragments. Default value
+// - separator — a string that is used as a separator between code fragments. Default value
// is "...".
// - info — a flag that enables info-level logs;
// - stacktrace — a flag that enables stack traces in panic logs.
diff --git a/showcase/configuration/README.md b/showcase/configuration/README.md
index d205e87f..9ad4ef58 100644
--- a/showcase/configuration/README.md
+++ b/showcase/configuration/README.md
@@ -15,7 +15,7 @@ one of these ways:
Do not combine direct roots with `-config-path`.
-Source roots can contain any text files that your documentation embeds.
+Source roots can contain any text files that your documentation embeds.
The examples use Java, Kotlin, and plain text so the configuration stays independent
of the programming language used by the project.
diff --git a/showcase/embedding/positive/named-source-root.md b/showcase/embedding/positive/named-source-root.md
index 5dc6edc1..8554c6ab 100644
--- a/showcase/embedding/positive/named-source-root.md
+++ b/showcase/embedding/positive/named-source-root.md
@@ -6,7 +6,7 @@ configured root happens to contain a matching relative path.
## How It Works
-In config file, each entry in `code-path` can have a `name` and a `path`.
+In the config file, each entry in `code-path` can have a `name` and a `path`.
When an instruction starts its `file` value with `$name/`, embed-code selects
only that named root and then resolves the remaining relative path inside it.
diff --git a/showcase/quick-start/README.md b/showcase/quick-start/README.md
index 3f429b0e..2c9c90b6 100644
--- a/showcase/quick-start/README.md
+++ b/showcase/quick-start/README.md
@@ -10,7 +10,7 @@ This folder is the smallest runnable Embed Code application setup. It contains:
Download the latest release for your platform from
[GitHub Releases](https://github.com/SpineEventEngine/embed-code-go/releases).
-Extract binary file from archive, if necessary, and place it to the `quick-start` folder.
+Extract the binary file from the archive, if necessary, and place it to the `quick-start` folder.
Open this folder before running the example:
@@ -65,8 +65,8 @@ followed by a managed code fence:
````
The `file` value is a relative path resolved from `code-path`, so this instruction reads
-[source/com/example/Greeting.java](source/com/example/Greeting.java).
-Embed mode writes the current source content into the managed fence.
+[source/com/example/Greeting.java](source/com/example/Greeting.java).
+Embed mode writes the current source content into the managed fence.
Check mode verifies that the fence is already up-to-date.
For more source/target configuration see [Configuration guide](../configuration/README.md).