agentleFS
jmfedericojmfederico/pi-web/.agents/skills/code-quality-architecture/SKILL.md

code-quality-architecture

Skill882 starsChanged 16 days agoMITView on GitHub

Project code quality and architecture expectations for implementation, refactoring, planning, and code review. Use this skill whenever writing, modifying, reviewing, or planning production code or architecture in this repository, especially when making architecture choices, introducing modules/services/components, managing side effects, dependencies, state, or boundaries. Favor composable, contained, intention-revealing, separated, dependency-injected, testable code while respecting the idioms of the framework or library in use.

We split this skill into the rules it gives an agent

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

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈18

    Distinctive · estimate

    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:

    Use this skill as a design lens, not as a framework tutorial.

    line 8
  2. Distinctive:

    Start with the simplest design that meets the behavioral contract and finish line.

    line 18
  3. Distinctive:

    Avoid unrelated refactoring, opportunistic cleanup, and broad rewrites unless the task requires them.

    line 22
  4. Distinctive:

    Use types to express domain meaning, valid states, and boundaries between parts of the system.

    line 40
  5. Distinctive:

    Keep domain decisions, orchestration, framework glue, persistence, transport, rendering, and validation separate when that separation makes …

    line 46
  6. Distinctive:

    Do not introduce a heavy dependency-injection framework unless the project already uses one or there is a clear reason.

    line 62
  7. Distinctive:

    If a change is hard to test, treat that as design feedback.

    line 68
  8. Distinctive:

    Before implementing, briefly identify the boundary you are changing:

    line 72
  9. Distinctive:

    Keep the smallest useful public surface.

    line 83
  10. Distinctive:

    Prefer explicit inputs/outputs over ambient state.

    line 84
  11. Distinctive:

    Avoid work at import time.

    line 85
  12. Distinctive:

    Use existing project patterns unless they conflict with these values strongly enough to justify a small refactor.

    line 86
  13. Distinctive:

    Avoid broad rewrites when a contained change will solve the problem.

    line 87
  14. Distinctive:

    Add abstraction only when it makes the code easier to change, test, or understand.

    line 88
  15. Distinctive:

    If you make an architectural tradeoff, mention it briefly in the final response.

    line 89
  16. Distinctive:

    When reviewing or finishing code, check:

    line 93
  17. Distinctive:

    Do names, types, and file boundaries communicate intent?

    line 99
  18. Distinctive:

    Do not over-engineer small fixes.

    line 105

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “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 quality and architecture expectations

Use this skill as a design lens, not as a framework tutorial. The goal is to shape code so future agents and humans can understand it, change it safely, and test it without needing to reverse-engineer hidden coupling.

For test-specific strategy, test helper conventions, and UI test harness choices, use the testing-guide skill. This skill still treats testability as a production-code design concern.

Respect the project's existing conventions and the framework/library idioms already in use. If a dependency expects a particular pattern, such as inheritance, decorators, lifecycle hooks, or a registration API, use that pattern deliberately and keep the surrounding project code as simple and composable as possible.

Values we optimize for

Proportionate

Start with the simplest design that meets the behavioral contract and finish line. Prefer boring, local changes that solve the problem without surprising future maintainers.

When an edge case or race is identified, assess its plausible frequency and consequence before adding special handling. Address it now when the contract requires it, it is reasonably likely in normal use, or its impact justifies the added complexity. Otherwise defer special handling, rely on ordinary observable failure or recovery behavior, and revisit if real usage shows that the case matters. Do not defer cases with a credible risk of corrupting durable state, weakening a security or authorization boundary, or failing silently without a practical recovery path.

Avoid unrelated refactoring, opportunistic cleanup, and broad rewrites unless the task requires them. Avoid new abstractions that add ceremony without clarifying ownership, reducing duplication, isolating volatility, or improving testability.

Composable

Build behavior from small pieces with explicit contracts. Prefer functions, modules, factories, services, components, or adapters that can be combined without knowing each other's internals.

Prefer composition over inheritance. Reach for inheritance only when a framework/dependency requires it, when it clearly models a stable relationship, or when it is already the local convention. If you use inheritance, keep the hierarchy shallow and explain the reason in the design or final summary.

Contained

A unit of code should do its job without leaking state, assumptions, or side effects across the system. Keep effects at clear boundaries: network, filesystem, timers, process state, browser APIs, storage, logging, telemetry, and UI/event dispatch.

