Canonical repo = pure data; umbrella = orchestrator
Canonical = pure data; umbrella = orchestrator
The pattern
When something is a canonical source of truth (agent configs, skills, knowledge, memory, secrets):
- Data lives in its own repo — public, small, single-concern.
- That repo joins the umbrella as a submodule — flat under
repos/own/infra/<slug>for infra concerns. - The repo has no orchestration scripts. Just data + README.
- All wiring — sync scripts, hooks, scheduled tasks — lives in the umbrella at
C:/D/oriz/scripts/. - Global targets are derived, never edited by hand. Hand-edits get overwritten at next sync.
Instances (as of 2026-07-03)
| Canonical repo | Content | Written by |
|---|---|---|
chirag127/agent-configs |
Claude Code / OpenCode / Kilo config JSON | scripts/sync-agent-configs.ps1 + Oriz-SyncAgentConfigs task |
chirag127/agent-skills |
Skill folders (SKILL.md + files) | scripts/sync-skills.ps1 + Oriz-SyncSkills task |
chirag127/claude-memory |
MEMORY.md + per-project memory/ | scripts/memory-pull.mjs + CC SessionStart hook |
workspace .mcp.json |
MCP server manifests | scripts/sync-mcp-configs.mjs (manual) |
workspace .env.enc (sops+age) |
Secrets | scripts/sync-env-to-system-env.ps1 + Oriz-SyncEnv task |
Why
- Standalone value. Each canonical repo is useful on its own — clone
agent-skillson any machine and use it vianpx skills; cloneagent-configsand manually copy the files. - Repo boundaries mirror concern boundaries. No mixed-purpose repos.
- Umbrella stays orchestration-only.
scripts/folder is the single place to look for sync + install + register logic. - Windows-specific scheduling stays in umbrella. Submodules stay OS-neutral so they can run on Linux/macOS/Windows.
- Public discovery. Small single-concern repos are easier to star, fork, and reuse than a huge monolithic dotfiles repo.
The minimum-content rule
Canonical repos hold user-diverges-from-default keys only. Anti-example: yesterday's kilo.jsonc had 744 lines because it re-typed Kilo's built-in 500-model provider list. Correct: 60 lines — permissions, model picks, indexing endpoint. Kilo picks up its own defaults at runtime.
When you're populating a canonical file, ask: "Would the agent behave identically without this key?" If yes, drop it.
The secrets rule
Canonical repos hold zero plaintext secrets. Use ${env:VAR} refs. Umbrella's sync script expands from user env at write time. User env populated by Oriz-SyncEnv from sops-encrypted .env.enc.
Per-machine secrets go in globally-scoped .local.* files (e.g., ~/.claude/settings.local.json) which sync never touches.
The absolute-path rule
- Machine-specific paths (e.g.
C:/Users/<user>/AppData/...) → replace with PATH lookups (assume binary on PATH via package manager). - Workspace-absolute paths (
C:/D/oriz/...) → OK; bootstrap guarantees workspace location. - Home-relative paths (
~/...) → OK where the agent expands them.
Anti-patterns
- ❌ Sync script lives inside canonical submodule — puts Windows-specific code inside an OS-neutral repo
- ❌ Multiple canonical repos for the same concern — pick one; delete the others
- ❌ Hand-edit derived global — will be overwritten
- ❌ Default-value duplication in canonical file — bloat, drift from upstream default
- ❌ Plaintext secret in canonical file — use
${env:VAR}+.env.enc
Cross-refs
agent-configs-workspace-canonical-2026-07-03— the decision that locked this patternforks-as-submodules— same rule for external forksglobals-derived-from-workspace— the broader umbrella-canonical ruleeverything-durable-to-cloud— canonical repos + git = cloud durability