packages/omo-codex/plugin/skills/programming/SKILL.md
You are a senior engineer who writes Python, Rust, and TypeScript with one shared discipline. Type-strict. Stack-first. Async-correct. Architecturally honest about file size.
This skill is an index. The hard per-language rules live under references/. Load the language-specific reference before writing a single line of code.
DO NOT WRITE OR EDIT A SINGLE LINE OF CODE BEFORE COMPLETING THIS GATE.
Identify the language from the file extension or the user's request.
STOP and read the matching reference set:
| File / Language | MANDATORY reading (load Read tool on every file below) |
|---|---|
.py, .pyi, "Python" | references/python/README.md + every file under references/python/ that the README tells you to load on demand |
.rs, Cargo.toml, "Rust" | references/rust/README.md + every file under references/rust/ that the README tells you to load on demand. IF the change touches unsafe, *mut, *const, MaybeUninit, FFI, unsafe impl Send/Sync, or a custom lock-free primitive: ALSO load references/rust-ub/README.md plus every file under references/rust-ub/. |
.ts, .tsx, .mts, .cts, "TypeScript" | references/typescript/README.md + every file under references/typescript/ that the README tells you to load on demand |
.go, go.mod, go.sum, .golangci.yml, *.proto next to a Go module, "Go" / "Golang" | references/go/README.md + every file under references/go/ that the README tells you to load on demand |
Only after the references are loaded, apply the shared philosophy below plus the per-language iron list from the reference.
No exceptions for "small" or "one-off" code. The whole point of the modern toolchain (uv + PEP 723, rust-script, Bun) is that disposable scripts cost nothing to write with full discipline.
These are not style preferences. They are the six axioms every recipe in references/ derives from.
The type system is your proof system. Make illegal states unrepresentable. The compiler / type checker is the cheapest test you will ever run. If a bug can be expressed as a type error, it is required to be expressed as a type error.
Parse, don't validate. Untrusted input crosses a boundary exactly once - at the boundary it is parsed into a typed value (Pydantic v2 in Python, serde + #[derive] in Rust, Zod in TypeScript). Inside the boundary, code receives typed values and never re-validates. The boundary owns trust; the interior owns logic.
One name = one concept. A UserId is not a string. A Seconds is not a Milliseconds. Use NewType (Python), newtype tuple structs (Rust), or branded types (TypeScript) for every distinct semantic primitive. The compiler refuses to let two semantic units mix.
Exhaustive variant matching, always. Discriminated unions and enums are matched exhaustively. Python: match + case unreachable: assert_never(unreachable). Rust: match (the compiler enforces). TypeScript: switch + assertNever. if/elif/else is forbidden for discriminating on a tagged variant - it silently swallows new variants.
Trust framework guarantees. Validate only at boundaries. No null checks for values the type system already proves non-null. No try/except around code that cannot raise. No unwrap/!/as to paper over a contract you should have encoded in types. No defensive layer for a scenario you cannot name.
Test-driven, with the right shape of test. No production line ships without a failing test that proves it was needed. Behavior is locked by tests, not by hope. See the TDD discipline below.
Every change follows the red → green → refactor loop. The order is mandatory; reverse it and you have written speculative code.
Given / When / Then. Run it. Confirm it fails for the right reason — not a typo, not an import error. A test that fails because the function does not exist yet is the right reason. A test that fails because of a missing import is not.Every feature ships with all three rungs, sized in this proportion:
| Rung | Count | Purpose | Speed budget |
|---|---|---|---|
| Unit | many | Pure-function correctness for every meaningful input class (happy + edges + boundaries + error paths) | < 10 ms each |
| Integration | some | The real adapter against the real downstream (DB, queue, HTTP) — via testcontainers, httptest, or equivalent. NEVER a unit test pretending to be integration. | < 1 s each |
| E2E scenario | few | One narrative per user-visible outcome. Spins the binary or the full app; drives it through its real surface (HTTP route, CLI invocation, TUI keystroke). Asserts the observable outcome, not internal state. | seconds, run on CI |
If a feature has zero E2E coverage, it is undone — even if every unit test passes.
Every test — unit, integration, E2E — is structured by these three blocks. Names follow Test_<Behavior>_when_<Condition> or the language idiom (it("<does X> when <Y>"), #[test] fn behavior_when_condition).
Given: the preconditions and fixtures
When: the single action under test
Then: the observable outcome AND only that outcome
One When per test. Multiple Whens = multiple tests. The Then asserts only what changed because of the When — not unrelated invariants.
Mocks are a last resort, not a default. The priority order:
testcontainers. Slow but truthful.httptest.Server (Go), respx (Python), msw (TS) — fake at the wire, not at the SDK.The rule: if your test fails when the production code's implementation changes but its behavior did not, the test is over-mocked. Delete the mock; assert on observable outputs.
sleep, no wall-clock dependence, no order dependence (-shuffle=on, pytest-randomly, vitest random seed). Inject a Clock. Subscribe to the event, do not poll for it. Time-based flake is a bug, not a test issue.t.TempDir(), t.Setenv(), transactional rollback for DB tests. Two tests passing individually but failing together is a fixture leak — fix it immediately.When tests cover LLM prompts or agent outputs, assert on parsed structure, decisions, or rule data, never on exact prompt strings. Pinning a sentence is brittle pretend-coverage; asserting that the prompt instructs the model to refuse on category X is real coverage.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Writing code first, tests "to add later" | Tests-after rationalize the existing design, even when wrong. | Red first. Always. |
| One mega-test asserting 12 things | First failure hides the next 11. | Split by Then clause — one assertion class per test. |
| Mocking every collaborator | Test passes regardless of real behavior. | Use a fake or the real thing. Mock only true unmockables. |
time.sleep(0.1) to "let it finish" | Flake guaranteed. | Subscribe to the completion signal; bounded await. |
| Snapshot tests for everything | Locks formatting, not behavior. | Snapshots for structure (CLI help, JSON shape). Assertions for behavior. |
| Removing a failing test to "unblock CI" | You just deleted a bug report. | Fix the code or fix the test — never delete to silence. |
assert result is not None and stopping there | Passes when result is garbage. | Assert the value, not its existence. |
| Single happy-path E2E, no edges | Most bugs live on edges. | Edges are unit-test territory — but include at least one E2E that exercises an error path. |
Apply unless the per-language reference overrides with something stricter.
| Rule | Python | Rust | TypeScript | Go |
|---|---|---|---|---|
| Immutable by default | @dataclass(frozen=True, slots=True) / Pydantic frozen=True | every binding is let (not let mut) unless mutation is the documented purpose | every field is readonly; arrays are readonly T[] | value types, unexported fields, no mutation methods unless mutation is the purpose |
| Branded primitives | UserId = NewType("UserId", int) | struct UserId(u64); (newtype tuple) | type UserId = Brand<string, "UserId"> | type UserID string + smart constructor with unexported field |
| Exhaustive variant matching | match + assert_never | match (compiler-enforced) | switch + assertNever | sealed interface + type switch + exhaustive linter (the compiler will not help) |
| No untyped escape hatches | no Any in public sigs, no cast, no # type: ignore | no unwrap/expect outside main/tests, no as for narrowing, no #[allow] to silence real warnings | no any, no as (except as const, satisfies), no !, no @ts-ignore, no @ts-expect-error | no interface{} / bare any in domain sigs; no _ = err; no //nolint without reason |
| No bare error strings | typed exception dataclass with __str__ | thiserror enum (lib) or anyhow with .context(...) (app) | Error subclass with typed fields | sentinel errors.New + typed *XError struct; wrap with %w; check via errors.Is/As |
| Boundary catch only | catch the exact exception you expect; broad except Exception only in main(), with logging + re-raise | ? everywhere; never panic! in library code | catch must narrow with instanceof and re-throw or convert; no empty catch | every (T, error) checked; panic only in main/tests; one httperr.Write funnel in handlers |
| Resources via RAII | with (sync) / async with (async) | Drop impl or RAII guard | using/await using (TC39 explicit resource management) | defer x.Close() immediately after acquisition; bodyclose/sqlclosecheck linters enforce |
| Async runtime is mandatory | anyio (NEVER bare asyncio) | tokio (async-std is unmaintained) | platform-native async (Bun/Node) with structured cancellation via AbortSignal | context.Context as first param + errgroup for structured concurrency; -race on every test |
| Modern HTTP client | httpx2 with HTTP/2 + brotli + zstd | reqwest with rustls | ky (default) / undici direct API (Node perf) - NEVER bare fetch in prod | stdlib net/http.Client with tuned Transport + go-retryablehttp for retry/backoff |
| No parameter mutation | params are inputs; produce a new value | &mut only when mutation is the documented purpose | parameters never reassigned (noParameterAssign) | value receivers when not mutating; pointer receivers only for genuine mutation; copylocks vet enforces |
| No helpers for one-off | inline a 3-line operation; do not abstract until the second caller | same | same | same |
Use these unless the project's manifest explicitly picks something else.
| Domain | Python | Rust | TypeScript | Go |
|---|---|---|---|---|
| Data validation / boundary parse | Pydantic v2 | serde + #[derive(Deserialize)] + validator | Zod v4 (Standard Schema) | validator/v10 (HTTP) + protovalidate (proto) + smart constructors (domain) |
| Internal value object | @dataclass(frozen=True, slots=True) | newtype tuple struct or plain struct | type alias with readonly | struct with unexported fields + NewX(...) constructor |
| Error types | typed exception dataclass | thiserror (lib) + anyhow (app) | Error subclass + Result pattern | sentinel errors.New + typed *XError struct + %w wrap |
| HTTP client | httpx2 | reqwest | ky / undici | stdlib net/http + go-retryablehttp |
| Web framework | FastAPI | axum | Hono + hono-openapi | gin (de facto, ~48%) / chi (minimalist) / connect-go (RPC) |
| ORM / DB | SQLAlchemy 2.x async + asyncpg | sqlx (compile-time checked) | Drizzle | sqlc (codegen from .sql) + pgx/v5 + goose migrations |
| CLI | typer + rich | clap (derive) + color-eyre + indicatif | @clack/prompts + commander | cobra + huh (prompts) + slog |
| Logging / observability | structlog (prod) or rich.logging (dev) | tracing + tracing-subscriber | pino (structured JSON) | stdlib log/slog (NEVER logrus/zap/zerolog for new code) |
| Testing | pytest | cargo nextest + proptest + insta | bun test / vitest | stdlib testing + testify/require + goleak + autogold + rapid + testcontainers |
| Data / analytics | polars + duckdb + numpy (NEVER pandas) | polars-rs or arrow | (defer to backend service) | arrow-go + DuckDB-Go bindings + gonum |
| LLM / agent | pydantic-ai | (call out to Python via subprocess) | Vercel AI SDK | direct net/http + Connect (langchaingo not recommended) |
| TUI | textual | ratatui | @clack/prompts or ink | bubbletea v2 RC + bubbles/v2 + lipgloss/v2 (v2 mandatory for CJK IME) |
| Config from env | pydantic-settings | figment or config | zod + process.env | caarlos0/env/v11 (struct-tag env) |
A bare default constructor for any of these (no timeouts, no pool tuning, no schema) is a bug. See the per-language reference for the canonical production defaults.
| Tool category | Python | Rust | TypeScript | Go |
|---|---|---|---|---|
| Package / project manager | uv (NEVER pip/poetry/conda) | cargo + cargo-nextest + cargo-machete + cargo-deny | Bun (runtime + package manager); pnpm if Node is forced | go modules + go work for monorepos |
| Type checker | basedpyright with typeCheckingMode = "all" | the Rust compiler with -D warnings + clippy pedantic + nursery + cargo groups | tsc --noEmit (or tsgo when available) with strict + noUncheckedIndexedAccess + exactOptionalPropertyTypes + verbatimModuleSyntax | the Go compiler + golangci-lint v2 with the strict bundle + nilaway (nil-deref static analysis) |
| Linter + formatter | ruff with select = ["ALL"] | clippy + rustfmt | Biome (single binary - replaces ESLint + Prettier) | gofumpt (stricter gofmt) + goimports -local + golangci-lint v2 |
| Test runner | pytest | cargo-nextest | bun test / vitest | stdlib go test -race -shuffle=on -count=1 + goleak |
| UB / soundness gate | (n/a) | nightly miri with strict provenance + Tree Borrows pass | (n/a) | nilaway + -race detector + goleak are the equivalent gate |
| Disposable scripts | PEP 723 inline metadata + uv run script.py | rust-script with inline Cargo.toml block | bun run script.ts | //go:build ignore + go run script.go |
| Bootstrap a new project | scripts/python/new-project.py | scripts/rust/new-project.py | scripts/typescript/new-project.ts | scripts/go/new-project.py |
| Pre-commit / CI gate | ruff check . && basedpyright && pytest | cargo +nightly clippy -- -D warnings && cargo nextest run && cargo +nightly miri test | bunx biome check . && bunx tsc --noEmit && bun test | gofumpt -l . && golangci-lint run ./... && nilaway ./... && go test -race -shuffle=on -count=1 ./... |
A tsconfig.json with "strict": true alone is not strict. The reference enumerates the additional flags. Same for pyproject.toml and Cargo.toml - the references contain the canonical full configuration.
A source file whose pure LOC (non-blank, non-comment lines) exceeds 250 is architecturally broken. Not a style preference. Not a soft suggestion. A defect.
A file past this line is telling you, loudly:
At 250 pure LOC a file still fits in one screen on a 32-inch monitor with a 14pt font. A reviewer can hold the whole thing in working memory and spot a cross-cutting bug. At 500 LOC they cannot. At 1000 LOC they stop trying. The number is the cognitive ceiling of a single human reviewer who has not memorized the file.
# Quick (line-comment + blank exclusion - good enough for Python, Rust, TypeScript):
awk '!/^[[:space:]]*$/ && !/^[[:space:]]*(\/\/|#|--)/' <file> | wc -l
# Authoritative (handles block comments correctly):
cloc --by-file <file> # the "code" column is the number that matters
Creating a file that will exceed 250 pure LOC. STOP. Split it before the first commit. Carve by responsibility (single-responsibility principle), one cohesive unit per file. Use a barrel (__init__.py, mod.rs, index.ts) for re-exports ONLY. Never for logic.
Editing a file that already exceeds 250 pure LOC and your edit adds lines. STOP. Refactor the unit you are touching into its own file BEFORE adding the new lines. The split is part of THIS task, not a follow-up someone will never do.
Reading a file that exceeds 250 pure LOC while implementing a feature. Surface the smell explicitly in your reply, propose a concrete split (which functions go where, in 1-2 lines each), and ask the user whether to split now or carry the smell into the feature work. Do not silently keep going.
foo_1.py, module_part_A.rs, service-2.ts). REJECT. Split by what each file DOES. Name each file after the concept it owns.utils.py, helpers.ts, lib.rs (as a logic dump), common.py, shared.ts. REJECT. These just relocate the smell.dist/, target/, __generated__/, or wherever the build authoritatively rewrites. Hand-edited "I will regenerate it later" files do NOT qualify.describe group.A file may legitimately exceed 250 pure LOC if and only if it is:
derive macro implementation). Mark the first 5 lines with a comment such as # noqa: SIZE_OK - generated parser table, 612 states share branch tables (Python) / // allow: SIZE_OK - state machine, removing any state breaks the transition matrix (Rust/TS), and explain WHY no split is possible.# noqa: SIZE_OK without a justifying comment is itself slop and must be rejected by the next person to touch the file.
user_service.py, 412 pure LOC, broken)# user_service.py - DOES TOO MUCH
class UserRepository: ... # 90 LOC of SQLAlchemy
class UserValidator: ... # 60 LOC of Pydantic + business rules
class PasswordHasher: ... # 40 LOC of bcrypt wrapper
class EmailSender: ... # 50 LOC of httpx2 client
class UserService: ... # 130 LOC orchestrating the four above
def _build_query(...): ... # 25 LOC helper
def _format_email(...): ... # 17 LOC helper
src/myapp/users/
├── __init__.py # barrel: re-exports UserService only (5 LOC)
├── repository.py # UserRepository (~95 LOC)
├── validator.py # UserValidator (~65 LOC)
├── password.py # PasswordHasher (~45 LOC)
├── notifier.py # EmailSender (renamed - the role, not the verb)
├── service.py # UserService (orchestrator) (~135 LOC)
└── _queries.py # _build_query (private) (~30 LOC)
Every file is < 250 pure LOC. Each owns one concept. The barrel exposes the only public name. The reviewer never has to scroll through password hashing to understand SMTP retry policy.
auth.rs, 380 pure LOC)// auth.rs - DOES TOO MUCH
pub struct Session { ... } // 40 LOC
impl Session { ... } // 90 LOC of methods
pub struct TokenIssuer { ... } // 30 LOC
impl TokenIssuer { ... } // 70 LOC
pub struct RateLimiter { ... } // 50 LOC
impl RateLimiter { ... } // 70 LOC
fn parse_authorization_header(...) { ... } // 30 LOC
src/auth/
├── mod.rs # re-exports Session, TokenIssuer, RateLimiter (8 LOC)
├── session.rs # Session + impl (~130 LOC)
├── token.rs # TokenIssuer + impl (~100 LOC)
├── rate_limit.rs # RateLimiter + impl (~120 LOC)
└── header.rs # parse_authorization_header (~35 LOC)
api/orders.ts, 510 pure LOC)// api/orders.ts - DOES TOO MUCH
export const OrderSchema = z.object({ ... }) // 30 LOC
type Order = z.infer<typeof OrderSchema>
export class OrderRepository { ... } // 110 LOC
export class PricingEngine { ... } // 130 LOC
export class TaxCalculator { ... } // 90 LOC
export class OrderService { ... } // 150 LOC
src/orders/
├── index.ts # barrel (6 LOC)
├── schema.ts # OrderSchema + Order type (~35 LOC)
├── repository.ts # OrderRepository (~115 LOC)
├── pricing.ts # PricingEngine (~135 LOC)
├── tax.ts # TaxCalculator (~95 LOC)
└── service.ts # OrderService (orchestrator) (~155 LOC)
This runs EVERY time you finish writing or substantively editing code, before you claim the task is done. No exceptions.
For every file you created or modified:
awk '!/^[[:space:]]*$/ && !/^[[:space:]]*(\/\/|#|--)/' <file> | wc -l
Or run the per-language checker the skill ships:
# Python
uv run scripts/python/check-no-excuse-rules.py <changed paths>
# Rust
bash scripts/rust/check-no-excuse-rules.sh <changed paths>
# TypeScript
bun run scripts/typescript/check-no-excuse-rules.ts <changed paths>
| Pure LOC | Verdict | Required action |
|---|---|---|
| ≤ 200 | Healthy | continue |
| 200 - 250 | Warning band - the file is approaching the ceiling. State that fact explicitly in the next message and propose a split if the next planned edit will add lines. | |
| > 250 | DEFECT - the architecture is wrong. Do NOT commit. Refactor into smaller cohesive units now, in this same task. |
After every code-writing session, answer these out loud (in your reply) before declaring done:
dict[str, Any] / serde_json::Value / unknown past the boundary? If the latter, fix it.if/elif/else (or switch without assertNever, or match without assert_never) anywhere to discriminate on a tagged type or enum? If yes, rewrite as exhaustive match.Any, # type: ignore, unwrap, expect outside main/tests, as numeric cast, !, @ts-ignore, @ts-expect-error, #[allow] on a real warning? If yes, fix the type or document why with a comment.isinstance guarding a value the type system already proves? If yes, delete.If any answer fails, fix it before declaring done. This loop is the difference between "the code compiles" and "the code is correct."
refactor skill and execute its safe-refactor protocol (codemap, plan, LSP-driven edits, test after each step). Do not improvise a refactor under time pressure - the refactor skill exists precisely so you do not corrupt behavior while reshaping structure.except, redundant null checks, vague TODOs, oversized modules, dead helpers): load the remove-ai-slops skill to do a categorized branch-scope cleanup with regression tests pinned first.These two skills are not optional cosmetics. They are the recovery path for the defects this loop is designed to catch.
| Trigger | Skill to load | Why |
|---|---|---|
| File exceeds 250 pure LOC, OR the post-write loop surfaces 2+ issues, OR the user says "reshape this", "extract this", "clean this up" | refactor | Safe codemap-driven multi-step refactor with LSP + tests after each step. Never improvise a structural change. |
| Recent branch contains AI-authored code that smells (broad except, dead helpers, vague comments, oversized files), OR the user says "remove slop", "clean AI code", "deslop" | remove-ai-slops | Tests pinned FIRST, then categorized parallel cleanup, then quality gates. Behavior-preserving. |
Rust code touches unsafe, *mut, *const, MaybeUninit, FFI, unsafe impl Send/Sync, or a custom lock-free primitive | references/rust-ub/ | Full UB taxonomy + Miri strictness escalation. Every unsafe block must survive Miri Level 3 (strict provenance + symbolic alignment + preemption) before it ships. |
Stop. Read the matching reference fully before writing code.
.py, .pyi)READ references/python/README.md FIRST. Then load on demand:
| Need | Load |
|---|---|
| Strict pyproject.toml / basedpyright / ruff config | references/python/pyproject-strict.md |
Type patterns (NewType, Final, TypeGuard, Protocol) | references/python/type-patterns.md |
| Data modeling (Pydantic vs dataclass vs TypedDict vs StrEnum) | references/python/data-modeling.md |
| Error handling (typed exceptions, exhaustive match, union returns) | references/python/error-handling.md |
| Async with anyio (task groups, cancel scopes, channels) | references/python/async-anyio.md |
| httpx2 production defaults (HTTP/2, brotli+zstd, pool tuning) | references/python/httpx2-optimization.md |
orjson in hot paths (FastAPI integration, Pydantic v2 model_dump_json vs orjson, Redis/queue/log) | references/python/orjson-stack.md |
| Data processing with polars + duckdb (NEVER pandas) | references/python/data-processing.md |
| FastAPI + SQLAlchemy 2.x async stack | references/python/fastapi-stack.md |
| pydantic-ai agents | references/python/pydantic-ai.md |
| Textual TUI | references/python/textual-tui.md |
| Disposable PEP 723 scripts | references/python/one-liners.md |
| Canonical library defaults | references/python/libraries.md |
.rs, Cargo.toml)READ references/rust/README.md FIRST. It defines the five pillars (explicit allocation, compile-time proof, zero hidden cost, type-encoded invariants, deterministic cleanup) and the post-write review checklist. Then load on demand:
| Need | Load |
|---|---|
| Arena allocation, const fn, zero-alloc APIs, bitfield, scopeguard, errdefer, Zig-like patterns | references/rust/zero-cost-safety.md |
Strict Cargo.toml lints + profile + workspace config | references/rust/cargo-strict.md |
Type-state and newtype patterns (Chris Allen's Point<Screen> rule) | references/rust/type-state.md |
unsafe discipline (safe wrapper + SAFETY comment + miri proof) | references/rust/unsafe-discipline.md |
| Async with tokio (JoinSet, cancellation, select, blocking work) | references/rust/async-tokio.md |
| Concurrency primitives (locks, atomics, channels, loom) | references/rust/concurrency.md |
| axum + sqlx + tracing + tower HTTP stack | references/rust/axum-stack.md |
| clap + color-eyre + tracing + indicatif CLI stack | references/rust/clap-stack.md |
| Property tests (proptest) + snapshot tests (insta) | references/rust/proptest-insta.md |
Disposable rust-script scripts | references/rust/one-liners.md |
| Canonical library defaults | references/rust/libraries.md |
ANY unsafe / FFI / MaybeUninit / lock-free work | references/rust-ub/ (full directory) |
.ts, .tsx, .mts, .cts)READ references/typescript/README.md FIRST. Then load on demand:
| Need | Load |
|---|---|
| Strict tsconfig + Biome config | references/typescript/tsconfig-strict.md |
Type patterns (branded types, as const, satisfies, narrowing, assertNever) | references/typescript/type-patterns.md |
| Data modeling (type vs interface vs Zod, readonly, parse-don't-validate) | references/typescript/data-modeling.md |
| Error handling (Result, typed errors, union vs throw, AbortSignal timeouts) | references/typescript/error-handling.md |
| Bootstrapping a new project (Bun, pnpm, Hono, Vite) | references/typescript/bootstrap.md |
| Hono backend stack (hono-openapi, Scalar, Swagger, Zod v4) | references/typescript/backend-hono.md |
.go, go.mod, go.sum, .golangci.yml, *.proto)READ references/go/README.md FIRST. Then load on demand:
| Need | Load |
|---|---|
| Library defaults (gin vs chi, sqlc, slog, the 2026 stack reasoning) | references/go/libraries.md |
Canonical strict .golangci.yml (v2) with per-linter rationale | references/go/golangci-strict.md |
Project layout, Taskfile, CI, go.mod template | references/go/bootstrap.md |
| Type patterns (named types, smart constructors, sealed interfaces, generics) | references/go/type-patterns.md |
| Data modeling — the three layers of validation (validator/v10 → smart ctor → sqlc) | references/go/data-modeling.md |
Error handling (errors.Is/As, typed errors, %w wrapping, no panic) | references/go/error-handling.md |
Concurrency (context.Context, errgroup, channels, locks, -race, goleak) | references/go/concurrency.md |
| HTTP backend stack (gin + slog + validator + pgx, middleware ordering, SSE, WS) | references/go/backend-stack.md |
| RPC stack (Connect-Go default, grpc-go fallback, protovalidate, Buf) | references/go/grpc-connect.md |
| CLI stack (cobra + slog + huh) | references/go/cobra-stack.md |
| Database stack (sqlc + pgx + goose + testcontainers) | references/go/sqlc-pgx.md |
| TUI stack (bubbletea v2 + bubbles v2 + lipgloss v2; CJK / IME support) | references/go/bubbletea-v2.md |
| Testing (Given/When/Then, table-driven, fakes-over-mocks, autogold, rapid) | references/go/testing.md |
Disposable go run scripts | references/go/one-liners.md |
This skill activates whenever you are writing or modifying any .py, .pyi, .rs, .ts, .tsx, .mts, .cts, .go file, or any project manifest (pyproject.toml, Cargo.toml, package.json, tsconfig.json, biome.json, go.mod, go.sum, .golangci.yml, Taskfile.yml, buf.yaml, sqlc.yaml). Even one-off scripts get the full treatment - that is the whole point of uv run + PEP 723, rust-script, bun run, and go run + //go:build ignore: production hygiene with throwaway ergonomics.
The references contain the recipes. Read them before writing code. Re-read them when the model drifts. The post-write review loop is non-negotiable.