write-discoverable-code
/write-discoverable-code
Write code that is easy to find with text search and understand in context. Use when writing, reviewing, or refactoring code, especially names, module boundaries, types, doc comments, and diagnostic messages.
- Author
- luxass ↗
- Repository
- agent-skills ↗
- Licence
- MIT
- Last repository change
- 09.11.2026
Assessment and security
- Files in this package
- 2
- Scripts
- 0
- HTML comments
- 0
- URLs in SKILL.md
- 0
No signals detected. Repository changed on 09.11.2026, without references to retired models or APIs.
MIT, open: use and modify while retaining author attribution.
What it does and when to use it
Write code that is easy to find with text search and understand in context. Use when writing, reviewing, or refactoring code, especially names, module boundaries, types, doc comments, and diagnostic messages.
Original author description
Write code that is easy to find with text search and understand in context. Use when writing, reviewing, or refactoring code, especially names, module boundaries, types, doc comments, and diagnostic messages.
How it works
- Naming
- Files and modules
- Types
- Comments and strings
- Before you commit
SKILL.md preview
---
name: write-discoverable-code
description: Write code that is easy to find with text search and understand in context. Use when writing, reviewing, or refactoring code, especially names, module boundaries, types, doc comments, and diagnostic messages.
---
# Write discoverable code
Most readers of a codebase, human or agent, find code the same way: they search for a
word, open the file at the hit, and read a few dozen lines around it. Agents lean on this
even harder, because they rarely have hover info, go-to-definition, or memory of the last
session. Every rule below has one goal: **the first search should land on the right line.**
## Naming
### Name exports so they are unique across the repo
A name is a search query someone will type later. Short generic names return pages of hits.
```ts
// Bad: "parse" matches hundreds of lines
export function parse(input: string) {}
// Good: one search, one hit
export function parseInvoiceCsv(input: string) {}
```
- Aim for two to four words, and include at least one word from the domain
(`invoice`, `webhook`, `tenant`).
- Stop when the name is unique. `parseInvoiceCsvFromUploadedFileForBilling` is too far.
Put the extra detail in the doc comment.
- Before you add a name, search for it. If it already exists elsewhere, pick another one.
### Do not let the folder carry the meaning
`billing/format.ts` and `reports/format.ts` can both export `formatAmount`. A search hit
shows the line, not the folder, so the reader can't tell them apart. Put the context in
the symbol: `formatBillingAmount`, `formatReportAmount`.
The exception is a strict, repo-wide convention where every file in a known place exports
the same names, such as route handlers that each export `GET` and `POST`.
### Use one word for one concept
If the codebase says `workspace`, do not add `project` for the same thing. If it says
`accountId`, do not add `acctId`. Each synonym splits future searches in two. Before you
name something, check what the surrounding code already calls it.
### Rename when meaning changes
If a function's behavior, inputs, or callers change, update its name in the same change.
That includes visibility: a `_internal` helper that other modules now import needs a
public name.
### Keep one copy of each function
Do not copy a function to a second file. Move it, update the imports, and delete the old
one in the same change. A search that finds two near-identical definitions forces the
reader to diff them.
## Files and modules
### Give files domain names
Generic file names like `utils.ts`, `helpers.ts`, `types.ts`, or `constants.ts` appear in
every package, so they tell a reader nothing. Prefer `invoice-totals.ts` over `utils.ts`.
Follow the framework when it requires a fixed name: `page.tsx`, `route.ts`, `mod.rs`,
`__init__.py`, and `index.ts` used only to re-export are fine.
### One question, one file
If someone asks "where do we retry failed webhooks?", the answer should be a file named for
that, such as `webhook-retry.ts`. It should not be line 400 of a `WebhookService` class.
- Keep coordinators short. A pipeline or service should read as a list of calls into
well-named modules.
- Do not overcorrect. A small helper used by only one module can stay in that module.
Splitting every function into its own file scatters one answer across many reads.
### Keep tests near the code
Where the ecosystem allows it, put `invoice-totals.test.ts` next to `invoice-totals.ts`.
A search for the name then finds both the code and its expected behavior.
## Types
### Make wrong calls fail to compile
Two plain `string` IDs can be swapped with no error. Brand them so the compiler catches it.
```ts
type AccountId = string & { readonly __brand: "AccountId" };
type InvoiceId = string & { readonly __brand: "InvoiceId" };
function voidInvoice(accountId: AccountId, invoiceId: InvoiceId) {}
```
Use your validation library's brand helper if you have one (`z.string().brand<"AccountId">()`
in Zod, a newtype in Rust). If a function takes two values of the same type, such as
`fromAccountId` and `toAccountId`, use an options object so each one has a label at the call site.
### Encode permissions and states in types
- For privileged operations, require a parameter type that proves the caller is allowed,
for example `TenantScopedDb` instead of a raw database client.
- Model states as a discriminated union (`{ status: "paid"; paidAt: Date } | { status: "open" }`)
instead of several optional fields with unwritten rules.
### Choose type names for error messages
Type names show up in compiler errors, and agents fix code by reading those errors.
`TenantScopedDb` tells the reader what went wrong; `Ctx2` does not. Avoid `any`, because it
turns those errors off.
## Comments and strings
### Write a one-line doc comment on every export
Say the one thing the signature cannot: units, time zone, who owns the data, what order
results come in.
Use plain, spaced-out words, because people search in phrases. A search for
"invoice total" does not match `computeInvoiceTotal`, but it matches this comment:
```ts
/** Computes the invoice total in cents, including tax. */
export function computeInvoiceTotal(invoice: Invoice): number {}
```
### Write searchable strings in full
Event names, feature flags, and error codes must appear in the source exactly as they
appear in logs and dashboards.
```ts
// Bad: nobody can search for "invoice.paid"
emit(`invoice.${status}`);
// Good
emit(status === "paid" ? "invoice.paid" : "invoice.voided");
```
### Start every error message with a fixed phrase
Put the variable parts at the end, so a message copied from a log leads straight to the
`throw`:
```ts
throw new Error(`Invoice total mismatch: expected ${expected}, got ${actual}`);
```
### Mark old paths
When you replace something, mark the old one `@deprecated` and name the replacement.
## Before you commit
- [ ] Does a search for each new export return its definition first?
- [ ] Would swapping two arguments of a new function cause a type error?
- [ ] Does each new export's doc comment say what the signature cannot?
- [ ] Does every log line, event name, and error message appear in full in the source?
- [ ] Did you rename everything whose behavior changed?
- [ ] After moving code, is the old copy gone?
Files in this package (2)
- LICENSE 1 KB
- SKILL.md 6 KB
Versions
| Repository | Score | Licence |
|---|---|---|
| This page · luxass/agent-skills | 100 | MIT |
| michalvavra/agents | 100 | MIT |
| modem-dev/skills | 100 | MIT |
Database snapshot: 13.11.2026 · package version d24b0e77265b (SHA-256 digest of the entire package)
Downloads in the last 30 days: 0 · ranking
Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.
Similar skills
- 100write-code
Write or review code in this repo. Use when writing new code, reviewing existing code, or editing code. - 100writing-maintainable-code
Principles for code that is easy to understand, change and trust. Use when writing, refactoring or reviewing code in any language, when a change touches business logic, external APIs, validation or error handling, or when preparing a commit or pull request. - 100write-readable-code
Use when writing or reviewing code for readability — names that say intent, functions at one level of abstraction, comments for why not what, and consistent formatting. - 100code-comments
Write, review, or remove code comments. Use when adding comments or doc comments, reviewing the comments in a diff, or cleaning up or removing comments. - 100typescript-write
Apply house coding standards to everyday application work. TRIGGER WHEN: writing or reviewing TypeScript/JavaScript code, including types, generics, async patterns, module boundaries, and style conventions. DO NOT TRIGGER WHEN: React performance (use react-development), or… - 100typescript-write
Apply house coding standards to everyday application work. TRIGGER WHEN: writing or reviewing TypeScript/JavaScript code, including types, generics, async patterns, module boundaries, and style conventions. DO NOT TRIGGER WHEN: React performance (use react-development), or…