agentleFS
ErikaAX08ErikaAX08/erikas-skills/code-documentation/SKILL.md

code-documentation

Skill6 starsChanged 2 months agoApache-2.0View on GitHub

Document code clearly, concisely, and professionally. Use when the user asks to document functions, classes, structs, or code files; add comments to existing code; improve existing documentation; or mentions "document", "comments", "docstrings", "JSDoc", "godoc", or "code documentation". Generates documentation that other engineers can quickly understand without being verbose, with strict prose line-count caps and no comment-width limit, while allowing one line per structured parameter, return, or error entry and forbidding per-property and per-interface-member documentation except for extreme type ambiguity.

16 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use audit-library-health, browse-and-evaluate and 9 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • MoizIbnYousafSkill

    audit-library-health

    Use when checking the overall health of a skills library. Run doctor, validate, check for stale skills, and verify generated docs are in sync.

    Also in 3 projects that use this

  • MoizIbnYousafSkill

    browse-and-evaluate

    Use when exploring the ai-agent-skills catalog to find, compare, and evaluate skills before installing. Always use --fields to limit output size and --dry-run before committing to an install.

    Also in 3 projects that use this

  • shanggqmSkill

    data-analysis

    数据分析技能,提供结构化的数据查询、统计分析和报告生成工作流。当用户需要查询数据库、进行数据统计分析、生成分析报告时使用。按规范输出原始数据、计算结果、Markdown报告和HTML可视化报告。

    Also in 3 projects that use this

  • +8 more from MoizIbnYousaf

The file

We split this skill into the rules it gives an agent

4 rules. 0 are common, 4 are distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 11 edited versions we read keep these.

  • 4

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Write the language-native format from references/documentation-formats.md, in the language-native position.

    line 40
  2. Distinctive:

    Leave trivial, unexported, self-evident elements undocumented.

    line 43
  3. Distinctive:

    Run the Review Checklist before delivering.

    line 44
  4. Distinctive:

    Delete routine field, property, and interface-member comments.

    line 51

“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Code Documentation

Documentation drifts toward two failure modes: silence (public APIs nobody can use without reading the implementation) and noise (prose that repeats what the code already says and rots the first time the code changes). This skill prevents both with hard per-element line caps. The amount of documentation an element gets is a function of its size and how obvious it is, never a fixed template applied uniformly.

See references/documentation-formats.md for the full per-language format reference with additional examples.

Contents

  • Workflow
  • Core Rules Summary
  • Code Examples
  • Common Mistakes
  • Review Checklist
  • References

Workflow

Choose the path that matches the request:

1. Document new code

  1. Identify the element type: package/module, struct/class/interface, constant/variable, field/property, function/method, or inline step inside a body.
  2. Classify each callable as trivial, medium, or complex using Function tiers. The tier caps descriptive prose; it never lowers documentation below what a caller needs.
  3. Apply the ceiling from Length caps by element. No function doc comment exceeds 2 prose lines, whatever the complexity.
  4. Move every caller-visible parameter, return, and error into a structured entry — one entry per line, exempt from the prose cap.
  5. Write the language-native format from references/documentation-formats.md, in the language-native position. Never use trailing comments.
  6. Leave trivial, unexported, self-evident elements undocumented.
  7. Run the Review Checklist before delivering.

2. Improve existing documentation

  1. Find public modules and exported symbols shipping silent, and document them to the cap.
  2. Cut prose that restates the implementation, then confirm the remaining lines still carry every caller-visible fact rather than hiding it in the body.
  3. Delete routine field, property, and interface-member comments; re-encode units, formats, ranges, defaults, and enum options in names, dedicated types, validation, or the type-level contract.
  4. Unwrap comments that were split to satisfy a column limit so each fact sits on one complete line.
  5. Replace external links with a self-contained contract stated in terms of the code.

3. Review existing documentation

Trace each element through visibility, tier, prose cap, structured entries, placement, field-comment justification, and staleness against the current body. Rerun the checklist after each correction.

Core Rules Summary

Length caps by element

ElementDocumented whenMax length
Package / module declarationAlways if public or required by the language convention1 prose line (rare 2nd invariant line)
Struct / class / interface declarationAlways, if exported/public1 prose line (rare 2nd invariant line)
Exported/public constant or variableAlways1 prose line, hard cap
Data field / property, in a structure or an interfaceAlmost never: only extreme, irreducible ambiguity from multiple runtime types or representations1 line, hard cap
Interface method signatureNever; the interface's declaration line carries the contractno comment
Trivial function/methodAlways if exported/public; otherwise only when not self-evident1 prose line + structured entries
Medium function/methodAlways if exported/publicup to 2 prose lines + structured entries
Complex function/methodAlways if exported/public2 prose lines, hard cap + structured entries
Inline step inside a bodyOnly non-obvious steps: a "why", an edge case, an assumption1 line per comment

