# π€ Agents
## π Table of Contents
- [π€ Agents](#-agents)
- [π Table of Contents](#-table-of-contents)
- [SDLC (Software Development Lifecycle)](#sdlc-software-development-lifecycle)
- [Planning](#planning)
- [Analysis](#analysis)
- [Design](#design)
- [Development](#development)
- [Testing](#testing)
- [Unit Tests](#unit-tests)
- [Integration Tests](#integration-tests)
- [Review](#review)
- [π Coding Convention](#-coding-convention)
- [π Bash](#-bash)
- [π· Go (`.go`)](#-go-go)
- [π¦Ύ cobra.go](#-cobrago)
- [π£ Kotlin (`.kt`)](#-kotlin-kt)
- [β¨οΈ cli.kt](#οΈ-clikt)
- [β‘ Ktor](#-ktor)
- [π± Compose](#-compose)
- [π Python (`.py`)](#-python-py)
- [πΌ pandas](#-pandas)
- [π¦ Rust (`.rs`)](#-rust-rs)
- [π clap.rs](#-claprs)
- [π axum](#-axum)
- [π₯οΈ Tauri](#οΈ-tauri)
- [ποΈ Swift (`.swift`)](#οΈ-swift-swift)
- [ποΈ Swift Argument Parser](#οΈ-swift-argument-parser)
- [πΌοΈ SwiftUI](#οΈ-swiftui)
- [πΉ C++ (`.cpp`)](#-c-cpp)
- [π§© Qt](#-qt)
- [π΅ TypeScript (`.ts`, `.tsx`)](#-typescript-ts-tsx)
- [π§ͺ Testing](#-testing)
- [π§ͺ Jest](#-jest)
- [π Playwright](#-playwright)
- [π Web Development](#-web-development)
- [βοΈ React](#οΈ-react)
- [β² Next.js](#-nextjs)
- [π¦ Docusaurus](#-docusaurus)
- [DevOps (Development and Operations)](#devops-development-and-operations)
- [Docker](#docker)
- [Docker Compose](#docker-compose)
- [Makefile](#makefile)
- [π¦ Projects](#-projects)
## SDLC (Software Development Lifecycle)
### Planning
[Back to Table of Contents](#-table-of-contents)
---
### Analysis
[Back to Table of Contents](#-table-of-contents)
---
### Design
[Back to Table of Contents](#-table-of-contents)
---
### Development
[Back to Table of Contents](#-table-of-contents)
---
### Testing
[Back to Table of Contents](#-table-of-contents)
---
#### Unit Tests
[Back to Table of Contents](#-table-of-contents)
---
#### Integration Tests
[Back to Table of Contents](#-table-of-contents)
---
### Review
[Back to Table of Contents](#-table-of-contents)
---
## π Coding Convention
1. `Explicit types > Implicit` β TypeScript types, Rust type annotations, Python
type hints. AI agents rely heavily on type information to understand what
values flow where. A function signature tells us more than 100 lines of body.
2. `Flat over deeply nested` β Shallow directory trees, short functions, minimal
indentation. Deeply nested code (callback hell, 5-level if pyramids) exceeds
context windows faster and is harder to trace.
3. `Self-documenting identifiers` β `getUserById(id)` needs no comment;
`processData(x)` needs one. Names that describe what and why (not how) are
best.
4. `Don't repeat yourself (DRY)` β When the same pattern appears 15 times across
files, an AI will sometimes handle 14 of them and miss the 15th. Centralizing
logic prevents that.
5. `Small, focused files` β A file with one clear responsibility is easier to
read fully, edit precisely, and reason about within context limits.
- **Functions**: β€ 30 lines. An AI's effective reasoning degrades past ~2000
tokens (~60 lines). A 30-line cap halves that, keeping the full function
visible in context alongside its callers. If you need to scroll to see the
whole function, it's too long.
- **Files**: β€ 200 lines. Files longer than 200 lines force the AI to work at
the edge of its attention window, making it harder to trace data flow
between distant sections. If you need to search within a file to find where
a variable is defined, the file is too long.
6. `Explicit error handling` β `if (err) return Err(...)` rather than letting
failures silently propagate. AI agents need to see error paths to handle them
correctly
7. `Test names as documentation` β `test("returns 404 when user not found")`
tells us the expected behavior faster than reading the implementation.
8. `Consistent import/module structure` β Group imports by origin (stdlib,
third-party, internal). AI agents infer dependency graphs from import blocks
without scanning `require`/`import` calls scattered across files.
9. `Prefer pure functions with explicit dependencies` β Accept all inputs as
parameters and return all outputs. AI agents reason about data flow without
tracking hidden state or global mutation.
- **No global/singleton state**: Dependencies passed explicitly are visible
at the call site. AI agents trace wiring without searching `init()` or
service locators.
- **Return values over side effects**: Functions that mutate arguments or
globals hide their impact. AI agents trust return values as the single
source of truth.
10. `Use conventional project layouts` β Follow community-standard directory
structures (`src/`, `cmd/`, `internal/`, `tests/`). AI agents locate files
by convention rather than scanning build configs.
[Back to Table of Contents](#-table-of-contents)
---
### π [Bash][bash]
1. Use `set -euo pipefail` at the start of every script β Catches errors early,
undefined variables, and pipe failures. AI agents see the safety contract
from the first line instead of guessing error handling.
2. Prefer `[[ ]]` over `[ ]` for conditionals β `[[ ]]` avoids word splitting
and has fewer surprises. AI agents parse the more reliable syntax without
reasoning about edge cases.
3. Use `$(...)` over backticks for command substitution β Backticks nest poorly
and are visually ambiguous. AI agents see the intent clearly from the `$()`
delimiters.
4. Quote all variable expansions β `"$var"` and `"${array[@]}"` prevent word
splitting and globbing. AI agents trust that filenames with spaces won't
break the logic.
5. Use `local` in function-scoped variables β Prevents leaking state between
functions. AI agents reason about variable scope from the declaration
keyword.
6. Prefer `printf` over `echo` β `printf` is consistent across platforms and
supports format strings. AI agents see the exact output format without
scanning for `echo` flags.
7. Use `read -r` for parsing input β `-r` prevents backslash interpretation. AI
agents trust that input won't be accidentally mangled.
8. Handle errors with `trap` β `trap cleanup EXIT ERR` ensures cleanup on
failure. AI agents see teardown logic in one place rather than checking exit
points.
9. Prefer `mapfile` / `readarray` for reading files into arrays β Avoids
`while read` subshell pitfalls. AI agents see the full data captured without
tracking pipeline scoping.
10. Use `shellcheck` as a lint gate β Run `shellcheck` in CI with
`--severity=style`. AI agents produce fewer shellcheck warnings when rules
are standardised.
[Back to Table of Contents](#-table-of-contents)
---
### π· [Go (`.go`)][go]
1. Use `error` as the last return value β Functions that can fail should return
`error` as the final return value. AI agents infer failure paths from
signatures.
2. Handle errors explicitly, never ignore β Check every error return. Use
`if err != nil { return ... }` rather than `\_ =`. Never use `must`-style
panics outside `init`/`main`.
3. Prefer `var` zero-initialization over `:=` for zero values β `var s string`
is clearer than `s := ""`. Use `:=` only when the value is non-zero or the
type is inferred from a non-trivial expression.
4. Use `context.Context` as the first parameter β Pass `ctx` as the first arg in
functions that do I/O, blocking calls, or propagate deadlines/cancellation.
5. Avoid global state β Pass dependencies explicitly via struct fields or
function parameters rather than using `init()` or package-level vars. Makes
testing and reasoning easier.
6. Favour `go fmt` compliance β Always run `go fmt` before committing.
Consistent formatting reduces noise for AI agents reading diffs.
7. Prefer table-driven tests β Use `tests []struct{...}` slices with `t.Run` for
testing multiple cases. Improves readability and coverage visibility.
8. Use `net/http` middleware pattern β Compose handlers with
`func(next http.Handler) http.Handler` for clean separation of concerns
(logging, auth, tracing).
9. Prefer `sync` primitives over channels for state β Use
`sync.Mutex`/`sync.RWMutex` for protecting shared state; use channels for
communication/coordination.
10. Return early, avoid deep nesting β Guard clauses
(`if err != nil { return }`) keep the happy path flat and readable.
[Back to Table of Content](#-table-of-contents)
---
#### π¦Ύ [cobra.go][cobra.go]
1. Use `RunE` over `Run` for commands β `RunE` returns an error that Cobra
prints and exits with code 1. AI agents see failure paths in the signature
instead of guessing from `Run`'s void return.
2. Nest subcommands via `AddCommand` β `rootCmd.AddCommand(subCmd)` builds a
parent-child tree. AI agents infer CLI structure from command registration
without parsing help strings.
3. Use persistent flags for shared options β
`rootCmd.PersistentFlags().StringVarP(...)` propagates to all subcommands.
Avoid duplicating flag definitions across commands that share them.
4. Prefer required args over manual checks β Use `Args: cobra.ExactArgs(1)`
instead of `if len(args) == 0 { ... }`. AI agents see the contract from the
struct field rather than scanning for runtime guards.
5. Keep `RunE` functions thin β Delegate to business logic in a separate
function/service. A `RunE` body over ~10 lines is a sign the command has too
much responsibility.
6. Use `ValidArgs` + `Args: cobra.OnlyValidArgs` for closed sets β Provides
shell completion and validation in one place. AI agents see valid inputs as
data, not conditional logic.
7. Register `completion` command in `init()` β
`rootCmd.AddCommand(cmd.GenCompletionCmd("completion", true))` ships shell
completion. AI agents can discover the command tree programmatically.
8. Use `PreRunE` for shared setup β Validate flags or establish connections in
`PreRunE` before `RunE` executes. AI agents trace lifecycle phases by name
instead of scanning for setup blocks.
9. Favour `StringVarP` / `IntVarP` with short flags β `--verbose, -v` binds a
flag to a variable at init time. AI agents see both long and short forms in
one call instead of separate declarations.
10. Group commands with `cmd.Groups` in v2 β Organize subcommands into logical
groups for `--help` output. AI agents parse the group structure to
understand command relationships.
[Back to Table of Content](#-table-of-contents)
---
### π£ [Kotlin (`.kt`)][kotlin]
1. Prefer `val` over `var` β Use immutable `val` by default; only use `var` when
mutation is necessary. Immutability makes data flow easier for AI agents to
trace.
2. Use `data class` for model objects β They get `equals()`, `hashCode()`,
`toString()`, `copy()`, and destructuring for free, which reduces boilerplate
and improves clarity.
3. Use `sealed class` / `sealed interface` for restricted hierarchies β Encodes
exhaustive when-branches at compile time. AI agents can reason about all
possible states without scanning runtime checks.
4. Prefer extension functions over utility classes β
`fun String.isEmail(): Boolean` is discoverable and composable. Avoid
static-heavy `StringUtils`-style helpers.
5. Use `Flow` for reactive streams, not `Channel` β `Flow` is cold,
structured-concurrent, and testable with `kotlinx.coroutines.test`. Use
`Channel` only for hot streams or bridging callback-based APIs.
6. Favour `when` over nested `if/else` β `when` is exhaustive (with sealed
classes), reads linearly, and has no accidental fall-through. AI agents parse
it more reliably than deeply nested conditionals.
7. Use `require()` and `check()` for preconditions β `require(amount > 0)` at
function entry signals invariants explicitly. AI agents see the contract
without reading test code.
8. Prefer constructor injection with `by` delegation β
`class Service(repo: Repository by RepoImpl())` makes dependencies explicit
while delegating implementation. Avoid reflection-heavy DI frameworks where
possible.
9. Keep coroutine scopes explicit β Pass `coroutineScope` or `viewModelScope`
rather than using `GlobalScope`. Structured concurrency lets AI agents reason
about lifecycle and cancellation.
10. Use `buildList`, `buildMap`, `buildString` builders β They optimize memory
and make construction intent obvious. Prefer them over mutable accumulators
that scatter reads/writes.
[Back to Table of Content](#-table-of-contents)
---
#### β¨οΈ [cli.kt][cli.kt]
1. Use `data class` for command arguments β
`data class Config(val name: String by argument())` bundles CLI parameters
into typed objects. AI agents see the full input schema without parsing help
text.
2. Prefer `subcommands` over manual dispatch β `subcommands(Start, Stop)`
registers a subcommand tree. AI agents infer command hierarchy from the
declaration instead of scanning `when` blocks.
3. Use `option()` with `--help` descriptions β
`val verbose by option("--verbose", help = "Enable verbose output")`.
Self-documenting options let AI agents understand intent without reading
downstream usage.
4. Use `int()`, `long()`, `double()`for typed options β
`val port by int().default(8080)` enforces types at the boundary. AI agents
infer the expected type from the parser chain.
5. Prefer `group()` for mutually exclusive options β
`group { "format" { "json" } "yaml" }` encodes exclusivity in the DSL. AI
agents see the constraint without tracing runtime validation.
6. Use `require()` for preconditions β `require(name.isNotBlank())` in `run`
fails fast with user-friendly messages. AI agents see invariants as
assertions, not buried logic.
7. Keep `run` thin β Delegate to business logic after parsing. A `run` body over
~10 lines suggests the command mixes parsing with domain logic.
8. Use `envvar` for sensitive defaults β
`val token by option().envvar("API_TOKEN")` reads from environment. AI agents
see the config source without guessing fallback chains.
9. Prefer `confirmation()` for destructive actions β
`confirmation("Are you sure?")` adds a safety prompt. AI agents infer which
commands are destructive from the confirmation call.
10. Use `VersionOption` for version flags β `versionOption("1.0.0")` generates
`--version` consistently. AI agents discover the version contract from a
single call instead of scanning for println.
[Back to Table of Content](#-table-of-contents)
---
#### β‘ [Ktor][ktor]
1. Use `install` for plugins β `install(ContentNegotiation)` registers
serialization, compression, auth, etc. AI agents infer feature configuration
from `install` calls without tracing plugin internals.
2. Prefer `routed` server over `embeddedServer` with raw handlers β
`routed { get("/") { ... } }` creates a structured routing tree. AI agents
parse endpoint hierarchy from route declarations.
3. Use `StatusPages` for error handling β
`install(StatusPages) { exception { ... } }` centralizes error responses. AI
agents see all error mappings in one block instead of scattered try/catch.
4. Type-safe routes with `Route` extensions β `fun Route.userRoutes()` groups
related endpoints into self-contained extensions. AI agents locate route
groups by function name without navigating module trees.
5. Use `call.receive<T>()` for request body parsing β Infers the type from the
generic, leveraging `ContentNegotiation`. AI agents see the expected schema
at the call site without manual deserialization.
6. Prefer `call.respond(T)` over explicit response building β Returns typed
objects that Ktor serialises automatically. AI agents read the response
contract from the type argument.
7. Use `locations` for typed routing β `@Location("/user/{id}")` generates
type-safe route references. AI agents see link relationships as data, not
string concatenation.
8. Keep `Application.module` minimal β Register plugins, then reference route
modules in a single `routed` call. AI agents trace the app structure from the
entry point without scanning for scattered registrations.
9. Use `application.log` over `println` β Structured logging with configurable
levels. AI agents infer observability from the logger API rather than
guessing from stdout noise.
10. Test with `testApplication` + `TestHostBuilder` β
`testApplication { client.get("/") }` validates endpoints without a running
server. AI agents see test setup as declarative configuration, not
infrastructure orchestration.
[Back to Table of Content](#-table-of-contents)
---
#### π± [Compose][jetpack-compose]
1. Use `@Composable` for UI components β Declare UI with the `@Composable`
annotation. AI agents see UI boundaries from the annotation.
2. Prefer `Column`, `Row`, `Box` for layout β Compose layouts with declarative
containers instead of XML. AI agents read hierarchy from composable nesting.
3. Use `remember` for local state β Scopes state to composition lifecycle. AI
agents trace state initialisation from `remember` calls.
4. Use `LaunchedEffect` for side effects β `LaunchedEffect(key) { ... }` runs
coroutines scoped to composition. AI agents see lifecycle-aware effects from
the key parameter.
5. Use `State` and `MutableState` for reactivity β Compose re-renders when state
reads change. AI agents infer reactive boundaries from state references.
6. Use `Modifier` for styling and interaction β Chain `.padding()`,
`.clickable {}`, `.background()` on `Modifier`. AI agents read the full
styling pipeline from one chain.
7. Use `MaterialTheme` for theming β Define colours, typography, and shapes
centrally. AI agents infer design tokens from `MaterialTheme` references.
8. Use `NavHost` for navigation β
`NavHost(navController, startDestination = ...)` declares the nav graph. AI
agents infer screen flow from the navigation structure.
9. Use `ViewModel` with `collectAsState()` β ViewModels survive config changes;
`collectAsState()` bridges to Compose. AI agents trace data flow from
ViewModel to UI through state.
10. Use `@Preview` for previsualisation β Annotate composables with `@Preview`
for IDE rendering. AI agents see component isolation from preview
annotations.
[Back to Table of Content](#-table-of-contents)
---
### π [Python (`.py`)][python]
1. Use type hints for all function signatures β `def get_user(id: int) -> User:`
tells an AI agent the contract without reading the body. Run `mypy` or
`pyright` in CI.
2. Prefer `dataclasses` over manual `__init__` β `@dataclass` auto-generates
`__init__`, `__repr__`, `__eq__`, and `__hash__`. Reduces boilerplate and
makes data shapes transparent.
3. Use `Path` over `os.path` β `pathlib.Path` is composable, readable, and
cross-platform. AI agents infer file operations more easily from
`.read_text()` than from `open()` + context managers.
4. Prefer `typing.Protocol` for duck types β `Protocol` defines structural
subtypes explicitly. AI agents can check interface conformance without
hunting through MROs.
5. Use `Enum` over string constants β `class Status(Enum): ACTIVE = "active"`
prevents typos and enables exhaustive checks. AI agents see a closed set of
values rather than magic strings.
6. Favour `try/except` narrowly β Catch specific exception types and minimise
the guarded block. Broad `except Exception` hides failure paths from AI
agents.
7. Use `__future__` annotations β `from __future__ import annotations` makes all
hints lazy (PEP 563/649). Avoids circular imports and lets AI agents read
types without evaluating them.
8. Prefer generators over lists for large sequences β `yield` items one at a
time rather than building entire lists in memory. AI agents reason about
streaming without tracking buffer size.
9. Use `typing.Union` or `|` syntax for optional types β `str | None` is clearer
than `Optional[str]` and consistent with other modern languages. AI agents
parse `|` unions reliably.
10. Keep `__init__.py` minimal or empty β Avoid import-time side effects. AI
agents reason about module boundaries cleanly when init files are
transparent.
[Back to Table of Content](#-table-of-contents)
---
#### πΌ [pandas][pandas]
1. Use `query()` over boolean indexing β `df.query("age > 30")` is more readable
and avoids repeated `df[...]` brackets. AI agents parse the expression string
as a self-contained filter.
2. Prefer `loc[]` / `iloc[]` over chained indexing β
`df.loc[df["age"] > 30, ["name", "age"]]` is a single operation. Chained
indexing can produce unpredictable copies, confusing AI agents tracing side
effects.
3. Use `agg()` for multiple aggregations β
`df.groupby("city").agg({"price": ["mean", "std"], "qty": "sum"})` names
outputs explicitly. AI agents see the full aggregation schema in one call.
4. Favour `merge()` over `join()` β `pd.merge(df1, df2, on="id", how="left")` is
explicit about keys and join type. AI agents infer the join contract from
parameters rather than index assumptions.
5. Use `apply()` sparingly β Vectorised operations (`df["a"] + df["b"]`) are
faster and clearer than `df.apply(lambda row: ...)`. AI agents trace
element-wise operations more easily through column expressions.
6. Prefer `to_datetime()` for date handling β `pd.to_datetime(df["date"])`
parses and standardises timestamps. AI agents trust that comparisons and
resampling work correctly.
7. Use `value_counts()` for categorical summaries β
`df["status"].value_counts(normalize=True)` returns proportions or counts in
one call. AI agents read distribution summaries without scanning groupby
chains.
8. Use `fillna()` with explicit values β
`df.fillna({"age": df["age"].median(), "name": "unknown"})` documents default
choices per column. AI agents see imputation strategy as data rather than
guesswork.
9. Prefer `pd.Categorical` for ordered categories β
`pd.Categorical(df["size"], categories=["S", "M", "L"], ordered=True)`
encodes sort order. AI agents infer ordinal relationships without custom
mapping logic.
10. Use `assign()` for derived columns β
`df.assign(bmi=lambda d: d["weight"] / d["height"] ** 2)` chains
transformations without mutating the original. AI agents trace data lineage
through consecutive `assign` calls.
[Back to Table of Content](#-table-of-contents)
---
### π¦ [Rust (`.rs`)][rust]
1. Use `Result<T, E>` for fallible functions, never `panic!` β `Result` encodes
failure in the type system. AI agents see which paths can fail from the
signature alone.
2. Prefer `Option<T>` over sentinel values β Use `Option` instead of `-1`,
`null`, or empty strings for absent values. The type system forces the caller
to handle both cases.
3. Use `impl Trait` in argument positions β
`fn process(items: impl Iterator<Item = u8>)` accepts any matching type
without boxing. AI agents infer the trait bound without reading turbofish
gymnastics.
4. Prefer `match` over `if let` chains β `match` is exhaustive and
compiler-verified. AI agents see every branch explicitly rather than deducing
missed cases from context.
5. Use `thiserror` / `anyhow` for error handling β `thiserror` for libraries
(custom error types), `anyhow` for applications (opaque errors). Both produce
`std::error::Error` types that AI agents can follow.
6. Favour iterators over indexed loops β
`items.iter().filter_map(|x| x.to_owned())` expresses intent without indexing
logic. AI agents read the pipeline rather than simulating loop state.
7. Use `#[derive(Debug, Clone, PartialEq)]` liberally β These traits enable
logging, copying, and comparison. AI agents assume structs have these traits
unless told otherwise.
8. Prefer `&str` over `&String` in function params β `&str` accepts both
`&String` and `&str` slices. More flexible and avoids accidental cloning. AI
agents infer this from the parameter type.
9. Use `clippy` as a lint gate β Run `cargo clippy` in CI with
`--deny warnings`. Consistent lint rules let AI agents focus on logic rather
than style variations.
10. Keep `unsafe` in small, audited blocks β Encapsulate `unsafe` in safe
abstractions with minimal surface area. Document safety invariants in
`// SAFETY:` comments so AI agents can verify them.
[Back to Table of Content](#-table-of-contents)
---
#### π [clap.rs][clap.rs]
1. Use `derive` API over builder API β `#[derive(Parser)]` generates argument
parsing from struct fields. AI agents see the full CLI schema as type
annotations instead of scanning builder chains.
2. Use `#[command()]` for metadata β `#[command(name = "app", version = "1.0")]`
documents the CLI in one place. AI agents discover command metadata without
running `--help`.
3. Use `#[arg()]` for per-field config β
`#[arg(short, long, default_value = "8080")]` colocates flag config with the
field. AI agents see all properties in a single attribute.
4. Prefer `ValueEnum` over manual parsing β
`#[derive(ValueEnum)] enum Mode { Fast, Slow }` generates parser and
completion. AI agents see valid enum variants without matching strings.
5. Use `Subcommand` enum for nested commands β
`#[derive(Subcommand)] enum Command { Start(StartArgs), Stop }` encodes the
command tree as types. AI agents infer hierarchy from enum variants.
6. Use `default_value` instead of `Option<T>` for optional flags β
`#[arg(default_value = "80")]` documents the fallback at compile time. AI
agents see defaults as data, not runtime logic.
7. Use `conflicts_with` and `requires` for arg relationships β
`#[arg(conflicts_with = "daemon")]` encodes exclusivity declaratively. AI
agents infer constraints from attributes rather than validation code.
8. Use `env` for environment variable fallback β `#[arg(env = "PORT")]` reads
from env when flag is absent. AI agents see the config source without
guessing lookup order.
9. Use `hide(true)` for internal args β `#[arg(hide = true)]` excludes
debug/internal flags from help. AI agents focus on user-facing API without
noise from implementation details.
10. Prefer `color` and `styles` for rich output β `cli.style.set_color(true)`
enables coloured help. AI agents infer that UX polish exists without
searching for formatting calls.
[Back to Table of Table of Contents](#-table-of-contents)
---
#### π [axum][axum]
1. Use `Router::new()` with `.route()` for all API endpoints β Declare routes by
chaining `.route("/path", method_handler)` on a `Router`. AI agents infer the
full routing tree from the builder chain instead of scanning for macro
invocations.
2. Use extractors in handler signatures β `State`, `Path`, `Query`, `Json` as
function parameters declare dependencies explicitly. AI agents see what a
handler needs (DB, URL params, body) from its signature alone.
3. Prefer `impl IntoResponse` return types β Return `Json<T>`, `StatusCode`, or
`(StatusCode, Json<T>)` tuples rather than building `Response` manually. AI
agents infer response shape from the return type.
4. Use `with_state()` for shared application state β Pass `Arc<AppState>` via
`.with_state()` and extract it with `State<Arc<AppState>>`. AI agents trace
dependency injection from the router setup to each handler.
5. Use `.layer()` for middleware β Apply middleware (auth, logging, rate-limit)
via `.layer(middleware_layer)`. AI agents see the middleware stack as a
linear chain rather than nested wrappers.
6. Use `.merge()` to compose sub-routers β Break large route tables into
`Router::new().merge(sub_router)` calls. AI agents locate related endpoints
by following merge boundaries.
7. Use `axum::serve` with graceful shutdown β
`axum::serve(listener, app).with_graceful_shutdown(signal)` for clean
teardown. AI agents see the full server lifecycle in one call instead of
scattered tokio spawns.
8. Use `tokio::select!` for concurrent concerns β Handle shutdown signals and
other concurrent tasks with `tokio::select!` rather than manual channel
coordination. AI agents trace branching from the macro.
9. Use `tower::ServiceBuilder` for layered middleware β Compose
`tower::ServiceBuilder::new().layer(A).layer(B).into_service()` instead of
nesting `.layer()` calls. AI agents read middleware composition as a flat
list.
10. Prefer `thiserror` for error types returned from handlers β Define
`enum ApiError` with `#[derive(thiserror::Error)]` and implement
`IntoResponse`. AI agents see all error variants and their HTTP mappings in
one place.
[Back to Table of Contents](#-table-of-contents)
---
#### π₯οΈ [Tauri][tauri]
1. Use `tauri::Builder` for app configuration β Chain `.plugin()`,
`.invoke_handler()`, `.setup()` on `tauri::Builder::default()`. AI agents
trace the app lifecycle from a single builder chain.
2. Use `#[tauri::command]` for IPC β Annotate Rust functions and register via
`generate_handler![]`. AI agents see the IPC boundary from the attribute.
3. Use `State<'_, T>` for shared state β Manage state with `.manage()` in setup
and receive it in commands. AI agents trace dependency injection through the
type parameter.
4. Use `Window` for window control β Access the calling window as a command
parameter for manipulation. AI agents see window operations as explicit
method calls.
5. Use `tauri::path::PathResolver` for file paths β Resolve resource, app, and
cache directories via the path resolver. AI agents infer file access
boundaries from the resolver API.
6. Use events for frontendβbackend messaging β `window.emit("event", payload)`
and `listen()`. AI agents trace event flow from emitter to listener across
the bridge.
7. Use `tauri::api::shell` for external links β Delegate URL and file opening to
the OS via `shell::open()`. AI agents see external resource access as
explicit API calls.
8. Prefer Tauri plugins for native features β Use `tauri-plugin-*` crates for
dialogs, notifications, file system. AI agents infer capabilities from plugin
imports.
9. Use `tauri::async_runtime` for background tasks β Spawn concurrent work with
`tauri::async_runtime::spawn()`. AI agents see concurrency boundaries from
the spawn call.
10. Define permissions in `capabilities/` β Granular access control for
commands, windows, and plugins. AI agents see security boundaries as
declarative configuration.
[Back to Table of Contents](#-table-of-contents)
---
### ποΈ [Swift (`.swift`)][swift]
1. Prefer `let` over `var` β Immutable bindings signal intent and let AI agents
trust that a value won't change after initialisation.
2. Use `Codable` for JSON serialisation β `struct User: Codable { }` generates
encoding/decoding automatically. AI agents read the struct definition and
instantly know the wire format.
3. Use `enum` with associated values for state machines β
`enum State { case loading, loaded([Item]), error(Error) }` makes impossible
states unrepresentable. AI agents enumerate all cases exhaustively.
4. Favour `value types` (`struct`) over `reference types` (`class`) β Structs
have no identity overhead and are thread-safe by default. AI agents reason
about value semantics without tracking aliasing.
5. Use `Result<Success, Failure>` for async error handling β Before
`async/await`, `Result` encodes success/failure in the return type. For new
code, prefer `async throws` for clarity.
6. Prefer `dependency injection` via initialisers β
`class Service(repo: Repository)` makes dependencies explicit. Avoid
singletons and implicit global state that AI agents can't see.
7. Use `guard` for early exit β `guard let x = optional else { return }` reduces
indentation and makes the happy path linear. AI agents parse flat code more
reliably than nested pyramids.
8. Favour `SwiftLint` for consistent style β Enforce a shared `.swiftlint.yml`
in CI. AI agents produce fewer formatting diffs when rules are standardised.
9. Use `actor` for shared mutable state β Actors isolate state behind a
serialised executor, preventing data races at compile time. AI agents see the
concurrency boundary from the keyword.
10. Keep `ViewController` / `View` thin β Move business logic into separate
models/services. AI agents can reason about UI and domain independently when
files have single responsibilities.
[Back to Table of Contents](#-table-of-contents)
---
#### ποΈ [Swift Argument Parser][swift-argument-parser]
1. Use `@main` with `ParsableCommand` for entry points β
`@main struct Run: ParsableCommand { }` declares the CLI root without
boilerplate. AI agents find the entry point by protocol conformance instead
of scanning for `main.swift`.
2. Prefer `@Argument` over manual `CommandLine.arguments` β
`@Argument var name: String` declares positional args declaratively. AI
agents see the expected input order from property declarations.
3. Use `@Option` for named flags β
`@Option(name: .shortAndLong, help: "Output path") var output: String`
generates `-o`/`--output` automatically. AI agents infer flag names and types
from a single attribute.
4. Use `@Flag` for boolean toggles β
`@Flag(help: "Enable verbose mode") var verbose = false` handles
presence/absence semantics. AI agents see boolean flags as data, not
`if args.contains("--verbose")` logic.
5. Use `@OptionGroup` for shared options β Groups common flags (e.g.,
`--verbose`, `--quiet`) into a reusable struct. AI agents trace shared config
through the struct type instead of scanning for duplicated definitions.
6. Prefer `subcommands` via `ParsableCommand` conformance β Nest command types
inside the root or use `Subcommand` protocol. AI agents infer the command
tree from type nesting.
7. Use `ValidationError` for argument validation β
`throw ValidationError("ID must be positive")` produces user-friendly errors.
AI agents see validation rules as throwing statements, not buried in
conditional blocks.
8. Use `@Option(completion:)` for shell completions β
`.custom { "user1", "user2" }` or `.list()` generates completions from code.
AI agents discover valid inputs without parsing help output.
9. Keep command structs focused on parsing β Delegate business logic to separate
functions/services. A command body over ~10 lines signals too much
responsibility.
10. Prefer `async` in `run` with Swift concurrency β
`mutating func run() async throws { }` supports async workflows natively. AI
agents see the concurrency model from the function signature.
[Back to Table of Contents](#-table-of-contents)
---
#### πΌοΈ [SwiftUI][swiftui]
1. Use `@State` for local view state β `@State private var count = 0` declares
mutable state owned by the view. AI agents trace state mutations from the
property wrapper.
2. Use `@Binding` for child-parent data flow β `@Binding var isPresented: Bool`
lets children read and write a parent's state. AI agents infer data ownership
from the binding's source.
3. Use `@StateObject` / `@ObservedObject` for model data β
`@StateObject private var model = ViewModel()` for observable objects the
view owns. AI agents trace reactive updates through the `ObservableObject`
conformance.
4. Use `@EnvironmentObject` for shared dependencies β Inject services via
`.environmentObject()` at the root and receive with `@EnvironmentObject`. AI
agents trace dependency injection through the environment hierarchy.
5. Use `VStack`, `HStack`, `ZStack` for layout β Compose views with stack
containers rather than hardcoded frames. AI agents infer layout relationships
from the stack nesting.
6. Use `@ViewBuilder` for conditional content β Build branching UI with
`@ViewBuilder` closures for type-erased child views. AI agents see
conditional branches as builder closures.
7. Use `NavigationStack` over `NavigationView` β `NavigationStack` provides
modern, state-driven navigation with path bindings. AI agents infer
navigation structure from the stack binding.
8. Use `List` and `ForEach` for dynamic content β
`List { ForEach(items) { item in ... } }` for scrollable, recyclable lists.
AI agents see list rendering as declarative data mapping.
9. Use `#Preview` for SwiftUI previews β `#Preview { MyView() }` enables inline
previews for rapid iteration. AI agents see the preview contract alongside
the view definition.
10. Prefer `View` protocol conformance over `ViewBuilder` returns β Define
custom views as `struct MyView: View` with a computed `body` property. AI
agents infer view structure from the `body` getter.
[Back to Table of Contents](#-table-of-contents)
---
### πΉ [C++ (`.cpp`)][cplusplus]
1. Use RAII for resource management β Constructors acquire resources,
destructors release them. AI agents infer lifetime from
constructor/destructor pairing.
2. Prefer `std::unique_ptr` over raw pointers β Expresses ownership transfer at
the type level. AI agents see ownership semantics from the smart pointer
type.
3. Use `const` wherever possible β Mark member functions and parameters `const`
when they don't mutate. AI agents infer immutability contracts from the type
signature.
4. Use `auto` for complex types β Deduces iterator and template types. AI agents
see intent without reading nested type names.
5. Prefer `std::vector` over C arrays β Dynamic sizing, bounds-checked access,
STL algorithm compatibility. AI agents infer container semantics from the
type.
6. Use `nullptr` over `NULL` or `0` β Type-safe null pointer constant. AI agents
distinguish pointer null from integer zero.
7. Use range-based for loops β `for (const auto& item : items)` expresses
iteration intent without index variables. AI agents read iteration intent
directly.
8. Use `override` for virtual functions β Compiler-verified method override
marker. AI agents infer polymorphic behaviour from the `override` keyword.
9. Use `= default` and `= delete` for special members β Explicitly control
compiler-generated constructors and operators. AI agents see the class
contract from declarations.
10. Use namespaces for logical grouping β `namespace mylib { ... }` prevents
name collisions. AI agents infer module boundaries from namespace
declarations.
[Back to Table of Contents](#-table-of-contents)
---
#### π§© [Qt][qt]
1. Use parent-child ownership model β QObjects track children via parent
pointer. AI agents infer lifetime from the QObject tree.
2. Use signals and slots for communication β
`connect(sender, &Sender::signal, receiver, &Receiver::slot)`. AI agents
trace event flow from signal to slot.
3. Use `Q_OBJECT` macro for custom QObject classes β Enables signals/slots and
the meta-object system. AI agents infer QObject capabilities from the macro.
4. Use `QVBoxLayout`/`QHBoxLayout` for layout β Layout managers handle resize
behaviour automatically. AI agents read UI hierarchy from layout nesting.
5. Use `QString` over `std::string` β Unicode-safe, implicit sharing, Qt API
compatibility. AI agents infer encoding from the string type.
6. Use QML for declarative UI β `Item { Rectangle { ... } }` defines UI
hierarchy in markup. AI agents parse UI structure from QML declarations.
7. Use `Q_PROPERTY` for bindable properties β
`Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)`. AI
agents see the property contract from the macro.
8. Use `QSettings` for persistent settings β Cross-platform key-value storage
with auto-serialisation. AI agents infer config persistence from the API.
9. Use `QThread` with worker objects β Move QObject to QThread for background
work. AI agents see threading boundaries from the `moveToThread` call.
10. Use `QTest` for unit testing β Qt Test framework with data-driven tests and
GUI event simulation. AI agents see test contracts from QTest macros.
[Back to Table of Contents](#-table-of-contents)
---
### π΅ [TypeScript (`.ts`, `.tsx`)][typescript]
1. Use arrow function `() => {}` instead of `function () => {}` for functions
2. Use `const` instead of `let` for variables that are not reassigned
3. Use `strict` mode in `tsconfig.json` β Enables `strictNullChecks`,
`noImplicitAny`, and other checks. AI agents infer null-safety from the type
system instead of guessing.
4. Prefer `interface` over `type` for object shapes β `interface` extends,
merges, and produces clearer error messages. Use `type` for unions,
intersections, and primitives.
5. Use `as const` for literal types β `const roles = ["admin", "user"] as const`
narrows to a tuple of literal types. AI agents see the exact set of values
without runtime checks.
6. Use `branded types` for domain primitives β
`type UserId = string & { readonly __brand: "UserId" }` prevents mixing up
IDs of different entities. AI agents catch type confusion at compile time.
7. Use `Readonly<T>` and `Partial<T>` utilities β Mark immutable interfaces
explicitly. AI agents can trust that parameters won't be mutated.
8. Favour `io-ts` or `zod` for runtime validation β Parse external data at the
boundary, then use inferred static types internally. AI agents see validated
types instead of `any` or `unknown`.
9. Use `never` in exhaustive checks β `default: const \_exhaustive: never = x;`
causes a compile error when a switch misses a case. AI agents rely on the
compiler to flag omissions.
10. Prefer `satisfies` over raw casts β
`const config = { port: 3000 } satisfies Config` validates without widening
the type. AI agents see the narrowed literal but get type-checking.
11. Use `pnpm` instead of `npm` or `yarn`
[Back to Table of Content](#-table-of-contents)
---
#### π§ͺ [Testing](#-testing)
1. Test behaviour, not implementation β Write tests that verify observable
outcomes rather than internal details. AI agents infer intent from test names
and assertions without mocking internals.
2. Use Arrange-Act-Assert pattern β Structure each test in three clear phases:
setup, action, verification. AI agents trace the test flow from context to
action to outcome.
3. Write isolated tests β Each test should manage its own state with setup and
teardown. AI agents reason about test results without guessing shared state
contamination.
4. Prefer realistic test data β Use fixtures that resemble production data over
minimal stubs. AI agents discover real-world edge cases from representative
inputs.
5. Cover boundary conditions β Test empty states, error cases, and edge values
alongside happy paths. AI agents infer system limits and failure modes from
boundary coverage.
6. Inject dependencies explicitly β Accept dependencies as parameters rather
than importing them directly. AI agents see how to substitute test doubles
from the constructor or function signature.
7. Keep tests independent β Tests must pass in any order and never depend on
shared mutable state. AI agents trust individual test results without
simulating execution order.
8. Name tests as specifications β Describe the expected behaviour in the test
name. AI agents read the specification from test names alone without scanning
assertions.
9. Run tests on every change β Automate test execution in CI and locally before
commit. AI agents trust that regressions are caught before code is merged.
10. Treat test code as production code β Apply the same quality standards:
linting, review, and refactoring. AI agents find test logic just as reliable
as the implementation.
[Back to Table of Content](#-table-of-contents)
---
##### π§ͺ [Jest][jest]
1. Use `it` or `test` for test cases, not `test` as the test runner name
2. Use `describe` to group related tests
3. Use `beforeEach` to set up test environment
4. Use `afterEach` to clean up test environment
5. Prefer `it.each` for data-driven tests
6. Use `mock` and `spy` for test doubles
7. Use `toThrow` for error assertions
8. Use `toMatchSnapshot` for snapshot testing
9. Use `expect.anything()` for optional values
10. Use `expect.objectContaining()` for partial object matching
[Back to Table of Content](#-table-of-contents)
---
##### π [Playwright][playwright]
1. Use `locator` over raw CSS/XPath selectors β
`page.locator('[data-testid="submit"]')` is self-healing and readable. AI
agents infer intent from the locator chain instead of parsing brittle
selector strings.
2. Prefer `getByRole`, `getByText`, `getByTestId` β Accessible queries mirror
how users interact. AI agents see the semantic target (button, heading)
rather than implementation details.
3. Use `page` fixtures over manual browser setup β
`test('...', async ({ page }) => {})` gets an isolated page. AI agents trace
the test scope from the fixture parameter.
4. Use `test.beforeEach` for shared setup β Navigate to a URL or seed data
before each test. AI agents see common setup at a glance instead of scanning
for repeated code.
5. Use `expect.toHaveText`, `toBeVisible`, `toBeEnabled` β Assertions that
describe the user-visible state. AI agents read expected behaviour from the
matcher name.
6. Use `mockRoute` for API stubs β
`page.route('**/api/**', route => route.fulfill({ json }))` avoids network
flakiness. AI agents see the mock boundary without inspecting the network
layer.
7. Use `waitForLoadState('networkidle')` sparingly β Prefer `waitForResponse` or
`locator.waitFor()` for precise waits. AI agents trace the exact condition
instead of guessing at "idle".
8. Use `test.use({ storageState })` for auth β Reuse logged-in sessions across
tests. AI agents infer the authentication context from the config instead of
scripting login in every test.
9. Use `snapshot` for visual regression β `expect(page).toHaveScreenshot()`
catches unintended UI changes. AI agents see the visual contract as a
first-class assertion.
10. Use `webServer` config for dev server β Let Playwright start the dev server
automatically. AI agents see the server dependency in config rather than a
separate shell command.
[Back to Table of Content](#-table-of-contents)
---
#### π [Web Development](#-web-development)
[Back to Table of Content](#-table-of-contents)
---
##### βοΈ [React][react]
1. Prefer function components over class components β Functions are simpler,
hooks-compatible, and produce less boilerplate. AI agents read data flow
top-to-bottom without lifecycle indirection.
2. Use hooks for state and side effects β `useState`, `useEffect`,
`useCallback`, `useMemo` replace lifecycle methods with composable
primitives. AI agents trace state changes through explicit hook calls.
3. Keep hooks at the top level β Never nest hooks inside conditionals or loops.
AI agents rely on consistent call order to infer which state belongs to which
component.
4. Extract custom hooks for reusable logic β `useAuth()`, `useDebounce()`,
`useIntersectionObserver()` name the abstraction. AI agents reason about
intent from the hook name instead of inlining effects.
5. Use `useReducer` for complex state β When state has multiple sub-values or
depends on previous state, `useReducer` centralises transitions. AI agents
see all state mutations in one reducer function.
6. Prefer `children` prop for composition β `<Card><p>content</p></Card>` is
more flexible than `<Card content={...} />`. AI agents understand layout
hierarchy from JSX nesting.
7. Memoise sparingly with `React.memo`, `useMemo`, `useCallback` β Profile
first, memoise second. Unnecessary memoisation obscures data flow and adds
surface area for AI agents to misread.
8. Use `key` prop correctly in lists β Use stable, unique IDs, not array
indices. AI agents reason about list reconciliation based on `key` stability.
9. Lift state up or colocate it β State shared by multiple children goes to the
nearest common ancestor; purely local state stays in the leaf. AI agents
trace state ownership without crossing too many files.
10. Use `React.StrictMode` in development β Catches impure renders, stale
effects, and legacy API usage. AI agents see the warnings as early signals
of logic errors.
[Back to Table of Content](#-table-of-contents)
---
##### β² [Next.js][next.js]
1. Use the App Router (`app/`) over the Pages Router (`pages/`) β App Router
supports server components, layouts, streaming, and nested routing. AI agents
infer page hierarchy from directory structure.
2. Prefer server components by default β Fetch data in server components and
pass props down. AI agents trace data flow server-to-client without waterfall
loading states.
3. Use client components only when needed β Mark files with `"use client"` only
when they need interactivity, browser APIs, or hooks. Every `"use client"`
boundary is a point where AI agents must track client/server split.
4. Use `generateStaticParams` for static paths β Pre-render dynamic segments at
build time. AI agents see the full set of possible routes without simulating
runtime resolution.
5. Use `loading.tsx` and `error.tsx` for fallbacks β File-based convention for
loading and error UI. AI agents locate error handling by filename instead of
scanning JSX for conditional branches.
6. Use `layout.tsx` for shared UI β Wrap child routes in common layouts without
repeating wrappers. AI agents infer layout nesting from the directory tree.
7. Prefer `server actions` for mutations β `"use server"` functions colocate
form logic with the component. AI agents see the full submit cycle (form β
action β revalidation) in one file.
8. Use `next/image` for images β Automatic optimisation, lazy loading, and
responsive sizes. AI agents trust that images are performant without auditing
`<img>` attributes.
9. Use `next/link` for client-side navigation β Prefetches pages in viewport and
enables soft navigation. AI agents infer link relationships from `href`
patterns.
10. Use `middleware.ts` for auth/redirects β Run logic before a request
completes. AI agents see auth gates and redirect rules in a single entry
point rather than scattered across pages.
[Back to Table of Content](#-table-of-contents)
---
#### π¦ [Docusaurus][docusaurus]
1. Use `sidebars.ts` for structured navigation β Define sidebar groups with
`label` and `items`. AI agents infer documentation hierarchy from the sidebar
config instead of scanning directory trees.
2. Use `docsearch` or local search plugin β Configure Algolia DocSearch or
`plugin-search` for discoverability. AI agents trust users can find content
without guessing permalink patterns.
3. Use `@site` path alias for cross-references β Reference files from anywhere
via `@site/docs/intro` instead of brittle relative paths. AI agents resolve
references reliably from the alias root.
4. Prefer MDX over plain Markdown β Import React components directly in docs for
interactive examples. AI agents see the import boundary and can compose UI
with documentation.
5. Use `admonitions` for callouts β `:::tip`, `:::note`, `:::warning`,
`:::danger` for structured emphasis. AI agents parse intent from the
admonition type rather than guessing from bold text.
6. Use versioning for API docs β `npm run docusaurus docs:version 2.0` freezes a
snapshot. AI agents see which docs apply to which version without reading
release notes.
7. Use `plugin-content-docs` `routeBasePath` for custom URLs β Configure `/` as
the base path for a docs-first site. AI agents infer URL structure from
config, not by crawling files.
8. Prefer `tabs` for multi-language examples β `import Tabs from '@theme/Tabs'`
colocates code samples in one component. AI agents maintain language parity
instead of scattering examples across pages.
9. Use `_category_.json` for metadata β Customize sidebar label, position, and
collapsed state per folder. AI agents see category metadata without opening
index files.
10. Keep custom CSS in `src/css/custom.css` β Override Infima variables for
branding. AI agents locate theme tweaks in the canonical file instead of
searching for scattered style tags.
[Back to Table of Content](#-table-of-contents)
---
## DevOps (Development and Operations)
### Docker
1. Use multi-stage builds β Separate build stage (`FROM ... AS builder`) from
runtime stage. AI agents infer build vs. runtime dependencies from stage
boundaries instead of reading package lists.
2. Pin base image digests β `FROM node:20-alpine@sha256:...` prevents
supply-chain drift. AI agents see exact base images without querying
registries.
3. Order `COPY` / `RUN` for layer caching β Copy `package.json` / `Cargo.toml`
before source code so dependency layers cache unless deps change. AI agents
trace cache-hit logic by instruction order.
4. Use `.dockerignore` β Exclude `node_modules`, `target/`, `.git`, `*.md`. AI
agents reason about build context size from the ignore rules instead of
guessing.
5. Prefer `COPY --chown=` over chmod in RUN β Sets ownership in the COPY layer
rather than adding an extra layer. AI agents see ownership metadata in the
same instruction as the file.
6. Run as non-root β `USER nobody` or a dedicated `USER app` after installing
deps. AI agents infer security posture from the USER directive.
7. Use `HEALTHCHECK` for services β
`HEALTHCHECK CMD curl -f http://localhost:8080/health` documents the
service's self-test. AI agents see the health contract in the Dockerfile.
8. Keep `CMD` / `ENTRYPOINT` simple β Prefer `CMD ["binary"]` (exec form) over
shell form. AI agents parse the process list from the JSON array without
shell interpolation.
9. Label images β `LABEL org.opencontainers.image.source="..."` ties the image
to its repo. AI agents trace provenance from labels.
10. Use `ARG` for version bumps β `ARG RUST_VERSION=1.85` centralises version
values. AI agents see all version pins in one block rather than scattered in
URLs.
[Back to Table of Contents](#-table-of-contents)
---
#### Docker Compose
1. Use versioned schema β `version: "3.8"` or newer. AI agents infer the compose
spec version from the declaration instead of guessing from feature usage.
2. Name services clearly β `app`, `db`, `cache` rather than `service1`,
`container1`. AI agents infer service roles from the service name.
3. Use `depends_on` with `condition` β
`depends_on: db: condition: service_healthy` models startup order with health
checks. AI agents trace dependency chains from `depends_on` blocks.
4. Prefer environment files over inline vars β `env_file: .env` keeps secrets
out of compose YAML. AI agents see the config source without reading inline
values.
5. Use named volumes for persistent data β `volumes: dbdata:` instead of bind
mounts. AI agents infer data lifecycle from volume declarations.
6. Set resource limits β `deploy: resources: limits: memory: 512M` documents
expected resource usage. AI agents infer capacity requirements from limits.
7. Use profiles for optional services β `profiles: ["dev"]` on dev-only services
keeps `docker compose up` clean for production. AI agents infer which
services are optional from profile assignments.
8. Keep port mappings explicit β `"8080:8080"` documents both host and container
ports. AI agents infer network topology from the port mapping pairs.
9. Use `restart: unless-stopped` for daemon services β Keeps services running
after crashes without forcing restart after manual stop. AI agents see the
restart policy intent.
10. Prefer `healthcheck` at the service level β
`healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"]`
colocated with service definition. AI agents find the health probe alongside
the service config instead of in a separate script.
[Back to Table of Contents](#-table-of-contents)
---
### Makefile
1. Declare `.PHONY` for all non-file targets β `.PHONY: build test clean`
prevents false-up-to-date when a file named `build` exists. AI agents infer
which targets produce files and which don't from the `.PHONY` declaration.
2. Default target first, named `help` or `all` β The first target (e.g., `help`)
is the default when running `make` bare. AI agents find entry points by
scanning the first target.
3. Use `$(MAKE)` over `make` for recursion β `$(MAKE) -C subdir` ensures flags
and env propagate. AI agents trace recursive invocations through `$(MAKE)`
references.
4. Prefer automatic variables β `$@` (target), `$<` (first prereq), `$^` (all
prereqs) instead of repeating names. AI agents read rule invariants from the
automatic variable idioms.
5. Use `:=` for simple expansion β `CC := gcc` evaluates once at parse time; `=`
is recursive expansion (evaluated each use). AI agents prefer `:=` to reason
about variable values without simulating deferred evaluation.
6. Use `?=` for user-overridable defaults β `PREFIX ?= /usr/local` lets users
override via environment without editing the Makefile. AI agents see which
variables are meant for customisation from `?=` syntax.
7. Keep recipes tab-indented β Make requires real tab characters, not spaces,
for recipe lines. AI agents produce valid Makefiles when they follow this
rule.
8. Break long lines with `\` β `target: dep1 dep2 dep3 \` followed by newline +
`<tab>` continuation keeps rules readable. AI agents parse multi-line recipes
without scrolling horizontally.
9. Use `$(shell ...)` sparingly β Prefer passing values from the environment or
build scripts over shelling out in variable assignments. AI agents trace
variable sources more easily from explicit assignments.
10. Separate build artifacts with `$(BUILD_DIR)` β `BUILD_DIR := build` and
`$(BUILD_DIR)/%.o: %.c` keeps generated files out of the source tree. AI
agents infer which paths are generated from `$(BUILD_DIR)` references.
[Back to Table of Contents](#-table-of-contents)
---
## π¦ Projects
| No | Category | Subcategory | Project | [TypeScript][typescript] | [Go][go] | [Rust][rust] | [C++][cplusplus] | [Kotlin][kotlin] | [Swift][swift] |
| --- | ----------------------------------- | ---------------------------------------- | ---------------- | ------------------------ | -------------------- | -------------- | ---------------- | ---------------------------------- | ---------------------------------------------- |
| 1 | [App](./packages/app) | Web | `hieudoanm.app` | [Next.js][next.js] | | | | | |
| - | - | Mobile | - | [Expo][expo] | | | | [Jetpack Compose][jetpack-compose] | [SwiftUI][swiftui] |
| - | - | Desktop | - | | | [Tauri][tauri] | [Qt][qt] | | |
| 2 | [CLI](./packages/cli) | | `hieudoanm.cli` | | [cobra.go][cobra.go] | [clap.rs] | | [cli.kt] | [Swift Argument Parser][swift-argument-parser] |
| 3 | [Documentation](./packages/docs) | | `hieudoanm.md` | [Docusaurus][docusaurus] | | | | | |
| 4 | [Extensions](./packages/extensions) | [Browser](./packages/extensions/browser) | `hieudoanm.ext` | | | | | | |
| 5 | [Server](./packages/server) | | `backbone` | | `net/http` | [Axum][axum] | | [Ktor][ktor] | |
| 6 | [Serverless](./packages/serverless) | | `browserverless` | | | | | | |
[Back to Table of Content](#-table-of-contents)
---
[axum]: https://docs.rs/axum/
[bash]: https://www.gnu.org/software/bash/
[clap.rs]: https://docs.rs/clap/
[cli.kt]: https://ajalt.github.io/clikt/
[cobra.go]: https://cobra.dev
[cplusplus]: https://isocpp.org/
[docusaurus]: https://docusaurus.io/
[expo]: https://expo.dev/
[go]: https://go.dev/
[jest]: https://jestjs.org
[jetpack-compose]: https://developer.android.com/compose
[qt]: https://www.qt.io/
[kotlin]: https://kotlinlang.org
[ktor]: https://ktor.io
[next.js]: https://nextjs.org
[pandas]: https://pandas.pydata.org
[playwright]: https://playwright.dev/
[python]: https://www.python.org
[react]: https://react.dev/
[rust]: https://www.rust-lang.org
[swift]: https://www.swift.org
[swiftui]: https://developer.apple.com/swiftui/
[swift-argument-parser]: https://github.com/apple/swift-argument-parser
[tauri]: https://tauri.app
[typescript]: https://www.typescriptlang.org/