refactor: AGENTS.md is the single source of truth for all runtimes

- Create ~/.config/mosaic/AGENTS.md as the canonical universal agent config
- Runtime adapters (CLAUDE.md, opencode/AGENTS.md, codex/instructions.md) are
  now thin pointers that say "READ ~/.config/mosaic/AGENTS.md"
- mosaic claude: injects AGENTS.md via --append-system-prompt
- mosaic opencode/codex: copies AGENTS.md to runtime config path before launch
- mosaic-link-runtime-assets: pushes thin pointers for direct launch fallback

AGENTS.md is runtime-agnostic. All runtimes get the same standards.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-19 13:24:12 -06:00
parent 0b7b823911
commit 3f2ba89db2
8 changed files with 723 additions and 679 deletions

View File

@@ -3,10 +3,13 @@ set -euo pipefail
# mosaic — Unified agent launcher and management CLI
#
# AGENTS.md is the single source of truth for all agent sessions.
# The launcher injects it into every runtime consistently.
#
# Usage:
# mosaic claude [args...] Launch Claude Code with SOUL.md injected
# mosaic opencode [args...] Launch OpenCode
# mosaic codex [args...] Launch Codex
# mosaic claude [args...] Launch Claude Code with AGENTS.md injected
# mosaic opencode [args...] Launch OpenCode with AGENTS.md injected
# mosaic codex [args...] Launch Codex with AGENTS.md injected
# mosaic init [args...] Generate SOUL.md interactively
# mosaic doctor [args...] Health audit
# mosaic sync [args...] Sync skills
@@ -22,9 +25,9 @@ mosaic $VERSION — Unified agent launcher
Usage: mosaic <command> [args...]
Agent Launchers:
claude [args...] Launch Claude Code with SOUL.md injected
opencode [args...] Launch OpenCode
codex [args...] Launch Codex
claude [args...] Launch Claude Code with AGENTS.md injected
opencode [args...] Launch OpenCode with AGENTS.md injected
codex [args...] Launch Codex with AGENTS.md injected
Management:
init [args...] Generate SOUL.md (agent identity contract)
@@ -49,6 +52,14 @@ check_mosaic_home() {
fi
}
check_agents_md() {
if [[ ! -f "$MOSAIC_HOME/AGENTS.md" ]]; then
echo "[mosaic] ERROR: ~/.config/mosaic/AGENTS.md not found." >&2
echo "[mosaic] Re-run the installer: cd ~/src/mosaic-bootstrap && bash install.sh" >&2
exit 1
fi
}
check_soul() {
if [[ ! -f "$MOSAIC_HOME/SOUL.md" ]]; then
echo "[mosaic] SOUL.md not found. Running mosaic init..."
@@ -65,31 +76,51 @@ check_runtime() {
fi
}
# Ensure AGENTS.md is present at the runtime's native config path.
# Used for runtimes that don't support CLI prompt injection.
ensure_runtime_config() {
local src="$MOSAIC_HOME/AGENTS.md"
local dst="$1"
mkdir -p "$(dirname "$dst")"
if ! cmp -s "$src" "$dst" 2>/dev/null; then
cp "$src" "$dst"
fi
}
# Launcher functions
launch_claude() {
check_mosaic_home
check_agents_md
check_soul
check_runtime "claude"
# SOUL.md is loaded via ~/.claude/CLAUDE.md directive (pushed by mosaic-link-runtime-assets)
# Claude supports --append-system-prompt for direct injection
local agents_content
agents_content="$(cat "$MOSAIC_HOME/AGENTS.md")"
echo "[mosaic] Launching Claude Code..."
exec claude "$@"
exec claude --append-system-prompt "$agents_content" "$@"
}
launch_opencode() {
check_mosaic_home
check_agents_md
check_soul
check_runtime "opencode"
# OpenCode reads from ~/.config/opencode/AGENTS.md — copy canonical version there
ensure_runtime_config "$HOME/.config/opencode/AGENTS.md"
echo "[mosaic] Launching OpenCode..."
exec opencode "$@"
}
launch_codex() {
check_mosaic_home
check_agents_md
check_soul
check_runtime "codex"
# Codex reads from ~/.codex/instructions.md — copy canonical version there
ensure_runtime_config "$HOME/.codex/instructions.md"
echo "[mosaic] Launching Codex..."
exec codex "$@"
}

View File

@@ -69,7 +69,7 @@ for p in "${legacy_paths[@]}"; do
remove_legacy_path "$p"
done
# Runtime files are synced as regular files (not symlinks) to reduce path confusion.
# Claude-specific runtime files (settings, hooks — NOT CLAUDE.md which is now a thin pointer)
for runtime_file in \
CLAUDE.md \
settings.json \
@@ -80,13 +80,13 @@ for runtime_file in \
copy_file_managed "$src" "$HOME/.claude/$runtime_file"
done
# OpenCode runtime adapter (optional, copied when present).
# OpenCode runtime adapter (thin pointer to AGENTS.md)
opencode_adapter="$MOSAIC_HOME/runtime/opencode/AGENTS.md"
if [[ -f "$opencode_adapter" ]]; then
copy_file_managed "$opencode_adapter" "$HOME/.config/opencode/AGENTS.md"
fi
# Codex runtime adapter (optional, copied when present).
# Codex runtime adapter (thin pointer to AGENTS.md)
codex_adapter="$MOSAIC_HOME/runtime/codex/instructions.md"
if [[ -f "$codex_adapter" ]]; then
mkdir -p "$HOME/.codex"

View File

@@ -77,7 +77,7 @@ foreach ($p in $legacyPaths) {
Remove-LegacyPath $p
}
# Sync runtime config files (copy, not link)
# Claude-specific runtime files (settings, hooks — CLAUDE.md is now a thin pointer)
$runtimeFiles = @("CLAUDE.md", "settings.json", "hooks-config.json", "context7-integration.md")
foreach ($rf in $runtimeFiles) {
$src = Join-Path $MosaicHome "runtime\claude\$rf"

View File

@@ -1,9 +1,12 @@
# mosaic.ps1 — Unified agent launcher and management CLI (Windows)
#
# AGENTS.md is the single source of truth for all agent sessions.
# The launcher injects it into every runtime consistently.
#
# Usage:
# mosaic claude [args...] Launch Claude Code with SOUL.md injected
# mosaic opencode [args...] Launch OpenCode
# mosaic codex [args...] Launch Codex
# mosaic claude [args...] Launch Claude Code with AGENTS.md injected
# mosaic opencode [args...] Launch OpenCode with AGENTS.md injected
# mosaic codex [args...] Launch Codex with AGENTS.md injected
# mosaic init [args...] Generate SOUL.md interactively
# mosaic doctor [args...] Health audit
# mosaic sync [args...] Sync skills
@@ -19,9 +22,9 @@ mosaic $Version - Unified agent launcher
Usage: mosaic <command> [args...]
Agent Launchers:
claude [args...] Launch Claude Code with SOUL.md injected
opencode [args...] Launch OpenCode
codex [args...] Launch Codex
claude [args...] Launch Claude Code with AGENTS.md injected
opencode [args...] Launch OpenCode with AGENTS.md injected
codex [args...] Launch Codex with AGENTS.md injected
Management:
init [args...] Generate SOUL.md (agent identity contract)
@@ -43,6 +46,15 @@ function Assert-MosaicHome {
}
}
function Assert-AgentsMd {
$agentsPath = Join-Path $MosaicHome "AGENTS.md"
if (-not (Test-Path $agentsPath)) {
Write-Host "[mosaic] ERROR: ~/.config/mosaic/AGENTS.md not found." -ForegroundColor Red
Write-Host "[mosaic] Re-run the installer."
exit 1
}
}
function Assert-Soul {
$soulPath = Join-Path $MosaicHome "SOUL.md"
if (-not (Test-Path $soulPath)) {
@@ -60,6 +72,18 @@ function Assert-Runtime {
}
}
function Ensure-RuntimeConfig {
param([string]$Dst)
$src = Join-Path $MosaicHome "AGENTS.md"
$parent = Split-Path $Dst -Parent
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent -Force | Out-Null }
$srcHash = (Get-FileHash $src -Algorithm SHA256).Hash
$dstHash = if (Test-Path $Dst) { (Get-FileHash $Dst -Algorithm SHA256).Hash } else { "" }
if ($srcHash -ne $dstHash) {
Copy-Item $src $Dst -Force
}
}
if ($args.Count -eq 0) {
Show-Usage
exit 0
@@ -71,23 +95,31 @@ $remaining = if ($args.Count -gt 1) { $args[1..($args.Count - 1)] } else { @() }
switch ($command) {
"claude" {
Assert-MosaicHome
Assert-AgentsMd
Assert-Soul
Assert-Runtime "claude"
# SOUL.md is loaded via ~/.claude/CLAUDE.md directive (pushed by mosaic-link-runtime-assets)
# Claude supports --append-system-prompt for direct injection
$agentsContent = Get-Content (Join-Path $MosaicHome "AGENTS.md") -Raw
Write-Host "[mosaic] Launching Claude Code..."
& claude @remaining
& claude --append-system-prompt $agentsContent @remaining
}
"opencode" {
Assert-MosaicHome
Assert-AgentsMd
Assert-Soul
Assert-Runtime "opencode"
# OpenCode reads from ~/.config/opencode/AGENTS.md
Ensure-RuntimeConfig (Join-Path $env:USERPROFILE ".config\opencode\AGENTS.md")
Write-Host "[mosaic] Launching OpenCode..."
& opencode @remaining
}
"codex" {
Assert-MosaicHome
Assert-AgentsMd
Assert-Soul
Assert-Runtime "codex"
# Codex reads from ~/.codex/instructions.md
Ensure-RuntimeConfig (Join-Path $env:USERPROFILE ".codex\instructions.md")
Write-Host "[mosaic] Launching Codex..."
& codex @remaining
}