agent-conventions

Enforce code conventions that make codebases agent-friendly and self-healing. Inspired by Factory AI's "agent-native development" philosophy where lint rules and conventions act as guardrails for AI coding agents. Use this skill whenever generating, reviewing, or refactoring code in any language or framework. Triggers on: code generation, file creation, refactoring, code review, new features, bug fixes, migrations, or any task that produces source code. Covers file organization, naming, searchability, testing, error handling, logging, security, and architectural boundaries. Stack-specific references available for React, Vue, Angular, Laravel, .NET, Python, Go, Rust, and more.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "agent-conventions" with this command: npx skills add zokor/agent-conventions/zokor-agent-conventions-agent-conventions

Agent Conventions

Conventions that make codebases searchable, predictable, and agent-friendly. The core principle: agents write the code; conventions write the law.

Core Philosophy

Every convention serves one or more of these goals:

  • Grep-ability: Code is easy to find via text search (named exports, consistent naming)
  • Glob-ability: File structure is predictable (agents can place and find files deterministically)
  • Self-healing: Conventions prevent drift and regressions automatically

Universal Rules (All Languages)

1. File Organization

Use a predictable layout so agents can place and find files deterministically.

Scope: The folder structures below are organized by project type. Universal rules (naming, exports, testing, errors, logging, security) apply to all project types. Folder structures are type-specific — don't force web app folders onto a game or CLI.


Web Applications (Frontend)

Choose by project size:

Option A: Concern-first (small/medium projects)

Group by concern at the top level, then by domain inside each:

src/
  components/
    layout/              # Structural shell (Header, Footer, Sidebar)
    ui/                  # Reusable primitives (Button, Modal, Input, Toast)
    users/               # User-specific components
    products/            # Product-specific components
  hooks/                 # React hooks / Vue composables (aka composables/)
    useUsers.ts
  services/              # Business logic, orchestration (non-HTTP)
    users.ts
    products.ts
  stores/                # Shared state containers (Pinia/Zustand/Redux)
    auth.ts
    cart.ts
  api/                   # HTTP clients (+ client interceptors/middleware)
    users.ts
    products.ts
  validators/            # Form/input validation schemas (Zod/Yup)
    user.ts
    login.ts
  types/
    user.ts
    product.ts
  enums/
    user.ts
  errors/
    user.ts
  constants/
  utils/
tests/

When to use: Project has < 10 domain areas, or features rarely have more than 2-3 concerns each. Simple, flat, easy to navigate.

Option B: Feature-first (large projects)

Group by feature, then by concern inside each:

src/
  components/
    layout/              # Structural shell (Header, Footer, Sidebar)
    ui/                  # Reusable primitives (Button, Modal, Input, Toast)
  features/
    users/
      components/        # User-specific UI components
      composables/       # Vue composables / React hooks (aka hooks/)
      stores/            # User-specific shared state
      services/          # Business logic, orchestration (non-HTTP)
      api/               # HTTP clients / DTO mappers
      validators/        # Form/input validation schemas
      types/
      enums/
      errors/
      constants/
      utils/
      index.{ext}        # Public surface
  shared/                # Truly cross-feature code (same concern buckets)
tests/                   # If the ecosystem requires a separate test tree

When to use: Project has 10+ domain areas, features have 3+ concerns each, or multiple teams work on separate features. Scales well — deleting a feature means deleting one folder.

When to graduate from A to B

Move a domain from concern-first to a feature folder when it accumulates 3+ concern files (components + service + types + ...). You don't need to migrate the entire project at once.

Shared rules (both approaches)

Decision rule (where to save a new file):

  • Used only by one domain/feature → inside that domain's folder
  • Used by multiple features and stable → src/shared/ (feature-first) or top-level concern folder (concern-first)
  • Shared UI (layout, primitives) → src/components/layout/ or src/components/ui/
  • Boundary code (HTTP, DB, queues) → api/, controllers/, endpoints/, repositories/ (framework idioms)

Composables/hooks vs stores:

  • composables/ (or hooks/) → reusable logic; usually per-caller state
  • stores/ → deliberate shared state container (feature-level global-ish)
  • If you intentionally create a singleton composable/hook (module-scoped state), treat it like a store: put it in stores/ (or name it accordingly)

api/ vs services/ vs hooks/:

  • api/ → raw HTTP calls (getUsers(), createUser()) — thin wrappers around fetch/axios
  • services/ → business logic, orchestration, transformations — no HTTP awareness
  • hooks/ (or composables/) → reactive wrappers that call api/ functions (useUsers() via TanStack Query/SWR)

validators/ — form and input validation:

  • One schema file per domain concept (validators/user.ts, validators/login.ts)
  • Use a schema library (Zod, Yup, Valibot) — never hand-roll validation
  • Schemas can be shared between frontend forms and backend API validation

Interceptors (HTTP/framework):

  • Keep interceptors/middleware at the boundary they intercept (HTTP client/server pipeline)
  • Prefer explicit registration (order matters) over hidden global side effects
  • Name by responsibility: auth, retry, logging, error-mapping, tracing

2. Splitting & Naming — One Domain Concept Per File

Agents should be able to infer file placement from meaning, not memory.

Agent-friendly default:

  • Behavior files (components/services/controllers/handlers): filename matches the primary symbol
    Examples: UserService.ts, UserController.php, UserCard.tsx
  • Definition buckets (types/, enums/, errors/, constants/): one domain concept per file

Examples (TypeScript/Python):

  • types/user.ts / types/user.py → user-only types/contracts
  • enums/user.ts / enums/user.py → user-only enums
  • errors/user.ts / errors/user.py → user-only errors

