Version: 0.1 Status: Draft / Working Standard Last updated: 2026-02-07 Author: Sebastian Mang Companion to: AI-Friendly Architecture Documentation Standard (AFADS), AI-Friendly Operational Procedures Standard (AFOPS), AI-Friendly Security Standard (AFSS), AI-Friendly Compliance Standard (AFCS), AI-Friendly Roadmap Standard (AFRS)
This standard defines how to document, structure, and maintain programming conventions so they are:
- human-readable — clear enough for any developer to follow without prior context
- AI-parseable — structured so an LLM can discover, interpret, and follow conventions when generating or reviewing code
- consistent across repos — every convention follows the same format
- derivable — linter configs, formatter configs, and CI checks are derived from conventions, not the other way around
- evolvable — conventions change through documented decisions, not tribal drift
This standard covers programming conventions:
- naming rules (files, variables, functions, types, database objects)
- project structure (directory layout, file organization, module boundaries)
- code patterns (reusable solutions to common problems)
- testing strategy (test types, coverage, organization, CI integration)
- dependency management (addition, updates, auditing, licensing)
- code style (formatting, linting, syntactic preferences)
- code review process (approval rules, checklists, merge strategy)
- AI-assisted development (rules for AI-generated code)
AFPS is not a linter configuration file. It is the human- and AI-readable source of truth from which linter configs, formatter configs, and CI checks are derived. When a linter rule and this standard disagree, this standard wins and the linter config must be updated.
AFPS is not a tutorial or style guide for a specific language or framework. It defines the format for documenting conventions, not the conventions themselves.
AFPS is a companion standard to AFADS and AFOPS. It extends:
- AFADS section 4 (Repository Standard) — AFPS defines the detailed project structure conventions that AFADS references at a high level
- AFOPS section 7 (Step Specification) — AFPS defines the code quality standards that procedure scripts and automation code must follow
A component documented per AFADS and operated per AFOPS writes its code per AFPS.
Every coding convention must be written down. If it is not in the conventions file, it is not a convention. New team members and AI agents must be able to learn every convention by reading the documentation.
Each repository contains its own conventions file. System-wide defaults live in the docs hub. Repo-level conventions override system defaults.
Convention artifacts use YAML metadata so AI agents and CI tooling can discover and enforce them without parsing prose.
Linter configs, formatter configs, and CI checks are derived from the conventions file. The conventions file is the source of truth; tool configs are generated or aligned artifacts.
When a convention changes, the change is recorded as an ADR (per AFADS section 6). The conventions file is updated and the ADR links to the diff.
When an AI agent generates or modifies code, it must read the conventions file first and follow it literally. Conventions are not suggestions.
Every convention artifact MUST be classified as one of these types:
| Type | Description | Example |
|---|---|---|
naming |
Naming rules for files, variables, functions, types, database objects | camelCase for functions, kebab-case for files |
structure |
Project directory layout and file organization rules | src/lib/server/ for server-only code |
pattern |
Reusable code patterns and idioms for common problems | Error handling pattern for load functions |
testing |
Testing strategy, coverage requirements, test file organization | Unit tests co-located, integration tests in tests/ |
dependency |
Rules for adding, updating, and auditing dependencies | Pin major versions, max 1 HTTP client library |
style |
Formatting, linting, and syntactic preferences | Tabs, single quotes, trailing commas |
review |
Code review process, approval rules, merge conventions | 1 approval required, squash merge only |
ai-coding |
Rules specific to AI-assisted code generation and editing | AI must not introduce new dependencies without flagging |
The type field in convention metadata MUST use one of these values.
Conventions live inside the AFADS-required docs/ directory:
docs/
conventions.yaml ← machine-readable convention index (required)
conventions/
naming.md ← one file per convention type
structure.md
patterns/
error-handling.md ← one file per pattern
form-validation.md
data-fetching.md
testing.md
dependencies.md
style.md
review.md
ai-coding.md
Convention files MUST be named using the convention type:
<type>.md ← if there is one file for the type
<type>/<qualifier>.md ← if there are multiple (patterns are always a directory)
Every repository MUST contain docs/conventions.yaml. This file is the machine-readable entry point for AI agents and CI tools. It lists every convention with its ID, type, and file path. See section 12 for the full schema.
Default conventions that apply across all repositories live in the docs hub:
docs/
conventions/
defaults/
naming.md
structure.md
style.md
testing.md
dependencies.md
review.md
ai-coding.md
conventions.yaml ← system-level convention registry
Repository-level conventions override system-level defaults. When a repo convention file exists for a type, it completely replaces the system default for that type. The repo's convention metadata MUST declare overrides_system: true for any convention that overrides a system default.
Every convention artifact MUST begin with a YAML frontmatter block. This block is the primary entry point for AI/LLM parsing.
---
convention_id: naming-sveltekit-webapp
name: SvelteKit Web Application Naming Conventions
type: naming
component_id: webapp # AFADS component_id, or "system" for system-wide
scope: [typescript, svelte] # languages / frameworks this applies to
status: active # active | draft | deprecated
owner: platform-team
last_reviewed: 2026-02-07
---overrides_system: true # this repo convention replaces the system default
supersedes: naming-sveltekit-webapp-v1 # convention_id this replaces
enforced_by: [eslint, biome] # tooling that enforces this convention
tags: [sveltekit, typescript, api]
related_patterns: [pattern-error-handling-load] # convention_ids of related patterns
adr_link: docs/adrs/0003-naming-conventions.md| Field | Required | Type | Description |
|---|---|---|---|
convention_id |
Yes | slug | Stable unique identifier, kebab-case |
name |
Yes | string | Human-readable name |
type |
Yes | enum | One of the types from section 3 |
component_id |
Yes | slug | AFADS component_id, or system for cross-component |
scope |
Yes | list | Languages, frameworks, or domains this applies to |
status |
Yes | enum | active / draft / deprecated |
owner |
Yes | string | Team responsible for maintaining this convention |
last_reviewed |
Yes | date | ISO date of last review |
overrides_system |
No | boolean | Whether this overrides the system-level default |
supersedes |
No | slug | Convention ID this replaces |
enforced_by |
No | list | Tooling that encodes this convention |
tags |
No | list | Searchable tags |
related_patterns |
No | list | Convention IDs of related pattern documents |
adr_link |
No | path | Path to the ADR that justifies this convention |
After the metadata block, every convention MUST include these sections in order:
## Purpose
## Rules
## Examples
## Exceptions
## Enforcement
## AI Guidance
One to three sentences describing what this convention governs and why it exists.
A numbered list of concrete, unambiguous rules. Each rule MUST be testable — a human or AI can determine whether code follows it. Rules use RFC 2119 language (MUST, SHOULD, MAY).
For each rule, at least one compliant example and one non-compliant example, using fenced code blocks with language tags. Examples MUST use the project's actual tech stack where applicable.
Documented cases where a rule may be violated, with justification. If there are no exceptions, state "No exceptions."
How each rule is enforced: which linter rule, which CI check, or "manual review only." If a rule has no automated enforcement, it MUST be flagged as enforcement: manual.
Specific instructions for AI agents generating or modifying code that falls under this convention. This section tells the AI what to do, not just what the rule is.
Patterns are a special convention type (type: pattern) that document reusable solutions to common coding problems. They have additional structure beyond the standard convention body.
In addition to the standard convention body (section 6), patterns MUST include these sections:
## Problem
## Context
## Solution
## Implementation
## Trade-offs
## Related Patterns
A concise statement of the problem this pattern solves.
When to use this pattern: what conditions, constraints, or requirements make it appropriate. Also when NOT to use it.
The pattern itself, described in prose. A narrative explanation of the approach.
A complete, working code example using the project's tech stack. Not a snippet — a full implementation that can be copy-adapted.
What you gain and what you lose by using this pattern. Performance implications, complexity cost, alternatives considered.
Links to other pattern convention_ids that are commonly used together or are alternatives.
The structure convention type defines where code lives. It has additional required sections beyond the standard convention body.
In addition to the standard convention body (section 6), structure conventions MUST include:
## Directory Tree
## File Placement Rules
## Import Path Conventions
## Module Boundaries
A complete directory tree showing the canonical project layout. Uses code blocks with annotations explaining the purpose of each directory.
Rules for where new files go, keyed by file type (component, utility, server route, test, migration, etc.).
Rules for import aliases, relative vs absolute imports, and barrel files (index re-exports).
Which directories may import from which other directories. This defines the dependency direction and prevents circular imports.
The testing convention type defines the testing strategy. It has additional required sections beyond the standard convention body.
In addition to the standard convention body (section 6), testing conventions MUST include:
## Test Types
## Coverage Requirements
## Test File Layout
## Test Naming
## Fixture and Mock Conventions
## CI Integration
Table of test types used in the project with scope, tooling, and run frequency:
| Type | Scope | Tooling | Runs |
|------|-------|---------|------|
| unit | Single function/module | Vitest | Every commit |
| integration | Component + database | Vitest + Supabase local | Every PR |
| e2e | Full user flows | Playwright | Every PR |
| component | Svelte component rendering | Vitest + testing-library | Every commit |Minimum coverage thresholds per test type, per directory, or per component.
Where test files live relative to source files (co-located vs separate tree).
Naming conventions for test files, describe blocks, and individual test cases.
How to organize test fixtures, factories, and mocks. Rules for when to mock vs use real dependencies.
How tests are run in CI, which tests gate merges, which are informational only.
The dependency convention type governs how external dependencies are managed. It has additional required sections beyond the standard convention body.
In addition to the standard convention body (section 6), dependency conventions MUST include:
## Approved Dependencies
## Addition Process
## Update Strategy
## Security Auditing
## License Policy
A list or reference to an approved dependency list. New dependencies not on this list require an ADR.
Steps to follow when adding a new dependency: evaluate, propose ADR, peer review, add.
How and when dependencies are updated (Dependabot/Renovate config, major vs minor vs patch policy).
How dependency vulnerabilities are detected and remediated. Cross-reference to AFSS for vulnerability response controls.
Which open-source licenses are acceptable and which are not.
The review convention type defines the code review process. It has additional required sections beyond the standard convention body.
In addition to the standard convention body (section 6), review conventions MUST include:
## Review Requirements
## Review Checklist
## Merge Strategy
## AI-Generated Code Review
Number of approvals, who can approve, blocking vs advisory reviews.
Standard checklist items reviewers must verify. Cross-references conventions by convention_id.
Squash, merge commit, or rebase. Branch naming conventions. Commit message format.
Additional review requirements when code was generated or modified by an AI agent. What to look for, what to verify beyond normal review.
The docs hub repo MUST contain a convention registry, analogous to the AFADS component registry (components.yaml) and AFOPS procedure registry (procedures.yaml).
docs/conventions.yaml
conventions:
- convention_id: naming-sveltekit-webapp
name: SvelteKit Web Application Naming Conventions
type: naming
component_id: webapp
scope: [typescript, svelte]
status: active
repo: github.com/<org>/webapp
ref: main
path: docs/conventions/naming.md
- convention_id: pattern-error-handling-load
name: SvelteKit Load Function Error Handling
type: pattern
component_id: system
scope: [sveltekit, typescript]
status: active
repo: github.com/<org>/platform-docs
ref: main
path: docs/conventions/patterns/error-handling-load.md
- convention_id: testing-integration-supabase
name: Supabase Integration Testing Strategy
type: testing
component_id: system
scope: [supabase, postgres, vitest]
status: active
repo: github.com/<org>/platform-docs
ref: main
path: docs/conventions/testing.mdconvention_idMUST match the ID in the convention's metadata block.component_idMUST match an AFADScomponent_id, or besystemfor system-wide conventions.- The registry SHOULD be validated in CI (e.g., check that referenced files exist and contain valid metadata).
This section defines how AI agents should interact with AFPS conventions when generating, modifying, or reviewing code.
When an AI agent starts a coding session, it MUST:
- Read
docs/conventions.yamlin the current repository. - If the repo's
conventions.yamlreferences system defaults, read the system-levelconventions.yamlfrom the docs hub. - Build a merged convention set (repo overrides system).
- Identify which conventions apply to the current task based on
scopeandtype.
When generating code, the AI agent MUST:
- Read all applicable convention files before writing any code.
- Follow the Rules section literally.
- Use the Examples section as templates when applicable.
- Follow the AI Guidance section for any convention-specific AI behavior.
- When a pattern exists for the problem being solved, use the pattern's Implementation section as the starting point.
- Never introduce a new dependency without checking the dependency convention's Approved Dependencies list.
When modifying existing code, the AI agent MUST:
- Read all applicable conventions.
- Follow existing code style in the file unless it violates a convention (in which case, follow the convention).
- Not refactor code style in files it was not asked to modify.
- Flag any convention violations it discovers in the code it is modifying, but only fix them if asked to or if the violations are in code it is actively changing.
When reviewing code, the AI agent MUST:
- Read all applicable conventions.
- Check each changed line against the Rules section of applicable conventions.
- Reference the specific
convention_idand rule number when flagging a violation. - Distinguish between MUST violations (blocking) and SHOULD violations (advisory).
When conventions appear to conflict:
- Repo-level conventions override system-level defaults.
- More-specific conventions override less-specific ones (e.g.,
naming-sveltekit-apioverridesnaming-typescript-general). - If a genuine conflict exists, the AI agent MUST flag it to the human and not guess.
When the AI agent recognizes a problem that matches a documented pattern:
- It MUST use the documented pattern rather than inventing a new approach.
- If the agent believes the pattern is suboptimal for the specific case, it must flag this to the human with a justification and ask before deviating.
A convention MUST be reviewed when:
| Trigger | Review deadline |
|---|---|
| 180 days since last review | within 2 weeks |
| Framework major version upgrade | before adoption |
| New team member proposes change | within 1 sprint |
| Convention conflict discovered | within 3 business days |
| AI agent flags repeated friction with a convention | within 1 sprint |
- Create a PR with proposed changes.
- The PR description MUST explain what changed and why.
- The convention owner MUST approve the PR.
- After merge, update
last_reviewedin the convention metadata.
To deprecate a convention:
- Set
status: deprecatedin the metadata. - Add a
supersedesfield pointing to the replacement convention. - Do not delete the file until all references to it have been updated.
A convention is considered compliant when:
- Metadata block contains all required fields (section 5.1)
- All required body sections are present (section 6)
- Every rule is testable and uses RFC 2119 language (section 6.2)
- At least one compliant and one non-compliant example per rule (section 6.3)
- Enforcement method is documented for every rule (section 6.5)
- AI Guidance section is present (section 6.6)
- Convention is registered in
conventions.yaml(section 12) -
last_revieweddate is within 180 days - If type is
pattern, pattern-specific sections are present (section 7) - If type is
structure, structure-specific sections are present (section 8) - If type is
testing, testing-specific sections are present (section 9) - If type is
dependency, dependency-specific sections are present (section 10) - If type is
review, review-specific sections are present (section 11)
| Standard | Section | AFPS Relationship |
|---|---|---|
| AFADS | Section 4 (Repository Standard) | AFPS section 8 defines the detailed project structure that AFADS references at a high level |
| AFADS | Section 5.1 (00-orientation.md) |
Quality attributes in orientation docs should reference convention_ids for how those attributes are achieved in code |
| AFOPS | Section 7 (Step Specification) | Automation scripts and procedure code must follow AFPS conventions. Procedure scripts should reference the applicable convention_ids |
- AFADS
docs/component.md— component documentation remains unchanged - AFADS ADRs — convention changes are recorded as ADRs per AFADS section 6
- AFOPS procedures — AFPS governs code quality, not operational procedures
- Convention metadata
component_idMUST match an AFADScomponent_id. - The
structureconvention's directory tree MUST be consistent with the AFADS section 4 file layout. - The
testingconvention's CI integration section SHOULD reference AFOPS procedures for test environment setup. - The
dependencyconvention's security auditing section MUST reference AFSS security controls for vulnerability management.
---
convention_id: naming-sveltekit-webapp
name: SvelteKit Web Application Naming Conventions
type: naming
component_id: webapp
scope: [typescript, svelte, sveltekit]
status: active
owner: platform-team
last_reviewed: 2026-02-07
enforced_by: [eslint]
---
## Purpose
Defines naming rules for the SvelteKit web application to ensure consistency
across components, routes, utilities, and database interactions.
## Rules
1. **Files**: MUST use kebab-case for all file names.
- Route files use SvelteKit conventions: `+page.svelte`, `+page.server.ts`, `+layout.svelte`.
- Component files: `user-profile-card.svelte`.
- Utility files: `format-currency.ts`.
2. **Variables and functions**: MUST use camelCase.
- `const userName = ...`
- `function fetchUserProfile() { ... }`
3. **Types and interfaces**: MUST use PascalCase.
- `type UserProfile = { ... }`
- `interface DatabaseRow { ... }`
4. **Database tables**: MUST use snake_case (matches Postgres convention).
- `user_profiles`, `order_items`
5. **Database columns**: MUST use snake_case.
- `created_at`, `user_id`
6. **Supabase RPC functions**: MUST use snake_case with verb prefix.
- `get_user_profile`, `update_order_status`
7. **Environment variables**: MUST use UPPER_SNAKE_CASE with project prefix.
- `PUBLIC_SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`
8. **SvelteKit route groups**: MUST use parenthesized names for layout groups.
- `(auth)`, `(app)`, `(marketing)`
## Examples
### Rule 1 — Compliantsrc/lib/components/user-profile-card.svelte src/routes/(app)/dashboard/+page.svelte src/lib/server/format-currency.ts
### Rule 1 — Non-compliant
src/lib/components/UserProfileCard.svelte ← PascalCase file name src/lib/server/formatCurrency.ts ← camelCase file name
### Rules 4–5 — Compliant
```sql
CREATE TABLE user_profiles (
id uuid PRIMARY KEY,
display_name text,
created_at timestamptz DEFAULT now()
);
CREATE TABLE UserProfiles ( -- PascalCase table name
Id uuid PRIMARY KEY, -- PascalCase column name
displayName text -- camelCase column name
);- SvelteKit special files (
+page.svelte,+error.svelte,$types.d.ts) follow SvelteKit conventions, not this rule. node_modules/, generated files, and third-party code are exempt.
| Rule | Tool | Config |
|---|---|---|
| File naming | eslint-plugin-filenames | eslint.config.js |
| Variable/function naming | @typescript-eslint/naming-convention | eslint.config.js |
| Type naming | @typescript-eslint/naming-convention | eslint.config.js |
| Database naming | Manual review + migration linter | CI check on supabase/migrations/ |
| Environment variables | Manual review | enforcement: manual |
When generating code for this component:
- Always use kebab-case when creating new files.
- When creating Supabase queries, use the exact table/column names from the schema (snake_case). Never convert to camelCase in SQL.
- When creating TypeScript types that map to database tables, the type name is PascalCase but property names match the database column names (snake_case), relying on Supabase's generated types.
- When creating environment variables, always add the appropriate prefix
(
PUBLIC_for client-accessible, project prefix for all).
---
## 18. Appendix B: Example Pattern (Error Handling)
```markdown
---
convention_id: pattern-error-handling-load
name: SvelteKit Load Function Error Handling
type: pattern
component_id: system
scope: [sveltekit, typescript]
status: active
owner: platform-team
last_reviewed: 2026-02-07
related_patterns: [pattern-error-handling-api, pattern-form-validation]
---
## Purpose
Defines the standard error handling pattern for SvelteKit `+page.server.ts`
and `+layout.server.ts` load functions.
## Problem
SvelteKit load functions interact with Supabase and must handle database
errors, auth errors, and not-found cases consistently without leaking
internal details to the client.
## Context
Use this pattern in every `load` function in `+page.server.ts` and
`+layout.server.ts` files. Do NOT use this pattern in API routes
(`+server.ts`) — see `pattern-error-handling-api` instead.
## Solution
Wrap Supabase calls in a try/catch, map known error codes to SvelteKit
`error()` responses, and let unknown errors propagate as 500s with a
generic message.
## Implementation
```typescript
// src/routes/(app)/projects/[id]/+page.server.ts
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params, locals }) => {
const { supabase } = locals;
const { data: project, error: dbError } = await supabase
.from('projects')
.select('id, name, description, created_at')
.eq('id', params.id)
.single();
if (dbError) {
if (dbError.code === 'PGRST116') {
// Row not found
throw error(404, { message: 'Project not found' });
}
// Unknown database error — log and return generic 500
console.error('Database error loading project:', dbError);
throw error(500, { message: 'Failed to load project' });
}
return { project };
};
- Load functions MUST NOT return raw Supabase error objects to the client.
- Load functions MUST map
PGRST116to 404. - Load functions MUST log unknown errors server-side before throwing 500.
- Error messages in
error()calls MUST be user-safe (no SQL, no stack traces).
See Implementation section above.
// BAD: leaks database error details to client
export const load: PageServerLoad = async ({ params, locals }) => {
const { data, error: dbError } = await locals.supabase
.from('projects')
.select('*')
.eq('id', params.id)
.single();
if (dbError) {
throw error(500, { message: dbError.message }); // WRONG: leaks internal details
}
return { project: data };
};- Gain: Consistent error responses, no information leakage, debuggable server logs.
- Cost: Slightly more code per load function. Could be reduced with a wrapper utility if the pattern is used very frequently.
No exceptions. All load functions that query Supabase must follow this pattern.
Manual code review. Planned: custom ESLint rule to detect raw dbError.message in error() calls.
When generating a SvelteKit load function that queries Supabase:
- Always use this pattern. Do not invent a different error handling approach.
- Check for
PGRST116(not found) as a named case. - Never pass
dbError.messagedirectly to theerror()helper. - If the query uses
.maybeSingle()instead of.single(), a null result is expected and should not throw 404 — handle it as an empty state.
pattern-error-handling-api— for+server.tsAPI routespattern-form-validation— for form action error handling
---
## 19. Summary
This standard provides:
- a **conventions-as-documentation** approach where coding standards are human-readable, AI-parseable, and version-controlled
- a **structured format** for naming, structure, patterns, testing, dependencies, style, review, and AI-coding conventions
- a **pattern catalog** for reusable solutions to common problems
- a **convention registry** for discoverability across the system
- an **AI integration model** that tells AI agents how to discover, follow, and enforce conventions when generating or reviewing code
- a **derivation model** where linter and formatter configs are derived from the conventions, not the other way around
- a clear **relationship to AFADS and AFOPS** so all three standards work together