Function tiers

TierShape
TrivialOne expression or a direct pass-through. No branching, no error path, no side effect beyond the return value.
MediumA handful of branches or a single loop, one side effect, a bounded and obvious error condition.
ComplexMultiple branches or nested logic, more than one side effect, non-obvious ordering, concurrency, or an error path the signature does not imply.

A medium function fully explained in 1 prose line does not need a padded second line to use the budget.

Non-negotiables

RuleDetail
No width limitNever wrap or truncate a comment to satisfy an 80-, 100-, or 120-column limit. Line counts, not column width, control brevity.
2-line prose ceilingNo function/method doc comment ever exceeds 2 descriptive prose lines. A 200-line function still gets 2.
Structured entries are exemptArgs:/@param, Returns:/@return, Raises:/@throws each take their own additional line, one entry per line. Not a licence for extra narrative paragraphs.
Members stay undocumentedDocument the struct, class, record, DTO, entity, config object, request/response type, or interface as a whole. Exported visibility does not justify member-by-member comments.
Interfaces documented onceAn interface gets 1 declaration line and nothing on its members. Per-operation facts live on the concrete implementations, which follow the function rule.
One field exceptionA field comment is allowed only where the declaration erases meaningful type information and an external constraint blocks a precise type. Exactly 1 line. It reaches data fields and properties only, never a method signature.
Native position onlyDeclaration comments immediately above the declaration, Python docstrings as the first statement, inline comments immediately above their step. Never trailing.
Nothing public ships silentEvery public package/module and every exported type, function, concrete method, constant, and variable is documented. Interface method signatures are the exception: they are covered by the interface's own line.
Private and self-evident stays bareForcing a comment onto a trivial unexported getter is as wrong as under-documenting.
No external referencesNo links to external docs, blog posts, Stack Overflow answers, or RFCs inside any comment or docstring. Explain behavior in terms of the code.
One documentation languageUse the repository's established language, or English when none exists. Never mix languages within one public API.

Always document when applicable

Assumptions, side effects, performance costs, concurrency constraints, null/None behavior, and the reason behind a magic number stated on one line above its declaration.

Caller-visible facts belong in the declaration contract. Implementation-local reasoning belongs inline at the exact step it explains, never in the declaration, even when prose budget remains.

Code Examples

Structure documented once, fields left bare

// PaymentRequest captures provider-independent input for one payment attempt.
type PaymentRequest struct {
    AmountCents             int64
    Currency                CurrencyCode
    Method                  PaymentMethod
    RetryOnTransientFailure bool
    id                      string
}

Units, currency format, method options, and retry behavior belong in names, dedicated types, and validation — not in one comment per field.

The extreme-ambiguity field exception

// LegacyAttribute preserves stored records that encode values as either UTF-8 text or base-10 integers.
type LegacyAttribute struct {
    // Value accepts either a UTF-8 string or a base-10 integer; every other runtime type is rejected.
    Value any
}

Value qualifies only because any hides two legal runtime types and a compatibility constraint prevents a precise type. A merely broad or poorly chosen type is not enough: improve the model instead.

Interface documented once, members left bare

// InvoiceRepository persists invoice records and their processing outcomes.
type InvoiceRepository interface {
    Create(ctx context.Context, data core.Invoice) (core.Invoice, error)
    UpdateStatus(ctx context.Context, id ULID, status string, officialID string) error
    GetByID(ctx context.Context, id ULID) (core.Invoice, error)
}
/** Describe the persisted shape of one invoice as returned by the invoices API. */
interface InvoiceRecord {
    id: string;
    status: InvoiceStatus;
    totalCents: number;
    issuedAtUtc: string;
    cancel(reason: CancellationReason): Promise<void>;
}

The member list is the contract. Facts about what each operation returns or raises go on the concrete implementations, under the function rule.

Complex function, still capped at 2 prose lines

// SyncInventory reconciles warehouse and e-commerce inventory; conflicts compare each system's inventory_updated_at normalized to UTC epoch seconds, with the highest value winning and ties favoring the warehouse.
// It returns partial results alongside a non-nil error whenever synchronization fails for one or more individual SKUs.
func SyncInventory(products []string, source string) (*Summary, error) {
    // Normalize once so conflict detection and writes use identical SKU keys.
    valid := normalize(products)

    for sku, conflict := range detectConflicts(valid, source) {
        resolve(sku, conflict)
    }
    ...
}

Structured entries carrying the contract