For ecosystems with “one public type per file” norms (C#, Java, PHP), keep the same idea but split by type and group by folder/namespace:

  • Domain/Users/UserRole.cs, Domain/Users/UserStatus.cs
  • app/Enums/UserRole.php, app/Exceptions/UserNotFoundException.php

Why: Agents can create files without scanning, and humans can navigate by globbing folders.

3. Exports — Prefer Named Over Default (JS/TS)

// ✅ Good — grep-able
export function createUser() {}
export class UserService {}

// ❌ Bad — invisible to grep
export default function() {}
export default class {}

Why: grep -r "export.*UserService" finds it. Default exports are anonymous to search.

4. Imports — Prefer Absolute Over Deep Relative (When Supported)

// ✅ Good
import { UserService } from '@/services/UserService'
use App\Services\UserService;

// ❌ Bad
import { UserService } from '../../../services/UserService'

Why: Absolute paths tell agents the exact module provenance. Relative paths break on file moves.

5. Testing — Close to Source, Mirroring Structure

Prefer colocated tests when the ecosystem supports it (JS/TS, Go):

src/
  users/
    UserService.ts
    UserService.test.ts      ← colocated
    UserController.ts
    UserController.test.ts   ← colocated

If the framework/tooling expects a separate test tree (Laravel, many .NET setups), mirror the feature structure under tests/:

tests/
  features/
    users/
      UserServiceTest.php

Why: Either way, agents can answer “where is the test for this?” by following a deterministic path.

Testing principles (all languages):

  • Test behavior through public interfaces (API, service contract, component props/events), not internal implementation details.
  • Do not add tests for guarantees already enforced at compile-time by the language/type system.
  • Add focused tests for runtime behavior the type system cannot guarantee (business rules, integration boundaries, side effects, failure handling).

5b. E2E / Browser Tests — Frontend Apps

  • Use Playwright for new projects; keep Cypress if already present in the repo.
  • Place tests in e2e/ (or tests/e2e/) at the project root — never colocated with source.
  • File naming: <feature-or-flow>.spec.ts (e.g., checkout.spec.ts, login.spec.ts).
  • Selectors: always use data-testid attributes. Never select by CSS class, tag, or visible text alone.
  • One spec file per user flow, not per component.
  • Full guide: frameworks/frontend/e2e.md

6. Error Handling — Use Typed Errors

// ✅ Good — structured, grep-able
throw new UserNotFoundError(userId)
throw new ValidationError('email', 'Email is required')

// ❌ Bad — unstructured, hard to trace
throw new Error('something went wrong')
throw 'error'

Why: Typed errors create a searchable error taxonomy. Agents can find all error types and handle them consistently.

7. Logging — Structured, Never Bare

// ✅ Good — structured with context
logger.info('user.created', { userId, email })
Log::info('user.created', ['userId' => $userId])

// ❌ Bad — bare string, no context
console.log('user created')
echo "user created";

Why: Structured logs are parseable by machines and searchable by agents.

When scaffolding new modules: Include a lightweight structured logger (or import one from a shared module). A module without logging is incomplete — at minimum, log errors with context at service boundaries. Don't leave logging absent just because there's no existing logger to follow.

7b. Retry & Recovery — Standard Policy

Do not invent ad-hoc retry logic. Follow the standard retry policy in retry.md, which defines:

  • Classify errors as retryable (transient) vs non-retryable (permanent) before retrying.
  • Max 3 attempts with exponential backoff + jitter (capped at 30s, total deadline 60s).
  • Idempotency required — only retry idempotent operations or those with a dedupe mechanism.
  • Observe every attempt with structured logs (operation, attempt number, error class, elapsed time).
  • Circuit breaker — stop calling a dependency after 5 consecutive failures, probe after 30s cooldown.

Full policy, including 409 classification, Retry-After handling, retry budgets, distributed concerns, and queue/dead-letter rules: retry.md.

8. Security & Configuration Basics

  • Never hardcode secrets, tokens, or API keys in source files
  • Environment-specific values (API base URLs, service endpoints, feature flags) should come from environment variables or a config module, not hardcoded constants. Use process.env.API_BASE (or framework equivalent), never const API_BASE = 'https://...'
  • Validate all external input at the boundary (route handlers, API endpoints)
  • Use parameterized queries, never string interpolation for SQL
  • Sanitize output to prevent XSS

9. Architectural Boundaries

  • Feature folders should not reach into another feature's internals
  • Use public module surfaces (index files, facades, service providers)
  • Dependencies flow inward: UI → Application → Domain → Infrastructure
// ✅ Good — uses the public surface
import { createUser } from '@/features/users'

// ❌ Bad — reaches into internals
import { hashPassword } from '@/features/users/utils/crypto'

10. Documentation Signals

  • Public APIs and exported functions should have docblocks/TSDoc
  • Complex business logic should have inline comments explaining "why", not "what"
  • Module-level comments for non-obvious architectural decisions

Stack-Specific References

For detailed conventions per framework or language, read the relevant reference file:

Frontend Frameworks

Backend Frameworks

Languages

General

Read the appropriate reference file based on the project's stack before generating code.

Self-Healing Workflow

When generating or reviewing code, follow this loop:

  1. Generate code following the conventions above
  2. Verify by mentally checking each rule (file placement, naming, exports, tests)
  3. Fix any violations before presenting the code
  4. Prevent regressions by ensuring new patterns match existing codebase conventions

If the project has linters configured (ESLint, PHPStan, Pint, etc.), always run them after generating code and fix violations before presenting results.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

agent-conventions

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

agent-coding

No summary provided by upstream source.

Repository SourceNeeds Review
Security

skillguard-hardened

Security guard for OpenClaw skills, developed and maintained by rose北港(小红帽 / 猫猫帽帽). Audits installed or incoming skills with local rules plus Zenmux AI intent review, then recommends pass, warn, block, or quarantine.

Archived SourceRecently Updated