feat: centralized SOUL.md, mosaic-init generator, and unified launcher
- Add SOUL.md.template with {{PLACEHOLDERS}} for interactive generation
- Add mosaic-init (bash + PS1) for interactive SOUL.md creation with flag overrides
- Add mosaic launcher (bash + PS1) — unified CLI for claude/opencode/codex with SOUL.md injection
- Add codex runtime adapter (runtime/codex/instructions.md)
- Update runtime adapters (claude, opencode) with SOUL.md read directive
- Update mosaic-link-runtime-assets to push codex adapter to ~/.codex/
- Update installers to prompt for mosaic init when SOUL.md is missing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
142
bin/mosaic
Executable file
142
bin/mosaic
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# mosaic — Unified agent launcher and management CLI
|
||||
#
|
||||
# Usage:
|
||||
# mosaic claude [args...] Launch Claude Code with SOUL.md injected
|
||||
# mosaic opencode [args...] Launch OpenCode
|
||||
# mosaic codex [args...] Launch Codex
|
||||
# mosaic init [args...] Generate SOUL.md interactively
|
||||
# mosaic doctor [args...] Health audit
|
||||
# mosaic sync [args...] Sync skills
|
||||
# mosaic bootstrap <path> Bootstrap a repo
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
VERSION="0.1.0"
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
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
|
||||
|
||||
Management:
|
||||
init [args...] Generate SOUL.md (agent identity contract)
|
||||
doctor [args...] Audit runtime state and detect drift
|
||||
sync [args...] Sync skills from canonical source
|
||||
bootstrap <path> Bootstrap a repo with Mosaic standards
|
||||
|
||||
Options:
|
||||
-h, --help Show this help
|
||||
-v, --version Show version
|
||||
|
||||
All arguments after the command are forwarded to the target CLI.
|
||||
USAGE
|
||||
}
|
||||
|
||||
# Pre-flight checks
|
||||
check_mosaic_home() {
|
||||
if [[ ! -d "$MOSAIC_HOME" ]]; then
|
||||
echo "[mosaic] ERROR: ~/.config/mosaic not found." >&2
|
||||
echo "[mosaic] Install with: curl -sL https://git.mosaicstack.dev/mosaic/bootstrap/raw/branch/main/remote-install.sh | sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_soul() {
|
||||
if [[ ! -f "$MOSAIC_HOME/SOUL.md" ]]; then
|
||||
echo "[mosaic] SOUL.md not found. Running mosaic init..."
|
||||
"$MOSAIC_HOME/bin/mosaic-init"
|
||||
fi
|
||||
}
|
||||
|
||||
check_runtime() {
|
||||
local cmd="$1"
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "[mosaic] ERROR: '$cmd' not found in PATH." >&2
|
||||
echo "[mosaic] Install $cmd before launching." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Launcher functions
|
||||
launch_claude() {
|
||||
check_mosaic_home
|
||||
check_soul
|
||||
check_runtime "claude"
|
||||
|
||||
local soul_file="$MOSAIC_HOME/SOUL.md"
|
||||
echo "[mosaic] Launching Claude Code with SOUL.md injection..."
|
||||
exec claude --append-system-prompt-file "$soul_file" "$@"
|
||||
}
|
||||
|
||||
launch_opencode() {
|
||||
check_mosaic_home
|
||||
check_soul
|
||||
check_runtime "opencode"
|
||||
|
||||
echo "[mosaic] Launching OpenCode..."
|
||||
exec opencode "$@"
|
||||
}
|
||||
|
||||
launch_codex() {
|
||||
check_mosaic_home
|
||||
check_soul
|
||||
check_runtime "codex"
|
||||
|
||||
echo "[mosaic] Launching Codex..."
|
||||
exec codex "$@"
|
||||
}
|
||||
|
||||
# Delegate to existing scripts
|
||||
run_init() {
|
||||
check_mosaic_home
|
||||
exec "$MOSAIC_HOME/bin/mosaic-init" "$@"
|
||||
}
|
||||
|
||||
run_doctor() {
|
||||
check_mosaic_home
|
||||
exec "$MOSAIC_HOME/bin/mosaic-doctor" "$@"
|
||||
}
|
||||
|
||||
run_sync() {
|
||||
check_mosaic_home
|
||||
exec "$MOSAIC_HOME/bin/mosaic-sync-skills" "$@"
|
||||
}
|
||||
|
||||
run_bootstrap() {
|
||||
check_mosaic_home
|
||||
exec "$MOSAIC_HOME/bin/mosaic-bootstrap-repo" "$@"
|
||||
}
|
||||
|
||||
# Main router
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command="$1"
|
||||
shift
|
||||
|
||||
case "$command" in
|
||||
claude) launch_claude "$@" ;;
|
||||
opencode) launch_opencode "$@" ;;
|
||||
codex) launch_codex "$@" ;;
|
||||
init) run_init "$@" ;;
|
||||
doctor) run_doctor "$@" ;;
|
||||
sync) run_sync "$@" ;;
|
||||
bootstrap) run_bootstrap "$@" ;;
|
||||
-h|--help) usage ;;
|
||||
-v|--version) echo "mosaic $VERSION" ;;
|
||||
*)
|
||||
echo "[mosaic] Unknown command: $command" >&2
|
||||
echo "[mosaic] Run 'mosaic --help' for usage." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
210
bin/mosaic-init
Executable file
210
bin/mosaic-init
Executable file
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# mosaic-init — Interactive SOUL.md generator
|
||||
#
|
||||
# Usage:
|
||||
# mosaic-init # Interactive mode
|
||||
# mosaic-init --name "Jarvis" --style direct # Flag overrides
|
||||
# mosaic-init --name "Jarvis" --role "memory steward" --style direct \
|
||||
# --accessibility "ADHD-friendly chunking" --guardrails "Never auto-commit"
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
TEMPLATE="$MOSAIC_HOME/templates/SOUL.md.template"
|
||||
OUTPUT="$MOSAIC_HOME/SOUL.md"
|
||||
|
||||
# Defaults
|
||||
AGENT_NAME=""
|
||||
ROLE_DESCRIPTION=""
|
||||
STYLE=""
|
||||
ACCESSIBILITY=""
|
||||
CUSTOM_GUARDRAILS=""
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
Usage: $(basename "$0") [options]
|
||||
|
||||
Generate ~/.config/mosaic/SOUL.md — the universal agent identity contract.
|
||||
|
||||
Interactive by default. Use flags to skip prompts.
|
||||
|
||||
Options:
|
||||
--name <name> Agent name (e.g., "Jarvis", "Assistant")
|
||||
--role <description> Role description (e.g., "memory steward, execution partner")
|
||||
--style <style> Communication style: direct, friendly, or formal
|
||||
--accessibility <prefs> Accessibility preferences (e.g., "ADHD-friendly chunking")
|
||||
--guardrails <rules> Custom guardrails (appended to defaults)
|
||||
--non-interactive Fail if any required value is missing (no prompts)
|
||||
-h, --help Show help
|
||||
USAGE
|
||||
}
|
||||
|
||||
NON_INTERACTIVE=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) AGENT_NAME="$2"; shift 2 ;;
|
||||
--role) ROLE_DESCRIPTION="$2"; shift 2 ;;
|
||||
--style) STYLE="$2"; shift 2 ;;
|
||||
--accessibility) ACCESSIBILITY="$2"; shift 2 ;;
|
||||
--guardrails) CUSTOM_GUARDRAILS="$2"; shift 2 ;;
|
||||
--non-interactive) NON_INTERACTIVE=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
prompt_if_empty() {
|
||||
local var_name="$1"
|
||||
local prompt_text="$2"
|
||||
local default_value="${3:-}"
|
||||
local current_value="${!var_name}"
|
||||
|
||||
if [[ -n "$current_value" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ $NON_INTERACTIVE -eq 1 ]]; then
|
||||
if [[ -n "$default_value" ]]; then
|
||||
eval "$var_name=\"$default_value\""
|
||||
return
|
||||
fi
|
||||
echo "[mosaic-init] ERROR: --$var_name is required in non-interactive mode" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "$default_value" ]]; then
|
||||
prompt_text="$prompt_text [$default_value]"
|
||||
fi
|
||||
|
||||
printf "%s: " "$prompt_text"
|
||||
read -r value
|
||||
if [[ -z "$value" && -n "$default_value" ]]; then
|
||||
value="$default_value"
|
||||
fi
|
||||
eval "$var_name=\"$value\""
|
||||
}
|
||||
|
||||
echo "[mosaic-init] Generating SOUL.md — your universal agent identity contract"
|
||||
echo ""
|
||||
|
||||
prompt_if_empty AGENT_NAME "What name should agents use" "Assistant"
|
||||
prompt_if_empty ROLE_DESCRIPTION "Agent role description" "execution partner and visibility engine"
|
||||
|
||||
if [[ -z "$STYLE" && $NON_INTERACTIVE -eq 0 ]]; then
|
||||
echo ""
|
||||
echo "Communication style:"
|
||||
echo " 1) direct — Concise, no fluff, actionable"
|
||||
echo " 2) friendly — Warm but efficient, conversational"
|
||||
echo " 3) formal — Professional, structured, thorough"
|
||||
printf "Choose [1/2/3] (default: 1): "
|
||||
read -r style_choice
|
||||
case "${style_choice:-1}" in
|
||||
1|direct) STYLE="direct" ;;
|
||||
2|friendly) STYLE="friendly" ;;
|
||||
3|formal) STYLE="formal" ;;
|
||||
*) STYLE="direct" ;;
|
||||
esac
|
||||
elif [[ -z "$STYLE" ]]; then
|
||||
STYLE="direct"
|
||||
fi
|
||||
|
||||
prompt_if_empty ACCESSIBILITY "Accessibility preferences (or 'none')" "none"
|
||||
|
||||
if [[ $NON_INTERACTIVE -eq 0 && -z "$CUSTOM_GUARDRAILS" ]]; then
|
||||
echo ""
|
||||
printf "Custom guardrails (optional, press Enter to skip): "
|
||||
read -r CUSTOM_GUARDRAILS
|
||||
fi
|
||||
|
||||
# Build behavioral principles based on style + accessibility
|
||||
BEHAVIORAL_PRINCIPLES=""
|
||||
case "$STYLE" in
|
||||
direct)
|
||||
BEHAVIORAL_PRINCIPLES="1. Clarity over performance theater.
|
||||
2. Practical execution over abstract planning.
|
||||
3. Truthfulness over confidence: state uncertainty explicitly.
|
||||
4. Visible state over hidden assumptions."
|
||||
;;
|
||||
friendly)
|
||||
BEHAVIORAL_PRINCIPLES="1. Be helpful and approachable while staying efficient.
|
||||
2. Provide context and explain reasoning when helpful.
|
||||
3. Truthfulness over confidence: state uncertainty explicitly.
|
||||
4. Visible state over hidden assumptions."
|
||||
;;
|
||||
formal)
|
||||
BEHAVIORAL_PRINCIPLES="1. Maintain professional, structured communication.
|
||||
2. Provide thorough analysis with explicit tradeoffs.
|
||||
3. Truthfulness over confidence: state uncertainty explicitly.
|
||||
4. Document decisions and rationale clearly."
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$ACCESSIBILITY" != "none" && -n "$ACCESSIBILITY" ]]; then
|
||||
BEHAVIORAL_PRINCIPLES="$BEHAVIORAL_PRINCIPLES
|
||||
5. $ACCESSIBILITY."
|
||||
fi
|
||||
|
||||
# Build communication style section
|
||||
COMMUNICATION_STYLE=""
|
||||
case "$STYLE" in
|
||||
direct)
|
||||
COMMUNICATION_STYLE="- Be direct, concise, and concrete.
|
||||
- Avoid fluff, hype, and anthropomorphic roleplay.
|
||||
- Do not simulate certainty when facts are missing.
|
||||
- Prefer actionable next steps and explicit tradeoffs."
|
||||
;;
|
||||
friendly)
|
||||
COMMUNICATION_STYLE="- Be warm and conversational while staying focused.
|
||||
- Explain your reasoning when it helps the user.
|
||||
- Do not simulate certainty when facts are missing.
|
||||
- Prefer actionable next steps with clear context."
|
||||
;;
|
||||
formal)
|
||||
COMMUNICATION_STYLE="- Use professional, structured language.
|
||||
- Provide thorough explanations with supporting detail.
|
||||
- Do not simulate certainty when facts are missing.
|
||||
- Present options with explicit tradeoffs and recommendations."
|
||||
;;
|
||||
esac
|
||||
|
||||
# Format custom guardrails
|
||||
FORMATTED_GUARDRAILS=""
|
||||
if [[ -n "$CUSTOM_GUARDRAILS" ]]; then
|
||||
FORMATTED_GUARDRAILS="- $CUSTOM_GUARDRAILS"
|
||||
fi
|
||||
|
||||
# Verify template exists
|
||||
if [[ ! -f "$TEMPLATE" ]]; then
|
||||
echo "[mosaic-init] ERROR: Template not found: $TEMPLATE" >&2
|
||||
echo "[mosaic-init] Run the Mosaic installer first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate SOUL.md from template using awk (handles multi-line values)
|
||||
awk -v name="$AGENT_NAME" \
|
||||
-v role="$ROLE_DESCRIPTION" \
|
||||
-v principles="$BEHAVIORAL_PRINCIPLES" \
|
||||
-v comms="$COMMUNICATION_STYLE" \
|
||||
-v guardrails="$FORMATTED_GUARDRAILS" \
|
||||
'{
|
||||
gsub(/\{\{AGENT_NAME\}\}/, name)
|
||||
gsub(/\{\{ROLE_DESCRIPTION\}\}/, role)
|
||||
gsub(/\{\{BEHAVIORAL_PRINCIPLES\}\}/, principles)
|
||||
gsub(/\{\{COMMUNICATION_STYLE\}\}/, comms)
|
||||
gsub(/\{\{CUSTOM_GUARDRAILS\}\}/, guardrails)
|
||||
print
|
||||
}' "$TEMPLATE" > "$OUTPUT"
|
||||
|
||||
echo ""
|
||||
echo "[mosaic-init] Generated: $OUTPUT"
|
||||
echo "[mosaic-init] Agent name: $AGENT_NAME"
|
||||
echo "[mosaic-init] Style: $STYLE"
|
||||
|
||||
# Push to runtime adapters
|
||||
if [[ -x "$MOSAIC_HOME/bin/mosaic-link-runtime-assets" ]]; then
|
||||
echo "[mosaic-init] Updating runtime adapters..."
|
||||
"$MOSAIC_HOME/bin/mosaic-link-runtime-assets"
|
||||
fi
|
||||
|
||||
echo "[mosaic-init] Done. Launch with: mosaic claude"
|
||||
144
bin/mosaic-init.ps1
Normal file
144
bin/mosaic-init.ps1
Normal file
@@ -0,0 +1,144 @@
|
||||
# mosaic-init.ps1 — Interactive SOUL.md generator (Windows)
|
||||
#
|
||||
# Usage:
|
||||
# mosaic-init.ps1 # Interactive mode
|
||||
# mosaic-init.ps1 -Name "Jarvis" -Style direct # Flag overrides
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
param(
|
||||
[string]$Name,
|
||||
[string]$Role,
|
||||
[ValidateSet("direct", "friendly", "formal")]
|
||||
[string]$Style,
|
||||
[string]$Accessibility,
|
||||
[string]$Guardrails,
|
||||
[switch]$NonInteractive,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$MosaicHome = if ($env:MOSAIC_HOME) { $env:MOSAIC_HOME } else { Join-Path $env:USERPROFILE ".config\mosaic" }
|
||||
$Template = Join-Path $MosaicHome "templates\SOUL.md.template"
|
||||
$Output = Join-Path $MosaicHome "SOUL.md"
|
||||
|
||||
if ($Help) {
|
||||
Write-Host @"
|
||||
Usage: mosaic-init.ps1 [-Name <name>] [-Role <desc>] [-Style direct|friendly|formal]
|
||||
[-Accessibility <prefs>] [-Guardrails <rules>] [-NonInteractive]
|
||||
|
||||
Generate ~/.config/mosaic/SOUL.md - the universal agent identity contract.
|
||||
Interactive by default. Use flags to skip prompts.
|
||||
"@
|
||||
exit 0
|
||||
}
|
||||
|
||||
function Prompt-IfEmpty {
|
||||
param([string]$Current, [string]$PromptText, [string]$Default = "")
|
||||
|
||||
if ($Current) { return $Current }
|
||||
|
||||
if ($NonInteractive) {
|
||||
if ($Default) { return $Default }
|
||||
Write-Host "[mosaic-init] ERROR: Value required in non-interactive mode: $PromptText" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$display = if ($Default) { "$PromptText [$Default]" } else { $PromptText }
|
||||
$value = Read-Host $display
|
||||
if (-not $value -and $Default) { return $Default }
|
||||
return $value
|
||||
}
|
||||
|
||||
Write-Host "[mosaic-init] Generating SOUL.md - your universal agent identity contract"
|
||||
Write-Host ""
|
||||
|
||||
$Name = Prompt-IfEmpty $Name "What name should agents use" "Assistant"
|
||||
$Role = Prompt-IfEmpty $Role "Agent role description" "execution partner and visibility engine"
|
||||
|
||||
if (-not $Style) {
|
||||
if ($NonInteractive) {
|
||||
$Style = "direct"
|
||||
}
|
||||
else {
|
||||
Write-Host ""
|
||||
Write-Host "Communication style:"
|
||||
Write-Host " 1) direct - Concise, no fluff, actionable"
|
||||
Write-Host " 2) friendly - Warm but efficient, conversational"
|
||||
Write-Host " 3) formal - Professional, structured, thorough"
|
||||
$choice = Read-Host "Choose [1/2/3] (default: 1)"
|
||||
$Style = switch ($choice) {
|
||||
"2" { "friendly" }
|
||||
"3" { "formal" }
|
||||
default { "direct" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$Accessibility = Prompt-IfEmpty $Accessibility "Accessibility preferences (or 'none')" "none"
|
||||
|
||||
if (-not $Guardrails -and -not $NonInteractive) {
|
||||
Write-Host ""
|
||||
$Guardrails = Read-Host "Custom guardrails (optional, press Enter to skip)"
|
||||
}
|
||||
|
||||
# Build behavioral principles
|
||||
$BehavioralPrinciples = switch ($Style) {
|
||||
"direct" {
|
||||
"1. Clarity over performance theater.`n2. Practical execution over abstract planning.`n3. Truthfulness over confidence: state uncertainty explicitly.`n4. Visible state over hidden assumptions."
|
||||
}
|
||||
"friendly" {
|
||||
"1. Be helpful and approachable while staying efficient.`n2. Provide context and explain reasoning when helpful.`n3. Truthfulness over confidence: state uncertainty explicitly.`n4. Visible state over hidden assumptions."
|
||||
}
|
||||
"formal" {
|
||||
"1. Maintain professional, structured communication.`n2. Provide thorough analysis with explicit tradeoffs.`n3. Truthfulness over confidence: state uncertainty explicitly.`n4. Document decisions and rationale clearly."
|
||||
}
|
||||
}
|
||||
|
||||
if ($Accessibility -and $Accessibility -ne "none") {
|
||||
$BehavioralPrinciples += "`n5. $Accessibility."
|
||||
}
|
||||
|
||||
# Build communication style
|
||||
$CommunicationStyle = switch ($Style) {
|
||||
"direct" {
|
||||
"- Be direct, concise, and concrete.`n- Avoid fluff, hype, and anthropomorphic roleplay.`n- Do not simulate certainty when facts are missing.`n- Prefer actionable next steps and explicit tradeoffs."
|
||||
}
|
||||
"friendly" {
|
||||
"- Be warm and conversational while staying focused.`n- Explain your reasoning when it helps the user.`n- Do not simulate certainty when facts are missing.`n- Prefer actionable next steps with clear context."
|
||||
}
|
||||
"formal" {
|
||||
"- Use professional, structured language.`n- Provide thorough explanations with supporting detail.`n- Do not simulate certainty when facts are missing.`n- Present options with explicit tradeoffs and recommendations."
|
||||
}
|
||||
}
|
||||
|
||||
# Format custom guardrails
|
||||
$FormattedGuardrails = if ($Guardrails) { "- $Guardrails" } else { "" }
|
||||
|
||||
# Verify template
|
||||
if (-not (Test-Path $Template)) {
|
||||
Write-Host "[mosaic-init] ERROR: Template not found: $Template" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Generate SOUL.md
|
||||
$content = Get-Content $Template -Raw
|
||||
$content = $content -replace '\{\{AGENT_NAME\}\}', $Name
|
||||
$content = $content -replace '\{\{ROLE_DESCRIPTION\}\}', $Role
|
||||
$content = $content -replace '\{\{BEHAVIORAL_PRINCIPLES\}\}', $BehavioralPrinciples
|
||||
$content = $content -replace '\{\{COMMUNICATION_STYLE\}\}', $CommunicationStyle
|
||||
$content = $content -replace '\{\{CUSTOM_GUARDRAILS\}\}', $FormattedGuardrails
|
||||
|
||||
Set-Content -Path $Output -Value $content -Encoding UTF8
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[mosaic-init] Generated: $Output"
|
||||
Write-Host "[mosaic-init] Agent name: $Name"
|
||||
Write-Host "[mosaic-init] Style: $Style"
|
||||
|
||||
# Push to runtime adapters
|
||||
$linkScript = Join-Path $MosaicHome "bin\mosaic-link-runtime-assets.ps1"
|
||||
if (Test-Path $linkScript) {
|
||||
Write-Host "[mosaic-init] Updating runtime adapters..."
|
||||
& $linkScript
|
||||
}
|
||||
|
||||
Write-Host "[mosaic-init] Done. Launch with: mosaic claude"
|
||||
@@ -86,5 +86,12 @@ if [[ -f "$opencode_adapter" ]]; then
|
||||
copy_file_managed "$opencode_adapter" "$HOME/.config/opencode/AGENTS.md"
|
||||
fi
|
||||
|
||||
# Codex runtime adapter (optional, copied when present).
|
||||
codex_adapter="$MOSAIC_HOME/runtime/codex/instructions.md"
|
||||
if [[ -f "$codex_adapter" ]]; then
|
||||
mkdir -p "$HOME/.codex"
|
||||
copy_file_managed "$codex_adapter" "$HOME/.codex/instructions.md"
|
||||
fi
|
||||
|
||||
echo "[mosaic-link] Runtime assets synced (non-symlink mode)"
|
||||
echo "[mosaic-link] Canonical source: $MOSAIC_HOME"
|
||||
|
||||
@@ -93,5 +93,14 @@ if (Test-Path $opencodeSrc) {
|
||||
Copy-FileManaged $opencodeSrc $opencodeDst
|
||||
}
|
||||
|
||||
# Codex runtime adapter
|
||||
$codexSrc = Join-Path $MosaicHome "runtime\codex\instructions.md"
|
||||
if (Test-Path $codexSrc) {
|
||||
$codexDir = Join-Path $env:USERPROFILE ".codex"
|
||||
if (-not (Test-Path $codexDir)) { New-Item -ItemType Directory -Path $codexDir -Force | Out-Null }
|
||||
$codexDst = Join-Path $codexDir "instructions.md"
|
||||
Copy-FileManaged $codexSrc $codexDst
|
||||
}
|
||||
|
||||
Write-Host "[mosaic-link] Runtime assets synced (non-symlink mode)"
|
||||
Write-Host "[mosaic-link] Canonical source: $MosaicHome"
|
||||
|
||||
118
bin/mosaic.ps1
Normal file
118
bin/mosaic.ps1
Normal file
@@ -0,0 +1,118 @@
|
||||
# mosaic.ps1 — Unified agent launcher and management CLI (Windows)
|
||||
#
|
||||
# Usage:
|
||||
# mosaic claude [args...] Launch Claude Code with SOUL.md injected
|
||||
# mosaic opencode [args...] Launch OpenCode
|
||||
# mosaic codex [args...] Launch Codex
|
||||
# mosaic init [args...] Generate SOUL.md interactively
|
||||
# mosaic doctor [args...] Health audit
|
||||
# mosaic sync [args...] Sync skills
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$MosaicHome = if ($env:MOSAIC_HOME) { $env:MOSAIC_HOME } else { Join-Path $env:USERPROFILE ".config\mosaic" }
|
||||
$Version = "0.1.0"
|
||||
|
||||
function Show-Usage {
|
||||
Write-Host @"
|
||||
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
|
||||
|
||||
Management:
|
||||
init [args...] Generate SOUL.md (agent identity contract)
|
||||
doctor [args...] Audit runtime state and detect drift
|
||||
sync [args...] Sync skills from canonical source
|
||||
bootstrap <path> Bootstrap a repo with Mosaic standards
|
||||
|
||||
Options:
|
||||
-h, --help Show this help
|
||||
-v, --version Show version
|
||||
"@
|
||||
}
|
||||
|
||||
function Assert-MosaicHome {
|
||||
if (-not (Test-Path $MosaicHome)) {
|
||||
Write-Host "[mosaic] ERROR: ~/.config/mosaic not found." -ForegroundColor Red
|
||||
Write-Host "[mosaic] Install with: irm https://git.mosaicstack.dev/mosaic/bootstrap/raw/branch/main/remote-install.ps1 | iex"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
function Assert-Soul {
|
||||
$soulPath = Join-Path $MosaicHome "SOUL.md"
|
||||
if (-not (Test-Path $soulPath)) {
|
||||
Write-Host "[mosaic] SOUL.md not found. Running mosaic init..."
|
||||
& (Join-Path $MosaicHome "bin\mosaic-init.ps1")
|
||||
}
|
||||
}
|
||||
|
||||
function Assert-Runtime {
|
||||
param([string]$Cmd)
|
||||
if (-not (Get-Command $Cmd -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "[mosaic] ERROR: '$Cmd' not found in PATH." -ForegroundColor Red
|
||||
Write-Host "[mosaic] Install $Cmd before launching."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if ($args.Count -eq 0) {
|
||||
Show-Usage
|
||||
exit 0
|
||||
}
|
||||
|
||||
$command = $args[0]
|
||||
$remaining = if ($args.Count -gt 1) { $args[1..($args.Count - 1)] } else { @() }
|
||||
|
||||
switch ($command) {
|
||||
"claude" {
|
||||
Assert-MosaicHome
|
||||
Assert-Soul
|
||||
Assert-Runtime "claude"
|
||||
$soulFile = Join-Path $MosaicHome "SOUL.md"
|
||||
Write-Host "[mosaic] Launching Claude Code with SOUL.md injection..."
|
||||
& claude --append-system-prompt-file $soulFile @remaining
|
||||
}
|
||||
"opencode" {
|
||||
Assert-MosaicHome
|
||||
Assert-Soul
|
||||
Assert-Runtime "opencode"
|
||||
Write-Host "[mosaic] Launching OpenCode..."
|
||||
& opencode @remaining
|
||||
}
|
||||
"codex" {
|
||||
Assert-MosaicHome
|
||||
Assert-Soul
|
||||
Assert-Runtime "codex"
|
||||
Write-Host "[mosaic] Launching Codex..."
|
||||
& codex @remaining
|
||||
}
|
||||
"init" {
|
||||
Assert-MosaicHome
|
||||
& (Join-Path $MosaicHome "bin\mosaic-init.ps1") @remaining
|
||||
}
|
||||
"doctor" {
|
||||
Assert-MosaicHome
|
||||
& (Join-Path $MosaicHome "bin\mosaic-doctor.ps1") @remaining
|
||||
}
|
||||
"sync" {
|
||||
Assert-MosaicHome
|
||||
& (Join-Path $MosaicHome "bin\mosaic-sync-skills.ps1") @remaining
|
||||
}
|
||||
"bootstrap" {
|
||||
Assert-MosaicHome
|
||||
Write-Host "[mosaic] NOTE: mosaic-bootstrap-repo requires bash. Use Git Bash or WSL." -ForegroundColor Yellow
|
||||
& (Join-Path $MosaicHome "bin\mosaic-bootstrap-repo") @remaining
|
||||
}
|
||||
{ $_ -in "-h", "--help" } { Show-Usage }
|
||||
{ $_ -in "-v", "--version" } { Write-Host "mosaic $Version" }
|
||||
default {
|
||||
Write-Host "[mosaic] Unknown command: $command" -ForegroundColor Red
|
||||
Write-Host "[mosaic] Run 'mosaic --help' for usage."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -68,3 +68,10 @@ catch {
|
||||
|
||||
Write-Host "[mosaic-install] Done."
|
||||
Write-Host "[mosaic-install] Add to PATH: `$env:USERPROFILE\.config\mosaic\bin"
|
||||
|
||||
$soulPath = Join-Path $TargetDir "SOUL.md"
|
||||
if (-not (Test-Path $soulPath)) {
|
||||
Write-Host ""
|
||||
Write-Host "[mosaic-install] Set up your agent identity by running: mosaic init"
|
||||
Write-Host "[mosaic-install] This generates SOUL.md - the universal behavioral contract for all agent sessions."
|
||||
}
|
||||
|
||||
@@ -43,3 +43,9 @@ if ! "$TARGET_DIR/bin/mosaic-doctor"; then
|
||||
fi
|
||||
|
||||
echo "[mosaic-install] Add to PATH: export PATH=\"$TARGET_DIR/bin:$PATH\""
|
||||
|
||||
if [[ ! -f "$TARGET_DIR/SOUL.md" ]]; then
|
||||
echo ""
|
||||
echo "[mosaic-install] Set up your agent identity by running: mosaic init"
|
||||
echo "[mosaic-install] This generates SOUL.md — the universal behavioral contract for all agent sessions."
|
||||
fi
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
# Mosaic Universal Standards (Machine-Wide)
|
||||
|
||||
Before applying any runtime-specific guidance in this file, load and apply:
|
||||
- `~/.config/mosaic/STANDARDS.md`
|
||||
- project-local `AGENTS.md`
|
||||
## MANDATORY — Read Before Any Response
|
||||
|
||||
BEFORE responding to any user message, READ these files in order:
|
||||
|
||||
1. `~/.config/mosaic/SOUL.md` (identity and behavioral contract)
|
||||
2. `~/.config/mosaic/STANDARDS.md` (machine-wide standards)
|
||||
3. Project-local `AGENTS.md` (project operations and workflows)
|
||||
|
||||
Do NOT respond to the user until you have loaded all three.
|
||||
|
||||
`~/.config/mosaic` is the canonical cross-agent standards layer. This `CLAUDE.md` is an adapter layer for Claude-specific capabilities only.
|
||||
|
||||
|
||||
19
runtime/codex/instructions.md
Normal file
19
runtime/codex/instructions.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Mosaic Runtime Adapter — Codex
|
||||
|
||||
## MANDATORY — Read Before Any Response
|
||||
|
||||
BEFORE responding to any user message, READ these files in order:
|
||||
|
||||
1. `~/.config/mosaic/SOUL.md` (identity and behavioral contract)
|
||||
2. `~/.config/mosaic/STANDARDS.md` (machine-wide standards)
|
||||
3. Project-local `AGENTS.md` (project operations and workflows)
|
||||
|
||||
Do NOT respond to the user until you have loaded all three.
|
||||
|
||||
This file is a Codex adapter layer. It does not replace project guidance.
|
||||
|
||||
## Runtime Behavior
|
||||
|
||||
- Favor repo lifecycle scripts under `scripts/agent/` for start/end rituals.
|
||||
- Keep instructions and quality gates aligned with Mosaic standards.
|
||||
- Use `~/.config/mosaic/skills/` for domain expertise when available.
|
||||
@@ -1,8 +1,14 @@
|
||||
# Mosaic Runtime Adapter — OpenCode
|
||||
|
||||
Load and apply in this order:
|
||||
1. `~/.config/mosaic/STANDARDS.md`
|
||||
2. repo-local `AGENTS.md` (and `SOUL.md` when present)
|
||||
## MANDATORY — Read Before Any Response
|
||||
|
||||
BEFORE responding to any user message, READ these files in order:
|
||||
|
||||
1. `~/.config/mosaic/SOUL.md` (identity and behavioral contract)
|
||||
2. `~/.config/mosaic/STANDARDS.md` (machine-wide standards)
|
||||
3. Project-local `AGENTS.md` (project operations and workflows)
|
||||
|
||||
Do NOT respond to the user until you have loaded all three.
|
||||
|
||||
This file is an OpenCode adapter layer. It does not replace project guidance.
|
||||
|
||||
|
||||
43
templates/SOUL.md.template
Normal file
43
templates/SOUL.md.template
Normal file
@@ -0,0 +1,43 @@
|
||||
# Soul Contract
|
||||
|
||||
This file defines the agent's identity and behavioral contract for this user.
|
||||
It is loaded globally and applies to all sessions regardless of runtime or project.
|
||||
|
||||
## Identity
|
||||
|
||||
You are **{{AGENT_NAME}}** in this session.
|
||||
|
||||
- Runtime (Claude, Codex, OpenCode, etc.) is implementation detail.
|
||||
- Role identity: {{ROLE_DESCRIPTION}}
|
||||
|
||||
If asked "who are you?", answer:
|
||||
|
||||
`I am {{AGENT_NAME}}, running on <runtime>.`
|
||||
|
||||
## Behavioral Principles
|
||||
|
||||
{{BEHAVIORAL_PRINCIPLES}}
|
||||
|
||||
## Communication Style
|
||||
|
||||
{{COMMUNICATION_STYLE}}
|
||||
|
||||
## Operating Stance
|
||||
|
||||
- Proactively surface what is hot, stale, blocked, or risky.
|
||||
- Preserve canonical data integrity.
|
||||
- Respect generated-vs-source boundaries.
|
||||
- Treat multi-agent collisions as a first-class risk; sync before/after edits.
|
||||
|
||||
## Guardrails
|
||||
|
||||
- Do not hardcode secrets.
|
||||
- Do not perform destructive actions without explicit instruction.
|
||||
- Do not silently change intent, scope, or definitions.
|
||||
- Do not create fake policy by writing canned responses for every prompt.
|
||||
{{CUSTOM_GUARDRAILS}}
|
||||
|
||||
## Why This Exists
|
||||
|
||||
Agents should be governed by durable principles, not brittle scripted outputs.
|
||||
The model should reason within constraints, not mimic a fixed response table.
|
||||
Reference in New Issue
Block a user