commit a7ceeb0bbb645fbae07a5eff8c711c8896830316 Author: Jason Woltje Date: Tue Feb 17 10:41:09 2026 -0600 feat: initial mosaic bootstrap framework diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ed8f26 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# Mosaic Agent Framework + +`~/.mosaic` is the universal userspace standards layer (master) for all agent runtimes. + +## Install Master Layer + +From `jarvis-brain` repo root: + +```bash +bash scripts/agent/bootstrap-mosaic.sh +``` + +Or directly from this package source: + +```bash +bash userspace/mosaic/install.sh +``` + +## What It Provides + +- Shared standards document: `~/.mosaic/STANDARDS.md` +- Runtime adapter docs: `~/.mosaic/adapters/` +- Shared wrapper commands: `~/.mosaic/bin/` + +## Usage + +Inside any compatible repository: + +```bash +~/.mosaic/bin/mosaic-session-start +~/.mosaic/bin/mosaic-critical +~/.mosaic/bin/mosaic-session-end +``` + +Wrapper commands call local repo scripts under `scripts/agent/`. + +## Bootstrap Any Repo (Slave Linkage) + +Attach any repository/workspace to the master layer: + +```bash +~/.mosaic/bin/mosaic-bootstrap-repo /path/to/repo +``` + +This creates/updates: + +- `.mosaic/` (repo-specific hook/config surface) +- `scripts/agent/` (portable lifecycle scripts) +- `AGENTS.md` (if missing) diff --git a/STANDARDS.md b/STANDARDS.md new file mode 100644 index 0000000..981030b --- /dev/null +++ b/STANDARDS.md @@ -0,0 +1,46 @@ +# Mosaic Universal Agent Standards + +This file is the canonical standards contract for agent sessions on this machine. + +Master/slave model: +- Master: `~/.mosaic` (this framework) +- Slave: each repo bootstrapped via `mosaic-bootstrap-repo` + +## Execution Model + +1. Load this file first. +2. Load project-local `AGENTS.md` next. +3. Respect repository-specific tooling and workflows. +4. Use lifecycle scripts when available (`scripts/agent/*.sh`). + +## Non-Negotiables + +- Data files are authoritative; generated views are derived artifacts. +- Pull before edits when collaborating in shared repos. +- Run validation checks before claiming completion. +- Avoid hardcoded secrets and token leakage in remotes/commits. +- Do not perform destructive git/file actions without explicit instruction. + +## Session Lifecycle Contract + +- Start: `scripts/agent/session-start.sh` +- Priority scan: `scripts/agent/critical.sh` +- End: `scripts/agent/session-end.sh` +- Limitation logging helper: `scripts/agent/log-limitation.sh "Title"` + +If a repo does not expose these scripts, run equivalent local workflow commands and document deviations. + +## Multi-Agent Safety + +- Coordinate through git pull/rebase discipline. +- Do not auto-resolve data conflicts in shared state files. +- Keep commits scoped to a single logical change set. + +## Prompting Contract + +All runtime adapters should inject: + +- `~/.mosaic/STANDARDS.md` +- project `AGENTS.md` + +before task execution. diff --git a/adapters/claude.md b/adapters/claude.md new file mode 100644 index 0000000..7081e92 --- /dev/null +++ b/adapters/claude.md @@ -0,0 +1,16 @@ +# Claude Adapter + +Use this adapter when running Claude CLI sessions. + +## Required Context + +1. `~/.mosaic/STANDARDS.md` +2. `/AGENTS.md` + +## Command Wrapper + +Use wrapper commands from `~/.mosaic/bin/` for lifecycle rituals. + +## Migration Note + +Project-local `.claude/commands/*.md` should call `scripts/agent/*.sh` so behavior stays runtime-neutral. diff --git a/adapters/codex.md b/adapters/codex.md new file mode 100644 index 0000000..dada518 --- /dev/null +++ b/adapters/codex.md @@ -0,0 +1,13 @@ +# Codex Adapter + +Use this adapter when running Codex CLI sessions. + +## Required Context + +1. `~/.mosaic/STANDARDS.md` +2. `/AGENTS.md` + +## Runtime Behavior + +- Favor repo lifecycle scripts under `scripts/agent/` for start/end rituals. +- Keep instructions and quality gates aligned with Mosaic standards. diff --git a/adapters/generic.md b/adapters/generic.md new file mode 100644 index 0000000..e47a9d7 --- /dev/null +++ b/adapters/generic.md @@ -0,0 +1,14 @@ +# Generic Adapter + +For runtimes without a first-class adapter yet. + +## Required Context + +1. Load `~/.mosaic/STANDARDS.md` +2. Load project `AGENTS.md` + +## Minimal Contract + +- Use `scripts/agent/session-start.sh` at start if present. +- Use `scripts/agent/session-end.sh` before completion if present. +- If missing, run equivalent repo commands and report what was executed. diff --git a/bin/mosaic-bootstrap-repo b/bin/mosaic-bootstrap-repo new file mode 100755 index 0000000..bf678af --- /dev/null +++ b/bin/mosaic-bootstrap-repo @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +set -euo pipefail + +TARGET_DIR="$(pwd)" +FORCE=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + --force) + FORCE=1 + shift + ;; + *) + TARGET_DIR="$1" + shift + ;; + esac +done + +if [[ ! -d "$TARGET_DIR" ]]; then + echo "[mosaic] Target directory does not exist: $TARGET_DIR" >&2 + exit 1 +fi + +MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.mosaic}" +TEMPLATE_ROOT="$MOSAIC_HOME/templates/repo" + +if [[ ! -d "$TEMPLATE_ROOT" ]]; then + echo "[mosaic] Missing templates at $TEMPLATE_ROOT" >&2 + echo "[mosaic] Install or refresh framework: ~/.mosaic/install.sh" >&2 + exit 1 +fi + +mkdir -p "$TARGET_DIR/.mosaic" "$TARGET_DIR/scripts/agent" + +copy_file() { + local src="$1" + local dst="$2" + + if [[ -f "$dst" && "$FORCE" -ne 1 ]]; then + echo "[mosaic] Skip existing: $dst" + return + fi + + cp "$src" "$dst" + echo "[mosaic] Wrote: $dst" +} + +copy_file "$TEMPLATE_ROOT/.mosaic/README.md" "$TARGET_DIR/.mosaic/README.md" +copy_file "$TEMPLATE_ROOT/.mosaic/repo-hooks.sh" "$TARGET_DIR/.mosaic/repo-hooks.sh" + +for file in "$TEMPLATE_ROOT"/scripts/agent/*.sh; do + base="$(basename "$file")" + copy_file "$file" "$TARGET_DIR/scripts/agent/$base" + chmod +x "$TARGET_DIR/scripts/agent/$base" +done + +if [[ ! -f "$TARGET_DIR/AGENTS.md" ]]; then + cat > "$TARGET_DIR/AGENTS.md" <<'AGENTS_EOF' +# Agent Guidelines + +## Standards Load Order + +1. `~/.mosaic/STANDARDS.md` +2. `AGENTS.md` (this file) +3. `.mosaic/repo-hooks.sh` + +## Session Lifecycle + +```bash +bash scripts/agent/session-start.sh +bash scripts/agent/critical.sh +bash scripts/agent/session-end.sh +``` + +## Repo-Specific Notes + +- Add project constraints and workflows here. +- Implement hook functions in `.mosaic/repo-hooks.sh`. +AGENTS_EOF + echo "[mosaic] Wrote: $TARGET_DIR/AGENTS.md" +else + echo "[mosaic] AGENTS.md exists; add standards load order if missing" +fi + +echo "[mosaic] Repo bootstrap complete: $TARGET_DIR" +echo "[mosaic] Next: edit $TARGET_DIR/.mosaic/repo-hooks.sh with project workflows" diff --git a/bin/mosaic-critical b/bin/mosaic-critical new file mode 100755 index 0000000..57795f1 --- /dev/null +++ b/bin/mosaic-critical @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ -x "scripts/agent/critical.sh" ]]; then + exec bash scripts/agent/critical.sh +fi + +echo "[mosaic] Missing scripts/agent/critical.sh in $(pwd)" >&2 +exit 1 diff --git a/bin/mosaic-log-limitation b/bin/mosaic-log-limitation new file mode 100755 index 0000000..7407b84 --- /dev/null +++ b/bin/mosaic-log-limitation @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ -x "scripts/agent/log-limitation.sh" ]]; then + exec bash scripts/agent/log-limitation.sh "$@" +fi + +echo "[mosaic] Missing scripts/agent/log-limitation.sh in $(pwd)" >&2 +exit 1 diff --git a/bin/mosaic-session-end b/bin/mosaic-session-end new file mode 100755 index 0000000..e928968 --- /dev/null +++ b/bin/mosaic-session-end @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ -x "scripts/agent/session-end.sh" ]]; then + exec bash scripts/agent/session-end.sh "$@" +fi + +echo "[mosaic] Missing scripts/agent/session-end.sh in $(pwd)" >&2 +exit 1 diff --git a/bin/mosaic-session-start b/bin/mosaic-session-start new file mode 100755 index 0000000..6505809 --- /dev/null +++ b/bin/mosaic-session-start @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ -x "scripts/agent/session-start.sh" ]]; then + exec bash scripts/agent/session-start.sh +fi + +echo "[mosaic] Missing scripts/agent/session-start.sh in $(pwd)" >&2 +exit 1 diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..2b2ac53 --- /dev/null +++ b/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TARGET_DIR="${MOSAIC_HOME:-$HOME/.mosaic}" + +mkdir -p "$TARGET_DIR" + +if command -v rsync >/dev/null 2>&1; then + rsync -a --delete "$SOURCE_DIR/" "$TARGET_DIR/" +else + rm -rf "$TARGET_DIR"/* + cp -R "$SOURCE_DIR"/* "$TARGET_DIR"/ +fi + +chmod +x "$TARGET_DIR"/bin/* +chmod +x "$TARGET_DIR"/install.sh + +echo "[mosaic-install] Installed framework to $TARGET_DIR" +echo "[mosaic-install] Add to PATH: export PATH=\"$TARGET_DIR/bin:$PATH\"" diff --git a/templates/repo/.mosaic/README.md b/templates/repo/.mosaic/README.md new file mode 100644 index 0000000..606f88a --- /dev/null +++ b/templates/repo/.mosaic/README.md @@ -0,0 +1,15 @@ +# Repo Mosaic Linkage + +This repository is attached to the machine-wide Mosaic framework. + +## Load Order for Agents + +1. `~/.mosaic/STANDARDS.md` +2. `AGENTS.md` (this repository) +3. `.mosaic/repo-hooks.sh` (repo-specific automation hooks) + +## Purpose + +- Keep universal standards in `~/.mosaic` +- Keep repo-specific behavior in this repo +- Avoid copying large runtime configs into each project diff --git a/templates/repo/.mosaic/repo-hooks.sh b/templates/repo/.mosaic/repo-hooks.sh new file mode 100755 index 0000000..8a09763 --- /dev/null +++ b/templates/repo/.mosaic/repo-hooks.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Optional repo-specific hooks used by scripts/agent/*.sh + +# Called by session-start.sh +# mosaic_hook_session_start() { +# echo "Run repo-specific startup checks" +# } + +# Called by critical.sh +# mosaic_hook_critical() { +# echo "Run repo-specific critical queries" +# } + +# Called by session-end.sh +# mosaic_hook_session_end() { +# echo "Run repo-specific end-of-session checks" +# } diff --git a/templates/repo/scripts/agent/common.sh b/templates/repo/scripts/agent/common.sh new file mode 100755 index 0000000..a9a0c38 --- /dev/null +++ b/templates/repo/scripts/agent/common.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root() { + git rev-parse --show-toplevel 2>/dev/null || pwd +} + +ensure_repo_root() { + cd "$(repo_root)" +} + +has_remote() { + git remote get-url origin >/dev/null 2>&1 +} + +run_step() { + local label="$1" + shift + echo "[agent-framework] $label" + "$@" +} + +load_repo_hooks() { + local hooks_file=".mosaic/repo-hooks.sh" + if [[ -f "$hooks_file" ]]; then + # shellcheck disable=SC1090 + source "$hooks_file" + fi +} diff --git a/templates/repo/scripts/agent/critical.sh b/templates/repo/scripts/agent/critical.sh new file mode 100755 index 0000000..f345425 --- /dev/null +++ b/templates/repo/scripts/agent/critical.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=./common.sh +source "$SCRIPT_DIR/common.sh" + +ensure_repo_root +load_repo_hooks + +if declare -F mosaic_hook_critical >/dev/null 2>&1; then + run_step "Run repo critical hook" mosaic_hook_critical +else + echo "[agent-framework] No repo critical hook configured (.mosaic/repo-hooks.sh)" + echo "[agent-framework] Define mosaic_hook_critical() for project-specific priority scans" +fi diff --git a/templates/repo/scripts/agent/log-limitation.sh b/templates/repo/scripts/agent/log-limitation.sh new file mode 100755 index 0000000..1b7eecb --- /dev/null +++ b/templates/repo/scripts/agent/log-limitation.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +TITLE="${1:-}" +if [[ -z "$TITLE" ]]; then + echo "Usage: $0 \"Short limitation title\"" >&2 + exit 1 +fi + +FILE="EVOLUTION.md" +if [[ ! -f "$FILE" ]]; then + echo "[agent-framework] $FILE not found. Create project-specific limitations log if needed." + exit 0 +fi + +if command -v rg >/dev/null 2>&1; then + last_num=$(rg -o "^### L-[0-9]{3}" "$FILE" | sed 's/^### L-//' | sort -n | tail -1) +else + last_num=$(grep -E "^### L-[0-9]{3}" "$FILE" | sed 's/^### L-//' | sort -n | tail -1) +fi + +if [[ -z "$last_num" ]]; then + next_num="001" +else + next_num=$(printf "%03d" $((10#$last_num + 1))) +fi + +entry_id="L-$next_num" + +cat </dev/null 2>&1; then + run_step "Run repo end hook" mosaic_hook_session_end +else + echo "[agent-framework] No repo end hook configured (.mosaic/repo-hooks.sh)" +fi + +if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + run_step "Show status" git status --short + run_step "Show diff summary" git diff --stat +fi diff --git a/templates/repo/scripts/agent/session-start.sh b/templates/repo/scripts/agent/session-start.sh new file mode 100755 index 0000000..f5efc64 --- /dev/null +++ b/templates/repo/scripts/agent/session-start.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=./common.sh +source "$SCRIPT_DIR/common.sh" + +ensure_repo_root +load_repo_hooks + +if git rev-parse --is-inside-work-tree >/dev/null 2>&1 && has_remote; then + run_step "Pull latest changes" git pull --rebase +fi + +if declare -F mosaic_hook_session_start >/dev/null 2>&1; then + run_step "Run repo start hook" mosaic_hook_session_start +else + echo "[agent-framework] No repo start hook configured (.mosaic/repo-hooks.sh)" +fi