Architecture
Key architectural concepts and design principles for AlignTrue.
Core principles
- Maintainability – Prefer explicit modules and shallow trees so AI can reason about the code
- Determinism – YAML → Type-safe model → JCS canonical JSON → SHA-256 hashes
- Simplicity – Small, predictable modules; no registries, no plugin magic
- Local-first – All useful flows run offline; cloud augments later
- Agent parity – Exporters preserve semantics and emit fidelity notes when they cannot
- Advisory-first – Validators explain before they block
Data flow
AlignTrue follows an IR-first (Intermediate Representation) architecture:
Source (YAML/Markdown)
↓
IR (Intermediate Representation)
↓
Canonical JSON (JCS) + SHA-256 Hash
↓
Agent Exports (.mdc, AGENTS.md, MCP configs, etc.)IR-first design
aligntrue.yaml(IR) is the canonical source, not bundles- Literate markdown with fenced ```aligntrue blocks compiles to IR
- All operations work on IR directly
- Canonicalization only at lock/publish boundaries
Two-way sync
- Default: IR → agents (export rules to agent files)
- Optional: agent → IR (pull changes back from agent files)
--accept-agentflag enables explicit pullback- Auto-pull enabled by default for seamless workflows
Determinism
When to canonicalize
Only canonicalize when determinism is required:
- Lockfile generation (
aligntrue lockin team mode) - Produce canonical hash for drift detection - Catalog publishing (
aligntrue publishin Phase 4) - Produce integrity hash for distribution - NOT during: init, sync, export, import, normal file operations
Why:
- Solo devs don’t need canonicalization overhead for local files
- Team mode only needs determinism for lockfile-based drift detection
- Catalog publishing needs integrity hash at distribution boundary
- Running canonicalization on every operation adds unnecessary cost
Implementation
packages/schema/src/canonicalize.tscontains JCS canonicalization logicpackages/core/src/lockfile.tscalls canonicalize when generating locks- Exporters do NOT canonicalize; they work with IR directly
- All hashing uses
packages/schema/src/hashing.ts
Package architecture
Stable modules (deterministic logic)
Keep these modules consolidated and deterministic:
packages/schema/src/canonicalize.ts– YAML → canonical JSON (JCS)packages/schema/src/hashing.ts– SHA-256 integrity hashingpackages/schema/src/validator.ts– IR validation with Ajv strict modepackages/core/src/config.ts– Config parsing and validationpackages/core/src/sync.ts– Two-way sync engine (IR ↔ agents)packages/core/src/bundle.ts– Dependency merge + precedence (team mode)packages/core/src/lockfile.ts– Lockfile generation with canonical hashingpackages/core/src/scope.ts– Hierarchical scope resolution
Adaptation layers (agent-specific)
These adapt core logic to specific surfaces:
packages/cli/src/commands/*– CLI command implementationspackages/exporters/src/*/exporter.ts– Agent-specific exportspackages/markdown-parser/src/parser.ts– Markdown parsing
Vendor bags
Vendor bags enable lossless round-trips for agent-specific metadata:
vendor.<agent>namespace for agent-specific extensionsvendor.*.volatileexcluded from hashing (timestamps, session IDs, etc.)- Preserved during sync operations
- Allows agents to store additional metadata without breaking AlignTrue semantics
Example:
vendor:
cursor:
session_id: "abc123" # Volatile, excluded from hash
preferences:
theme: "dark" # Stable, included in hashHierarchical scopes
Path-based rules with merge order for monorepos:
- Root scope (applies everywhere)
- Directory scopes (applies to subtree)
- File-level overrides (most specific)
Rules merge with precedence from most specific to least specific.
Team mode features
Lockfiles
- Enable with
mode: teamin config - Generated with
aligntrue lock - Pin exact versions and hashes
- Detect drift in CI with
aligntrue check
Bundles
- Merge dependencies and rules
- Resolve conflicts with precedence rules
- Generate once, track in git
- Enable reproducible builds
Drift detection
- Compare current state against lockfile
- Report changes to rules, versions, or hashes
- Fail CI if drift detected (configurable severity)
Exporters
AlignTrue includes 43 exporters supporting 28+ agents:
Categories
- MCP config exporters - JSON configs for Model Context Protocol agents
- Agent-specific formats - Native formats (.mdc, .yml, .json, etc.)
- Universal formats - AGENTS.md for broad compatibility
- Dual-output - Both universal + specific (e.g., Aider)
Fidelity notes
Each exporter documents what information may be lost when converting from IR:
- Stored in exporter metadata
- Written to export file footers
- Help users understand limitations
- Guide decisions about which exporters to use
Footer format
All exports include:
- Lock hash (if available)
- Exporter version
- Capabilities version
- Loss count (fidelity notes)
AI-maintainable code principles
1. Explicit over dynamic
// Good: Explicit dispatch
switch (target) {
case "cursor":
return exportCursor(bundle);
case "codex":
return exportCodex(bundle);
}
// Bad: Dynamic lookup
const exporters = { cursor: exportCursor, codex: exportCodex };
return exporters[target](bundle);2. Flat over nested
Max depth three. Modules at packages/*/src/ with minimal nesting.
3. Consolidated complexity
Keep deterministic logic together up to ~800 LOC. Split only when boundaries are obvious.
4. Clear data flow
Good: CLI command → schema service → exporter
Bad: CLI → orchestrator → factory → plugin host → exporter
5. Deterministic schema validation
Single JSON Schema (2020-12) exported from packages/schema. Use Ajv strict mode everywhere.
6. Finish refactors
If you start moving logic, finish in the same PR or leave a _legacy.ts file with owner + removal date.
Testing philosophy
- Unit tests for all core logic
- Integration tests for CLI commands
- Golden tests for determinism
- Contract tests for exporters
- No real time, network, or randomness in tests
- Match CI environment exactly (TZ=UTC)
Security considerations
- No outbound network calls in core path
- Telemetry opt-in via env var (off by default)
- Never log secrets or PII
- Never commit real tokens
- Atomic file writes prevent corruption
- Sandbox execution for command runners
Next steps
- Review workspace structure
- Explore development commands
- See setup guide for installation