| name | coding |
| description | Universal coding rules for any project type โ error handling, testing, API design, dependency hygiene, config/secrets, logging. Extends `coding-agent-guardrails`. |
| version | 0.1.0 |
| triggers | ["coding rules","/coding"] |
| globs | ["**/*"] |
Coding skill
Universal rules for any project type โ backend, CLI, web, bash.
Apply these on every file you touch.
Layering
coding-agent-guardrails (base โ structure + VCS + build discipline)
โ
โโโ coding (this skill โ universal runtime rules)
โ โโโ error handling
โ โโโ testing discipline
โ โโโ API design
โ โโโ dependency hygiene
โ โโโ config/secrets
โ โโโ logging
โ
โโโ android-coding (extends coding + coding-agent-guardrails)
โโโ Kotlin/Compose specifics
โโโ Android-only rules
- Read the
coding-agent-guardrails skill before applying anything here โ it governs every file you touch (file size, code organization, VCS discipline, build behavior) and is always in force.
- This skill extends it; it never replaces it. Where both speak, the tighter rule wins for the matching file type.
- Where a project-type-specific skill (
android-coding, future web-coding, cli-coding) specifies a tighter rule, that skill wins for its file types.
1. Error handling โ catch at boundaries
- Catch errors at the boundary (API handler, CLI entrypoint, background job) โ never let them escape uncaught
- Return typed results (
Result<T>, Either<Error, T>, or a language-idiomatic equivalent) โ never throw from a public API
- Every error the caller must handle is named, not generic
def get_user(id):
return db.query(User, id)
def get_user(id) -> Result[User, NotFoundError]:
try:
return Ok(db.query(User, id))
except DoesNotExist:
return Err(NotFoundError(f"User {id} not found"))
2. Testing โ every non-trivial function has one
- Every public function with non-trivial logic gets at least one test
- Cover edge cases explicitly โ empty input, zero, negative, boundary values
- Mock external dependencies (network, filesystem, clock) โ tests must be deterministic
def divide(a, b):
return a / b
def test_divide_by_zero():
with pytest.raises(ZeroDivisionError):
divide(1, 0)
3. API design โ consistent, versioned, typed errors
- Consistent naming across endpoints/methods โ same verb/noun conventions throughout
- Version endpoints (
/api/v1/...) before a breaking change, not after
- Structured error responses โ a machine-readable code plus a human message, never a bare string
{ "error": "something went wrong" }
{ "error": { "code": "USER_NOT_FOUND", "message": "User 42 not found" } }
4. Dependencies โ never change versions in feature work
- Never bump a dependency version as a side effect of feature work
- Version bumps get their own dedicated, single-purpose change
- requests==2.28.0
+ requests==2.31.0
5. Config & secrets โ never hardcoded
- Secrets live in environment variables โ never in source, never in config committed to git
- No hardcoded URLs, hostnames, or credentials โ inject via config/env
- Feature flags gate incomplete or risky work, not comments
API_KEY = "sk-live-abc123"
API_KEY = os.environ["API_KEY"]
6. Logging โ structured, no PII, appropriate levels
- Structured logs (key-value or JSON) โ not free-text string concatenation
- Never log PII (email, phone, full name, tokens) โ redact or omit
- Log level matches severity:
debug for tracing, warn for recoverable issues, error for failures needing attention
logger.error(f"User {user.email} logged in")
logger.info("user_login", extra={"user_id": user.id})