Make state ownership explicit: who owns it, who may mutate it, when it is created, and how it is cleaned up. Avoid hidden global coordination, surprise mutation, ad hoc event dispatch, and imports that perform work merely by being loaded. If code must produce side effects, make the trigger, scope, cleanup, and failure behavior visible.

Clear intention

Names, types, file boundaries, and function boundaries should reveal why the code exists. Prefer a small amount of clear structure over clever compactness.

Use types to express domain meaning, valid states, and boundaries between parts of the system. Do not duplicate lint/type rules here; the point is to make the design easier to understand, not merely to satisfy TypeScript.

Comments are most valuable when they explain why a decision exists, what invariant must be preserved, or why an apparent simpler approach would be unsafe. Avoid comments that merely restate the code.

Clear separation of concerns

Keep domain decisions, orchestration, framework glue, persistence, transport, rendering, and validation separate when that separation makes the code easier to reason about.

Framework-facing code should usually be thin: gather inputs, call the core logic, map results back to the framework. Core logic should usually be usable without starting the UI, server, session runtime, browser, filesystem, or network.

Deliberate error handling

Failures must be observable and traceable to their cause. Handle them at meaningful boundaries through an explicit return or throw, contextual logging, a user-visible error, or another signal appropriate to that boundary. Do not silently rescue failures, swallow errors, or turn them into vague fallback or success behavior. Avoid scattering defensive try/catch blocks everywhere; let core logic communicate failures clearly, then translate them at the edge that has the right context.

When changing PI WEB-managed durable state, structure operations so failure does not silently leave partial writes, ambiguous overwrites, or broken invariants. Apply this where an actual persistence or lifecycle boundary warrants it; do not add transactional machinery to ephemeral or reconstructible state without a concrete need.

Security and authorization boundaries fail closed. Never convert a validation, authentication, authorization, or policy failure into permissive behavior merely to keep an operation running.

Dependencies injected

Pass collaborators, configuration, clocks, random sources, storage, network clients, and environment-specific services in through parameters, constructors, or small factories where practical. This makes dependencies visible and replaceable.

Do not introduce a heavy dependency-injection framework unless the project already uses one or there is a clear reason. Lightweight dependency injection is enough: explicit inputs beat hidden imports and singletons.

Testable by design

Testability should emerge from the previous values. Prefer pure or mostly pure core logic, small adapters around side effects, and explicit seams where tests can provide fakes or fixtures.

If a change is hard to test, treat that as design feedback. Look for hidden dependencies, mixed concerns, or side effects happening too deep in the call stack. Avoid designs that require excessive mocking just to reach the behavior under test.

How to apply this during coding

Before implementing, briefly identify the boundary you are changing:

  • What is the core behavior?
  • What are the side effects or external dependencies?
  • Who owns any mutable state, and how is it cleaned up?
  • Where should errors be handled or translated?
  • What should stay framework-specific, and what can be plain logic?
  • What would make this easy to test?

During implementation:

  • Keep the smallest useful public surface.
  • Prefer explicit inputs/outputs over ambient state.
  • Avoid work at import time; make startup, registration, listeners, timers, and connections explicit.
  • Use existing project patterns unless they conflict with these values strongly enough to justify a small refactor.
  • Avoid broad rewrites when a contained change will solve the problem.
  • Add abstraction only when it makes the code easier to change, test, or understand.
  • If you make an architectural tradeoff, mention it briefly in the final response.

Review checklist

When reviewing or finishing code, check:

  • Is this the simplest design that meets the behavioral contract and finish line, with any edge-case or race handling justified by likelihood or impact?
  • Can this behavior be reused or combined without copying internals?
  • Are side effects visible, bounded, and cleaned up when needed?
  • Is mutable state ownership clear?
  • Do names, types, and file boundaries communicate intent?
  • Are failures observable and traceable at the right boundary, without leaving durable state ambiguous or weakening a security or authorization boundary?
  • Are domain logic and framework glue separated enough for the size of the change?
  • Are important dependencies explicit and replaceable in tests?
  • Can the meaningful behavior be tested without booting unnecessary infrastructure?

Do not over-engineer small fixes. The right amount of architecture is the minimum structure that makes the code clear, safe to change, and straightforward to test.

Download now (ZIP)

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. Altinity/clickhouse-sink-connector★ 345same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository8 other files it gives its agents.

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.