def process_payment(amount: float, method: str, retry: bool = True) -> dict:
    """Process a payment using the selected method; retry only transient failures.

    Args:
        amount: Positive amount in USD.
        method: Payment method; accepts 'card', 'paypal', or 'transfer'.
        retry: Whether to make up to two additional provider calls after a transient failure; false makes one attempt.

    Returns:
        Payment status, transaction ID, and processed_at_utc as a YYYY-MM-DDTHH:MM:SSZ string.

    Raises:
        ValueError: If amount or method is invalid.
        PaymentError: If the sole attempt fails while retry is false, or every attempt fails while retry is true.
    """
    return payment_provider.process(amount=amount, method=method, retry=retry)

One complete line per entry — never compacted together, never wrapped to a column limit.

Exported constant, exactly one line

// DefaultRetryLimit bounds transient provider retries before Charge returns an error.
const DefaultRetryLimit = 2

Constants and variables are symbols, not data-structure properties, so the field prohibition does not apply to them.

Inline comments that earn their line

# Convert epoch seconds at the boundary so every internal timestamp is timezone-aware UTC.
timestamp = datetime.fromtimestamp(response.timestamp, tz=timezone.utc)

# Traverse in reverse so each removal preserves indexes that remain to be visited.
for index in range(len(items) - 1, -1, -1):
    if should_remove(items[index]):
        del items[index]

# Reserve five seconds of the execution budget for cleanup.
REQUEST_TIMEOUT_SECONDS = 25

Against the same steps, # Increment counter, # Iterate over users, and # Return True add nothing and are prohibited.

Private and self-evident, left undocumented

def _get_user_name(user):
    return user.name

A docstring here would restate the name and the body. The public-symbol rule does not reach it.

Common Mistakes

MistakeFix
Doc comment wrapped to an 80- or 120-column limitKeep each prose line and each structured entry complete on one line; line counts control brevity.
Complex function gets a six-line narrativeCap prose at 2 lines and move parameter, return, and error facts into structured entries.
Every exported struct field carries a commentDocument the structure once; encode units, formats, ranges, and defaults in names, types, and validation.
Every interface method carries its own commentDocument the interface once; put per-operation contract facts on the concrete implementations.
Contract facts hidden in the body to respect the capUse both prose lines fully and add structured entries; never drop a caller-visible fact.
Field Type // comment trailing on the declarationUse the language-native leading position, or remove the comment entirely.
Public module or exported symbol ships with no documentationDocument every public symbol to its cap; silence is a violation, not brevity.
Trivial unexported getter padded with a docstringLeave it undocumented.
Comment explains complexity that should be refactored awaySimplify the code instead of narrating it.
Docstring points at an external URL for the real contractState the contract in terms of the code; external references are prohibited.
Stale comment describes behavior the body no longer hasRewrite it against the current contract, or delete it.

Review Checklist

  • Public coverage: Every public package/module and exported type, function, concrete method, constant, and variable is documented.
  • Declaration caps: Packages/modules and types have 1 prose line, rarely a second line for a hard invariant.
  • Constant cap: Every exported constant and variable has exactly 1 prose line.
  • Prose ceiling: No function/method doc comment exceeds 2 lines of descriptive prose, regardless of complexity.
  • Tier applied: Every documented callable was classified trivial/medium/complex and respects that tier's cap.
  • Structured entries: Each documented parameter, return, and error occupies its own line and is not counted against the prose cap.
  • No width wrapping: No comment was split or truncated to satisfy a column limit.
  • Members bare: No routine field, property, or interface-member comments, whatever the visibility.
  • Interfaces once: Each interface carries a single declaration line and no comment on any method signature.
  • Field exception justified: Any field comment is exactly 1 line and driven by irreducible ambiguity between multiple legal runtime types.
  • Placement: Declaration comments sit immediately above declarations, Python docstrings are first statements, inline comments precede their step, and no trailing comments remain.
  • Silence where due: Trivial, unexported, self-evident elements are left undocumented rather than padded to a template.
  • Contract completeness: Non-obvious errors/exceptions the callable can produce are documented.
  • Special cases: Applicable assumptions, side effects, performance costs, concurrency constraints, and null/None behavior are stated; magic numbers carry a reason.
  • Layer separation: Caller-visible edge cases live in the declaration contract; implementation-local reasoning lives inline at the relevant step.
  • Inline discipline: Inline comments explain "why", stay single-line, and no large commented block sits inside a body.
  • Freshness: No redundant, obvious, or outdated comments remain.
  • Language: Documentation uses the repository's established language, or English when none exists, without mixing within one public API.
  • Self-contained: No links or references to external documentation or sources.

References

  • Full per-language format guide: references/documentation-formats.md

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.