#!/bin/sh # Load the four immutable contract files in fixed order and write the # generated system prompt to /var/lib/mosaic/system-prompt.md. # # Order is normative: CONSTITUTION.md, STANDARDS.md, SOUL.md, USER.md. set -eu CONTRACT_DIR="${1:-/opt/mosaic/contracts}" OUT="${2:-/var/lib/mosaic/system-prompt.md}" FILES="CONSTITUTION.md STANDARDS.md SOUL.md USER.md" if [ ! -d "$CONTRACT_DIR" ]; then echo "load-contracts: contract directory not found: $CONTRACT_DIR" >&2 exit 1 fi PARENT="$(dirname "$OUT")" mkdir -p "$PARENT" TEMP="$OUT.partial" : > "$TEMP" for f in $FILES; do path="$CONTRACT_DIR/$f" if [ ! -r "$path" ]; then echo "load-contracts: missing contract file: $path" >&2 rm -f "$TEMP" exit 1 fi printf '===== CONTRACT: %s =====\n' "$f" >> "$TEMP" cat "$path" >> "$TEMP" printf '\n' >> "$TEMP" done # Sanctioned mission injection point (M4): when the task runner provides a # mission snapshot, its objective and directives are appended AFTER the # immutable contracts. Runtime data; never part of the contract fixtures. if [ -n "${MOSAIC_MISSION_FILE:-}" ]; then if [ ! -r "$MOSAIC_MISSION_FILE" ]; then echo "load-contracts: MOSAIC_MISSION_FILE set but not readable: $MOSAIC_MISSION_FILE" >&2 rm -f "$TEMP" exit 1 fi printf '===== MISSION (runtime) =====\n' >> "$TEMP" node -e ' const m = JSON.parse(require("fs").readFileSync(process.env.MOSAIC_MISSION_FILE, "utf8")); process.stdout.write("Objective: " + m.objective + "\n"); for (const d of m.directives ?? []) process.stdout.write("- " + d + "\n"); ' >> "$TEMP" printf '\n' >> "$TEMP" fi mv "$TEMP" "$OUT" echo "load-contracts: wrote $OUT from $CONTRACT_DIR" >&2