<< All versions

Skill v3.2.4

currentAutomated scan100/100
goberomsu/craft-skills/principle-programming
──Details
PublishedNovember 4, 2026 at 05:41 PM
Content Hashsha256:c6908e06c586c663...
Git SHA8470c8b34604
──Files
Files (1 file, 11.5 KB)
SKILL.md11.5 KBactive
SKILL.md · 123 lines · 11.5 KB

name: principle-programming description: Guides correctness-first, type-strict Python and TypeScript implementation. Use when asked to write a .py or .ts file, scaffold a Python/TypeScript project, add strict types, assess an implementation diff for correctness or type holes, or fix a reproducible defect. Not for smell-only assessment or behavior-preserving restructuring — use refactor; not for suite-level test architecture — use principle-testing. metadata: version: 3.2.4


principle-programming

Write Python and TypeScript under one discipline: correctness first, maintainability second, brevity third. The type system is the proof, the test is the safety net, and the smallest code that satisfies both — never either alone — is the goal. Success looks like a clean type-check + lint pass, evidence for changed observable behavior, and each changed file considered against the LOC review signal below. principle-testing owns suite-level architecture, while refactor owns smell-only review and behavior-preserving restructuring.

Load the task-relevant reference first

Load only the references the task needs before touching code; a one-off script does not need every language guide.

ScopeRead
Any implementation or code editreferences/workflow.md — understand → plan → change → verify → report, and the completion contract
.py, .pyi, or Python taskreferences/python.md — tooling table, iron list, data-modeling map
.ts, .tsx, .mts, .cts, or TypeScript taskreferences/typescript.md — tooling table, iron list, and this package's assets/tsconfig.strict.json; load references/typescript/clean-code.md when naming, function shape, or structure is in scope
Smell-only reviewRoute to refactor; it owns the code-smell catalog and the resulting restructuring
Comments in a diff, or a request to strip or review themreferences/comments.md: one reviewer pass, accepted fixes, and encoding offers for claimed constraints

Principle references

  • laziness-protocol prefers deletion and the smallest change that solves the problem.
  • minimize-reader-load collapses layers and hidden state a reader must hold in their head.
  • build-the-lever builds the script that does or proves the work, so a reviewer can rerun it. When an agent keeps doing the same thing by hand, have it write the tool or skill it wishes it had. If a script can do a step the same way every time, use the script, and save agents for the judgment calls.
  • model-the-domain encodes repeated rules in one structure, not scattered conditionals.
  • type-system-discipline makes illegal states unrepresentable.

Write only what the task needs

Stop at the first rung that holds, after the correctness requirements are already known — this ladder never substitutes for them:

  1. Does this need to exist? Speculative need → skip it, say so in one line (YAGNI).
  2. Does the codebase already have it? Reuse the existing helper, util, or pattern — never rewrite it.
  3. Does the stdlib do it? Use it.
  4. Does a native platform feature cover it? <input type="date"> over a date-picker library, CSS over JS layout, a DB constraint over an app-side check.
  5. Does an already-installed dependency solve it? Use it; never add a dependency for what a few lines cover.
  6. Can it be one line? One line.
  7. Only then: the minimum code that works.

Apply laziness-protocol to this ladder and build-the-lever when non-trivial work needs a rerunnable tool.

When two rungs hold, take the higher one. When two options are the same size, take the one correct on edge cases — fewer lines never means the flimsier algorithm. Validation at trust boundaries, error handling that prevents data loss, security, and accessibility are correctness, not brevity — never skimp on these.

Deletion beats addition, boring beats clever, fewest files wins — and a complex request earns one question before it earns code: "do you actually need X, or does Y already cover it?" A bug report names a symptom, not the cause: inspect affected callers of the function you touch and fix the shared function once — one guard there is a smaller diff than one per caller, and patching only the reported path leaves a sibling caller broken.

For symbol operations, prefer available language-server definitions, references, rename, and diagnostics; confirm support in the source project rather than inferring it from another workspace's server status. Use an available AST tool when syntax-aware matching or transformation helps; consult an existing code graph only for a concrete dependency or impact question, checking its coverage and freshness. When semantic support is unavailable, use bounded text search and source inspection, disclose coverage limits, and validate with the project's checks rather than claiming semantic proof or complete caller coverage. Stop when that fallback cannot establish the safety the change needs; do not assume missing support requires installing a server, hook, or skill wrapper.

Record a deliberate shortcut's ceiling and upgrade path in a follow-up note, type, test, or lint rule, per step 5 of comments.

