Architecture¶
1. Overview¶
Code Principles is a policy-composition system for AI coding assistants. Its architecture separates stable engineering concepts from project-specific and technology-specific refinements.
The system is intentionally layered:
orchestrator
├── project profiles
├── modifiers
├── language adapters
├── framework adapters
└── core skills
↓
resolved policy
↓
task execution
This structure prevents the repository from becoming a collection of duplicated “best practices” prompts.
2. Architectural principles¶
2.1 Project type before technology¶
The dominant policy is selected from the artifact and operational context, not from the language name.
Examples:
- a reusable Python package and a reusable PHP package share the
reusable-libraryprofile; - a React single-page application and a Vue single-page application share the
browser-web-applicationprofile; - a Go service and a PHP service may share the
backend-serviceprofile; - a C++ real-time component requires constraints not present in a generic C++ library.
2.2 One source of truth per rule¶
A general rule belongs in one core skill. Profiles, modifiers, and adapters reference or refine that rule instead of copying it.
For example:
- the meaning of DRY belongs in
core/abstraction-and-reuse; profiles/reusable-libraryselects a stricter extension and compatibility mode;languages/gorefines interface guidance for Go;frameworks/reactrefines composition and state-placement guidance for React.
2.3 Refinement, not replacement¶
Adapters refine general policy within their domain. They must not silently replace higher-precedence project requirements.
2.4 Explicit conflict handling¶
Conflicts are expected. A profile is valuable because it determines which quality attributes dominate in a given context.
2.5 Conservative behavior under uncertainty¶
When context is uncertain, the system favors local, reversible, low-coupling decisions and avoids speculative architecture.
3. Repository layers¶
3.1 Orchestrator¶
Path:
Responsibilities:
- context detection;
- evidence classification;
- base profile selection;
- modifier activation;
- adapter selection;
- override application;
- conflict resolution;
- resolved-policy generation;
- visible policy summary.
Non-responsibilities:
- defining all engineering principles;
- containing framework implementation guidance;
- generating project architecture from language detection alone;
- forcing a confirmation step for every task.
The orchestrator metadata is stored in orchestrator/skill.yaml, while normative model behavior is stored in orchestrator/SKILL.md.
3.2 Core skills¶
Path:
A core skill owns a coherent decision domain. Proposed domains are:
| Skill | Primary responsibility |
|---|---|
code-clarity |
local readability, naming, explicitness, level of abstraction |
abstraction-and-reuse |
DRY, YAGNI, extension points, duplication of knowledge |
modular-design |
cohesion, coupling, responsibilities, composition, encapsulation |
contracts-and-errors |
validation, parsing, fail-fast behavior, error boundaries |
dependencies-and-boundaries |
dependency direction, DI, modules, ports and adapters |
state-and-side-effects |
mutability, commands, queries, idempotency, state ownership |
api-and-compatibility |
public surface, versioning, deprecation, compatibility |
testing-strategy |
test levels, behavior focus, test design, legacy characterization |
performance |
measurement, budgets, resource constraints, hot paths |
safe-change |
bounded refactoring, legacy behavior, Chesterton’s Fence |
distributed-reliability |
retries, duplicates, ordering, partial failure, consistency |
engineering-review-lenses |
Conway, Hyrum, Gall, Brooks, Murphy, organizational review |
A core skill may define multiple modes. For example, abstraction-and-reuse may expose:
conservative;balanced;extensible-library.
3.3 Project profiles¶
Implementation path:
A profile:
- describes a class of project;
- sets default priorities;
- activates relevant core skills;
- selects default modes;
- defines typical risks;
- defines non-goals;
- may recommend modifiers;
- must remain language-agnostic.
A profile must not contain syntax or APIs specific to PHP, TypeScript, Python, Go, C++, or any framework.
Example profile composition:
id: reusable-library
skill_modes:
code-clarity: balanced
abstraction-and-reuse: extensible-public-library
modular-design: library-oriented
contracts-and-errors: strict-boundaries
api-and-compatibility: public-library
testing-strategy: unit-focused
safe-change: compatibility-first
The orchestrator loads implemented profile.yaml files as the runtime source for these default mode
selections. This keeps profile configuration inspectable and prevents a second hand-maintained mode table.
3.4 Modifiers¶
Package path:
A modifier represents a cross-cutting constraint that can apply to multiple profiles.
A modifier may:
- raise the priority of a quality attribute;
- activate a core skill;
- strengthen a skill mode;
- add prohibited decisions;
- add verification requirements.
A modifier must not behave as an alternative full profile.
Examples:
public-apistrengthens compatibility and contract requirements;security-sensitivestrengthens validation, secret handling, least privilege, and auditability;memory-sensitivestrengthens streaming and allocation awareness;accessibility-requiredadds UI accessibility verification without replacing the web-application profile.
3.5 Language adapters¶
Implementation path:
A language adapter may cover:
- runtime semantics;
- type system and type-checking limitations;
- error model;
- resource ownership;
- concurrency model;
- module and packaging conventions;
- public API conventions;
- testing conventions;
- common language-specific failure modes.
A language adapter must not restate the entire project profile.
3.5.1 Language relationships¶
Inheritance between adapters must be explicit and acyclic.
All six initial target adapters are implemented. JavaScript owns runtime semantics shared with TypeScript; TypeScript adds erased static-type refinements without duplicating that runtime policy. PHP, Python, Go, and C++ are independent language roots.
3.5.2 Python adapter scope¶
The Python adapter refines guidance for:
- type hints and their runtime limitations;
Any,Unknown-equivalent boundaries, and optional values;Protocoland structural typing;dataclassuse;- mutable default arguments;
- exceptions and context preservation;
- context managers;
- iterators and generators;
- CPU-bound versus I/O-bound concurrency;
asyncio, threading, and multiprocessing trade-offs;- package API and
pyproject.tomlconventions.
3.6 Framework adapters¶
Implementation path:
A framework adapter should contain only framework-specific refinements.
Examples:
- React: component boundaries, state placement, effects, composition, user-behavior testing;
- Next.js: server/client boundaries, caching, rendering modes, routing, server actions, secret handling;
- Vue: reactivity, composables, component state, dependency injection where applicable;
- Nuxt: server/client boundaries, auto-imports, SSR, server routes, data fetching;
- Angular: framework DI, signals, RxJS, services, standalone components, forms;
- Symfony: service container, request lifecycle, Messenger, Doctrine integration, configuration conventions;
- Drupal: plugin APIs, hooks, cache metadata, entities, configuration, extension lifecycle, Symfony integration.
All seven initial framework adapters are implemented. React depends only on JavaScript and deliberately owns no TypeScript policy. Next.js combines React and TypeScript with explicit server/client rules. Nuxt refines Vue instead of repeating its component and reactivity rules. Drupal depends on PHP and Symfony but owns its host extension, entity, configuration, update, and cacheability contracts.
3.7 Schemas¶
Path:
Schemas provide machine-readable validation for metadata and resolved state.
skill.schema.json¶
Validates orchestrator and core skill metadata.
profile.schema.json¶
Validates language-independent project profiles and modifiers represented as profile-like policy components.
adapter.schema.json¶
Validates language and framework adapter metadata.
project-context.schema.json¶
Validates explicit repository configuration and detected context snapshots.
resolved-policy.schema.json¶
Validates the final merged policy used to perform a task.
3.8 Evaluations¶
Planned path:
Each scenario should contain:
input.md
repository-signals.yaml
expected-context.yaml
expected-policy.yaml
forbidden-decisions.md
review-notes.md
Evaluations should test policy selection, not only final code output.
4. Resolution pipeline¶
4.1 Input collection¶
Inputs may include:
- current user request;
- explicit user constraints;
- repository configuration;
- repository files and structure;
- existing code conventions;
- deployment or runtime information;
- previous decisions preserved in project context.
4.2 Context normalization¶
Inputs are normalized to the canonical context vocabulary defined in TERMINOLOGY.md and project-context.schema.json.
4.3 Evidence classification¶
Each important value is classified by confidence:
4.4 Base profile selection¶
Exactly one primary profile is normally selected. Composite policy is created using modifiers rather than selecting several overlapping base profiles.
Exceptions may exist for repositories containing clearly separate deliverables, but task-scoped resolution should still identify one dominant profile for the affected code.
4.5 Modifier activation¶
Modifiers are activated only when evidence supports them.
4.6 Adapter selection¶
Language and framework adapters are selected for the affected implementation boundary.
4.7 Mode resolution¶
Profiles set defaults, modifiers strengthen or adjust them, adapters refine them, and explicit overrides take precedence.
4.8 Conflict resolution¶
Conflicts are resolved using:
- precedence;
- protected quality attributes;
- task scope;
- evidence strength;
- failure consequences;
- reversibility;
- public exposure;
- compatibility requirements;
- architecture authority.
4.9 Policy output¶
The final resolved policy is an immutable decision snapshot for the current task. It should be reproducible from the same evidence and configuration.
5. Configuration model¶
A repository may include:
This file should describe stable project policy, not temporary task instructions.
Example:
specification_version: 0.10.0
selection_mode: automatic-with-visible-result
project:
artifact_type: fullstack-application
project_stage: active-product
exposure:
- organization-internal
- public-api
domain_complexity: moderate
architecture_authority: incremental-improvement
runtime:
- browser
- nodejs
languages:
- typescript
frameworks:
- react
- nextjs
modifiers:
- public-api
- security-sensitive
overrides:
prohibited_patterns:
- microservices-without-explicit-approval
- full-cqrs-without-demonstrated-need
skill_modes:
abstraction-and-reuse: conservative
6. Dependency rules¶
6.1 Allowed dependencies¶
orchestrator → all metadata layers
profile → core skill identifiers and modes
modifier → core skill identifiers and modes
language adapter → core skills and parent language adapters
framework adapter → core skills, language adapters, parent framework adapters
resolved policy → all selected identifiers
6.2 Forbidden dependencies¶
- core skills must not depend on framework adapters;
- project profiles must not depend on specific programming languages;
- language adapters must not select a project profile by themselves;
- framework adapters must not redefine language runtime semantics;
- metadata dependency graphs must not contain cycles;
- examples must not become normative sources of truth.
7. Duplication policy¶
The repository distinguishes three forms of duplication:
7.1 Duplicated normative knowledge¶
Not allowed. The same general rule must not be independently defined in multiple components.
7.2 Contextual refinement¶
Allowed. An adapter may explain how a general rule applies in its technology.
7.3 Illustrative repetition¶
Allowed in examples when necessary for clarity, but examples must link conceptually to the normative source.
8. Extensibility model¶
A new component should be introduced only when it owns a distinct decision responsibility.
Add a new core skill when:¶
- the rule domain applies across multiple project types and languages;
- it has a coherent set of conflicts and modes;
- existing skills cannot own it without losing cohesion.
Add a new profile when:¶
- the artifact type has a meaningfully different priority model;
- the difference cannot be represented by a modifier;
- the profile applies across more than one language.
Add a new modifier when:¶
- the concern applies across several profiles;
- it changes priorities but does not define the whole artifact;
- it can be activated independently.
Add a new adapter when:¶
- the language or framework has distinct semantics or conventions that materially change how core rules are implemented.
9. Visible reporting¶
The user-facing summary should normally be compact. A recommended shape is:
resolved_context:
profile: fullstack-web-application
modifiers: [public-api, security-sensitive]
languages: [typescript]
frameworks: [react, nextjs]
architecture_authority: incremental-improvement
significant_decisions:
- Keep server-side validation authoritative.
- Preserve public API compatibility.
- Do not introduce CQRS without demonstrated need.
For a small local task, only exceptional assumptions or trade-offs need to be shown.
10. Security architecture¶
The skills system itself is advisory, but it must treat security constraints as high precedence.
The orchestrator must not allow a profile or style rule to override:
- secret protection;
- access-control requirements;
- data-integrity requirements;
- memory-safety requirements where applicable;
- untrusted-input validation;
- safe dependency and execution boundaries.
A security modifier may strengthen the policy, but the absence of a modifier does not permit insecure code.
11. Evolution strategy¶
The architecture should evolve through working increments:
- foundation documents and schemas;
- orchestrator MVP;
- six core skills;
- five profiles;
- TypeScript, Python, and C++ adapters;
- JavaScript, PHP, and Go adapters;
- framework adapters;
- modifiers;
- evaluation suite;
- stable release.
This follows the principle that a complex working system should evolve from a simpler working system rather than being designed as an untested complete hierarchy.
12. Canonical knowledge architecture¶
The principles/ layer precedes Core Skills in the dependency graph:
principle entries
↓
Core Skills
↓
profiles and modifiers
↓
language/framework refinements
↓
orchestrator resolution
Core Skills may reference principle IDs. Principle entries must not depend on profiles, languages, frameworks, or task-specific policies.
13. Compendium generation architecture¶
Canonical YAML is transformed into human-readable Markdown by tools/generate_compendium.py. Generated documentation is committed so the repository is useful without contributor tooling, but validation detects missing generated pages.
14. External dependency boundary¶
Platform integrations may depend on the host’s plugin format. Normative engineering behavior must remain local and self-contained. Third-party Skills are outside the authority graph and cannot be resolution inputs.