Sync behavior
Complete reference for AlignTrue’s two-way sync system, conflict resolution, and precedence rules.
Comprehensive reference for sync internals. For practical workflow selection, see Choosing Your Workflow.
Overview
AlignTrue synchronizes rules between three locations:
- Intermediate Representation (IR) -
.aligntrue/.rules.yaml(internal, auto-generated, pure YAML format) - User-Editable Files -
AGENTS.md,.cursor/*.mdc,.vscode/mcp.json, etc. - Team Lockfile -
.aligntrue.lock.json(team mode only)
The sync engine maintains consistency while allowing both IR→agent and agent→IR flows.
Sync directions
IR → Agent (default)
When: Every aligntrue sync command (default direction)
Flow:
IR (.aligntrue/.rules.yaml) → Parse → Validate → Export → Agent filesVisual flow
What happens:
- Load configuration from
.aligntrue/config.yaml - Parse rules from
.aligntrue/.rules.yaml(internal IR) - Validate against JSON Schema
- Resolve scopes and merge rules
- Export to each enabled agent (Cursor, AGENTS.md, etc.)
- Write agent files atomically (temp+rename)
- Update lockfile (team mode only)
Example:
# Standard sync
aligntrue sync
# Preview changes
aligntrue sync --dry-run
# Non-interactive (CI)
aligntrue sync --forceOutput:
◇ Loading configuration...
◇ Parsing rules...
◇ Syncing to 2 agents...
│
◆ Files written:
│ • .cursor/rules/aligntrue.mdc (3 rules)
│ • AGENTS.md (3 rules)
│
◇ Sync complete! No conflicts detected.Agent → IR (pullback)
When:
- Solo mode (auto-pull): Automatically before every
aligntrue sync(default) - Team mode (manual):
aligntrue sync --accept-agent <name>(explicit opt-in)
Solo Mode Auto-Pull:
Solo developers editing native agent formats (.cursor/*.mdc, AGENTS.md) benefit from automatic pull on sync:
# Edit native format
vi .cursor/rules/aligntrue-starter.mdc
# Auto-pull happens automatically
aligntrue sync
# ◇ Auto-pull: pulling from cursor
# ✓ Updated IR from cursor
# ✓ Synced to: AGENTS.mdConfiguration:
# .aligntrue/config.yaml
exporters:
- cursor
- agents-md
# Auto-enabled for solo mode
sync:
auto_pull: true # Default for solo mode
primary_agent: cursor # Auto-detected from exporters
on_conflict: accept_agent # Default for solo modeFlow:
Agent files → Parse → Detect conflicts → Resolve → IR (.aligntrue/.rules.yaml)Auto-pull flow
What happens:
- Load existing IR from
.aligntrue/.rules.yaml - Parse agent files (
.cursor/*.mdc,AGENTS.md, etc.) - Detect conflicts (field-level comparison in team mode, auto-accept in solo mode)
- Prompt for resolution (interactive mode)
- Apply changes to IR
- Write updated
.aligntrue/.rules.yaml
Example:
# Pull changes from Cursor
aligntrue sync --accept-agent cursor
# Pull from AGENTS.md
aligntrue sync --accept-agent agents-mdSee Import Workflow Guide for detailed migration strategies and coverage analysis.
Output:
◇ Loading IR from .aligntrue/.rules.yaml...
◇ Parsing Cursor rules from .cursor/rules/*.mdc...
◇ Detecting conflicts...
│
⚠ Warning: Using mock data for agent→IR parsing
│
◆ Changes detected:
│ • 2 rules modified
│ • 1 rule added
│ • 0 rules deleted
│
◇ Conflicts detected. Starting resolution...Precedence rules
IR wins by default
.aligntrue/.rules.yaml is the internal authority.
Format: Pure YAML (not markdown). This is an internal file auto-generated by AlignTrue. Users should edit AGENTS.md or agent-specific files instead.
If you edit both IR and agent files:
aligntrue sync→ IR overwrites agent files (no prompt)aligntrue sync --accept-agent→ Triggers conflict resolution
Recommended workflow:
- Edit
AGENTS.mdor agent files - Run
aligntrue sync - All agent files updated automatically
Explicit pullback required
To pull changes from agent files back to IR:
# Must explicitly opt in
aligntrue sync --accept-agent cursorWithout --accept-agent, IR always wins.
Conflict detection
Conflicts detected when:
- Field values differ between IR and agent file
- Rule exists in agent but not in IR (new rule)
- Rule exists in IR but not in agent (deleted rule)
Field-level granularity:
Conflict in rule 'my-project.backend.use-typescript':
Field 'severity':
IR: error
Agent: warnConflict resolution
Interactive mode (default)
When conflicts detected, you’ll see:
⚠ Conflict detected in rule 'my-project.backend.use-typescript'
Field 'severity':
IR: error
Agent: warn
[i] Keep IR (discard agent change)
[a] Accept agent (pull agent change to IR)
[d] Show full diff
[q] Quit (abort sync)
Choice:Options:
i- Keep IR value, discard agent changea- Accept agent value, update IRd- Show complete diff of ruleq- Abort sync, no changes written
Batch mode
Apply same resolution to all conflicts in a rule:
⚠ Multiple conflicts in rule 'my-project.backend.use-typescript'
Apply same resolution to all 3 conflicts? [y/n]: y
[i] Keep IR for all fields
[a] Accept agent for all fields
[q] Quit
Choice:Saves time when you trust one source completely.
Non-interactive mode
For CI or scripting, use default strategy:
# Keep IR, discard all agent changes (default)
aligntrue sync --force
# Accept all agent changes (coming in Step 17)
aligntrue sync --accept-agent cursor --forceNo prompts, uses default resolution strategy.
Manual edit detection
If sync detects manual edits to generated files:
⚠ Checksum mismatch: .cursor/rules/aligntrue.mdc
This file was manually edited since last sync.
[v] View current content
[o] Overwrite (discard manual edits)
[k] Keep manual edits (skip sync)
[a] Abort sync
Choice:Checksum tracking:
- AlignTrue computes SHA-256 hash of each generated file
- Stores hash in
.aligntrue/.checksums.json - Compares before overwriting
Best practice: Edit AGENTS.md or agent files, not generated exports.
Scope behavior
Per-scope exports
Some exporters create one file per scope:
Cursor (.cursor/rules/*.mdc):
.aligntrue/.rules.yaml (with scopes):
- default scope → .cursor/rules/aligntrue.mdc
- apps/web scope → .cursor/rules/apps-web.mdc
- packages/core scope → .cursor/rules/packages-core.mdcFilename conversion:
- Scope path → filename
- Forward slashes → hyphens
- Example:
apps/web→apps-web.mdc
Why per-scope files?
- Cursor can load rules contextually based on current file
- Smaller files, faster parsing
- Clearer organization
Merged exports
Other exporters merge all scopes into one file:
AGENTS.md:
.aligntrue/.rules.yaml (with scopes):
- default scope
- apps/web scope
- packages/core scope
→ AGENTS.md (single file, all rules merged)Scope metadata preserved:
## Rule: use-typescript-strict
**Scope:** apps/web
Use TypeScript strict mode in all files.Why merged?
- Universal format for multiple agents
- Simpler for agents without scope support
- Single source of truth at root
Scope merge order
When rules overlap across scopes, merge order determines precedence:
# .aligntrue/config.yaml
scopes:
- name: root
path: .
merge_order: [root, path, local]
- name: apps-web
path: apps/web
merge_order: [root, path, local]Merge order levels:
root- Workspace-level rules (lowest priority)path- Scope-specific rules (medium priority)local- File-level overrides (highest priority)
Example:
# Root scope defines base rule
id: my-project.global.use-typescript
severity: warn
# apps/web scope overrides severity
id: my-project.global.use-typescript
severity: error # Stricter in frontendFinal merged rule in apps/web scope:
id: my-project.global.use-typescript
severity: error # apps/web override winsDry run mode
Preview changes without writing files:
aligntrue sync --dry-runOutput shows:
- Audit trail - All operations with timestamps
- Files that would be written - Paths and sizes
- Warnings - Potential issues
- Conflicts - What would trigger prompts
- Content hashes - SHA-256 of each file
Example:
◆ Dry-run mode: No files will be written
Audit trail:
[2025-10-27T12:00:00Z] Loaded config from .aligntrue/config.yaml
[2025-10-27T12:00:01Z] Parsed 3 rules from .aligntrue/.rules.yaml
[2025-10-27T12:00:02Z] Resolved 2 scopes
[2025-10-27T12:00:03Z] Exported to cursor (1 file)
[2025-10-27T12:00:04Z] Exported to agents-md (1 file)
Files to write:
• .cursor/rules/aligntrue.mdc (2.4 KB, hash: a3b2c1d4...)
• AGENTS.md (1.8 KB, hash: e5f6a7b8...)
Warnings: None
Conflicts: NoneUse cases:
- Verify changes before committing
- Debug exporter behavior
- Review scope resolution
- CI validation (non-destructive)
Git integration
AlignTrue can automatically manage git operations for generated files.
Three modes
1. Ignore Mode (Default)
# .aligntrue/config.yaml
git:
mode: ignore- Adds generated files to
.gitignore - Developers sync locally, don’t commit agent files
- Recommended for solo developers
Behavior:
aligntrue sync
# Adds to .gitignore:
# .cursor/rules/*.mdc
# AGENTS.md
# .vscode/mcp.json2. Commit Mode
# .aligntrue/config.yaml
git:
mode: commit- Commits generated files automatically after sync
- Team shares agent files via git
- Recommended for teams with consistent agents
Behavior:
aligntrue sync
# After successful sync:
git add .cursor/rules/*.mdc AGENTS.md
git commit -m "chore: sync AlignTrue rules"3. Branch Mode
# .aligntrue/config.yaml
git:
mode: branch- Creates feature branch for each sync
- Commit changes to branch
- Developers review before merging
Behavior:
aligntrue sync
# Creates branch: aligntrue/sync-2025-10-27-120000
# Commits changes to branch
# Developer reviews and merges via PRPer-adapter override
Override git mode for specific exporters:
# .aligntrue/config.yaml
git:
mode: ignore # Default for all exporters
exporters:
- name: cursor
git_override: commit # Commit Cursor files
- name: agents-md
# Uses default (ignore)Use case: Commit .cursor/*.mdc for team, ignore AGENTS.md for personal use.
Idempotent .gitignore
AlignTrue safely manages .gitignore:
- Adds entries only if not present
- Preserves existing entries and comments
- Uses markers for AlignTrue-managed section:
# Your existing entries
node_modules/
dist/
# BEGIN AlignTrue
.cursor/rules/*.mdc
AGENTS.md
# END AlignTrueSafe operations:
- Running sync multiple times doesn’t duplicate entries
- Manual edits outside markers are preserved
- Removing marker comments stops AlignTrue management
Lockfile behavior (team mode)
When team mode enabled (mode: team in config):
Validation before sync
Lockfile validated before syncing:
# .aligntrue/config.yaml
lockfile:
mode: soft # Warn but continue (default)
# mode: strict # Block on mismatch (CI)
# mode: off # Disable validationThree modes:
Off (Solo Mode):
- No lockfile validation
- Always succeeds
- Recommended for solo developers
Soft (Team Mode Default):
- Warns on lockfile mismatch
- Continues sync anyway
- Exit code 0 (success)
Strict (CI):
- Errors on lockfile mismatch
- Aborts sync
- Exit code 1 (failure)
Regeneration after sync
Lockfile regenerated after successful sync (team mode only):
aligntrue sync
# 1. Validates lockfile (soft/strict)
# 2. Performs sync
# 3. Regenerates .aligntrue.lock.jsonLockfile contents:
{
"version": "1",
"generated_at": "2025-10-27T12:00:00Z",
"mode": "soft",
"rules": [
{
"rule_id": "my-project.backend.use-typescript",
"content_hash": "a3b2c1d4e5f6...",
"source": "local:.aligntrue/.rules.yaml"
}
],
"bundle_hash": "e5f6a7b8c9d0..."
}Per-rule hashes:
- SHA-256 of canonical IR (JCS)
- Excludes
vendor.*.volatilefields - Deterministic across machines
Bundle hash:
- SHA-256 of sorted rule hashes
- Quick validation before per-rule check
Drift detection
Lockfile drift occurs when:
- Rules edited but lockfile not updated
- Teammate pushed rules without lockfile
- Git merge conflict resolved manually
Detection:
aligntrue sync
# Compares current rules to lockfile hashes
# Reports mismatchesResolution:
Soft mode (warning):
⚠ Warning: Lockfile is out of sync
Rule 'my-project.backend.use-typescript' hash mismatch
Continuing sync...Strict mode (error):
✖ Error: Lockfile validation failed
Rule 'my-project.backend.use-typescript' hash mismatch
Aborting sync. Use --force to override.Fix:
# Regenerate lockfile
aligntrue sync --force
# Or delete and regenerate
rm .aligntrue.lock.json
aligntrue syncPerformance considerations
File operations
AlignTrue optimizes sync performance:
- Atomic writes - Temp file + rename (prevents partial writes)
- Lazy loading - Only parses files when needed
- Caching - Reuses parsed IR across exporters
- Parallel exports - Multiple exporters run concurrently
Large repositories
For monorepos with many scopes:
# .aligntrue/config.yaml
scopes:
- name: backend
path: packages/backend
include: ["**/*.ts"]
exclude: ["**/*.test.ts", "**/node_modules/**"]Performance tips:
- Use
excludepatterns to skip irrelevant files - Limit scope depth with specific paths
- Enable only needed exporters
CI optimization
# Fast validation (no file writes)
aligntrue check --ci
# Faster than full sync in CITroubleshooting
Sync hangs or times out
Cause: Large rule files, slow disk, or exporter deadlock.
Fix:
# Check file sizes
ls -lh AGENTS.md .aligntrue/.rules.yaml
# Run with dry-run to test
aligntrue sync --dry-run
# Disable problematic exporter
# Edit .aligntrue/config.yaml and remove exporterConflicts on every sync
Cause: Agent and IR are both being edited.
Fix:
Option 1: Native format workflow (recommended)
- Edit
AGENTS.mdor any agent file - Run
aligntrue syncto propagate changes - Enable bidirectional sync with
auto_pull: true
Option 2: Manual control
- Edit
AGENTS.mdas primary file - Run
aligntrue syncto update other agents - Disable auto-pull with
auto_pull: false
Tip: Use native format workflow for flexibility - edit any file, changes sync everywhere.
Lockfile always out of sync
Cause: Volatile vendor fields changing on each sync.
Fix:
# Mark changing fields as volatile
vendor:
_meta:
volatile: ["my-agent.timestamp", "my-agent.cache"]
my-agent:
timestamp: "2025-10-27T12:00:00Z" # Excluded from hashVolatile fields won’t cause lockfile drift.
See also
- Command Reference - Detailed flag documentation
- Import Workflow - Migrate from existing agent rules
- Git Sources Guide - Pull rules from repositories
- Troubleshooting - Common sync issues
- Extending AlignTrue - Create custom exporters
- Quickstart Guide - Get started in <60 seconds