Core decisions

  • Make illegal states unrepresentable when a bug can become a type error (type-system-discipline).
  • Parse untrusted input into a typed value once at the boundary, then trust that contract internally.
  • Give each concept its own type and name; match tagged variants exhaustively (model-the-domain).
  • Keep a change as one logical, independently reversible unit; split unrelated work rather than using file count as a proxy.

For planned changes that declare where temporary breakage is acceptable, defer to the principle-architecture skill's outcome-oriented-execution.md file under references; verify at the declared phase boundaries.

The 250 pure LOC review signal

Use minimize-reader-load to judge cohesion.

A source file over 250 pure LOC deserves a cohesion review, not an automatic split. Split it when independent responsibilities make the file hard to reason about; keep a cohesive unit intact when extraction would only scatter its contract. For an existing large file, improve the unit being touched when that is a bounded, clearer change rather than expanding the task to reorganize it. Generated tables and genuinely indivisible state machines may exceed the signal with a one-line justification comment.

Use the repository's incumbent measurement when it has one; otherwise this command gives a comparable pure-LOC count:

bash
awk '!/^[[:space:]]*$/ && !/^[[:space:]]*(\/\/|#)/' <file> | wc -l

TDD — red, green, refactor

Use red-first TDD when adding or changing observable behavior, or when risk warrants a regression net: write a failing Given/When/Then test, confirm it fails for the intended reason, then write the minimum code to pass. For a localized low-risk mechanical edit, run the cheapest credible verification instead of manufacturing a test.

For every reproducible defect, retain a failing-first regression test at the defect's natural layer before the fix makes it pass. Assert the contract, not the dump; prefer the real object, then an in-memory fake, then a wire-level fake. Mock only true unmockables (clock, randomness) at the narrowest seam, and inject a clock or subscribe to events instead of sleeping. When a test is impractical or would be a bad test, the tdd skill's rule governs instead: prefer no new test over a bad test and use the closest executable check (owner decision (i) in the craft-mode skill's conflicts.md file under references).

Logging decisions

When adding logs, follow the project's established logging practice. Choose the level by the consumer's need, place logs at decisions rather than every step, and keep messages stable while putting variable context in structured fields.

Mutable tooling and runtime facts

For mutable language, LSP, test-runner, package-manager, and runtime behavior, consult the official primary documentation for the installed version and platform first. Disclose conflicts rather than silently choosing a source. A more-specific repository-local contract or reproducible evidence for the matching version and platform may override general or stale documentation. Unresolved support stays unknown: use no guessed command or claimed capability, and stop or use the repository's verified fallback.

Output contract

Leave behind code that follows the selected language reference, plus the checks named in this recipe run against the change. Report the changed artifact locations, each check and its result, and any focused behavior evidence in the completion summary.

When the language or tooling is not covered by a reference, or a required toolchain is missing, stop without a result and report the unsupported or missing prerequisite.

Requirements

Use the repository's incumbent package manager, type checker, linter, test runner, and LOC measurement first; use these defaults only when the project has no established equivalent:

  • Python: uv, basedpyright (typeCheckingMode = "all"), ruff (select = ["ALL"]), pytest.
  • TypeScript: bun (or pnpm), tsc with this package's assets/tsconfig.strict.json, biome.
  • awk + wc for the fallback LOC measurement.
  • Runtime sources: Python documentation and Node.js documentation; consult the matching installed runtime version before relying on mutable behavior.
  • Before choosing language-specific tooling, safely record python3 --version for Python work and node --version for TypeScript work. Also run the incumbent package manager's, type checker's, and test runner's documented version probe; do not substitute a guessed command when an incumbent tool lacks one.
  • When the selected runtime or any of those tools changes, review the applicable official documentation, rerun affected language-specific evals, update this recipe if needed, bump the package version, and record the reason in the commit message before trusting prior results.

Anti-patterns

  • Skipping types on a throwaway script → use the smallest project-compatible setup; disposable code still needs an honest contract.
  • Leaving a shortcut's constraint unenforced → use a follow-up note, type, test, or lint rule, per no-comments step 5.
  • Using except Exception / an empty catch that swallows the stack trace → catch specific exceptions and handle or log them explicitly.
  • Introducing an interface/Protocol with exactly one implementation, or a factory for one product → use the concrete type directly until a second implementation exists.
  • Adding # type: ignore / @ts-ignore with no explanation → fix the type, or add a comment explaining why the escape hatch is unavoidable.
  • Logging every operation or interpolating unstable context into messages → log decision points with stable messages and structured fields.

Verification

  • [ ] Task-relevant references were read before writing code.
  • [ ] The core decisions, LOC review signal, and relevant TDD or logging guidance were applied.
  • [ ] The incumbent type checker, linter, and focused verification pass clean.
All versions