Files
stack/packages/mosaic/framework/guides/TOOLS-REFERENCE.md
T
code-be-01andorch-01 9014a510a9
ci/woodpecker/push/publish Pipeline was successful
ci(mosaic): repo-structure declaration CI gate (T51 WP5c) (#1378)
Co-authored-by: code-be-01 <[email protected]>
2026-08-24 04:43:26 +00:00

18 KiB

Machine-Level Tool Reference

Centralized reference for tools, credentials, and CLI patterns available across all projects. Project-specific tooling belongs in the project's AGENTS.md, not here.

All tool suites are located at ~/.config/mosaic/tools/.

Tool Suites

Git Wrappers (Use First)

Mosaic wrappers at ~/.config/mosaic/tools/git/*.sh handle platform detection and edge cases. Always use these before raw CLI commands.

This index is complete and is kept complete mechanically: tools/quality/scripts/check-tools-index.sh fails CI when a wrapper ships without an entry here, or when an entry here names a wrapper that no longer exists. A wrapper missing from this list is, from inside an agent session, indistinguishable from a wrapper that was never written — which is how the APPROVE/APPROVED incident below happened.

Every command takes --help. All of them accept --login <account> to pin the acting identity; supply it explicitly on any host where the provider CLI's default account is an admin.

Issues
issue-create.sh Create an issue (Gitea or GitHub)
issue-view.sh Show one issue
issue-list.sh List issues
issue-edit.sh Edit title/body/labels/milestone
issue-comment.sh Add a comment
issue-assign.sh Assign or unassign
issue-close.sh Close an issue
issue-reopen.sh Reopen a closed issue
Pull requests
pr-create.sh Open a pull request
pr-edit.sh Edit PR title, body, base branch, or draft/ready state
pr-view.sh Show one PR
pr-list.sh List PRs
pr-diff.sh Fetch a PR's diff
pr-metadata.sh PR metadata as JSON (head SHA, base, state, mergeability)
pr-review.sh Place a review verdict — see the dialect note below
pr-ci-wait.sh Block until the PR's CI reaches a terminal state
pr-merge.sh Merge a PR
pr-close.sh Close a PR without merging
Milestones
milestone-create.sh Create a milestone
milestone-list.sh List milestones
milestone-close.sh Close a milestone
Gates and guards
ci-queue-wait.sh CI queue guard — required before push/merge (see below)
push-guard.sh Refuse verifications that pass for the wrong reason (e.g. green against an unpushed tree)
mutate-push-guard.sh Regenerate the guard's mutation-coverage table from measurement, so the table cannot drift from the guard
verify-clean-clone.sh Prove the committed artifact runs, from a clean clone — not the working tree
Context
detect-platform.sh Resolve the provider (Gitea vs GitHub) for the current repo; every other wrapper uses it
lane-brief.sh Live dispatch brief for a repo "lane" (milestone/label) straight from the provider
Workspace
mosaic-worktree.sh Create/list/remove git worktrees — the only supported way; see below
wrapper-guard.sh PreToolUse hook that enforces the two rules above; not called by hand

Workspace placement is derived, not chosen. mosaic-worktree.sh new <branch> takes a branch name and nothing else. Every path comes out of git worktree list --porcelain — main worktree, repo name, parent dir, then <parent>/<repo>-worktrees/<branch-slug>. There is no placement flag because a decision an agent has to make is a decision that drifts: the rule "big work goes on a work filesystem" already existed in prose and 255 GB accumulated in $HOME across 842 directories anyway, under five simultaneous conventions on a single host.

~/.config/mosaic/tools/git/mosaic-worktree.sh new <branch> [--from <base>]
~/.config/mosaic/tools/git/mosaic-worktree.sh path <branch>   # derived path, no side effect
~/.config/mosaic/tools/git/mosaic-worktree.sh list            # this repo's worktrees + state
~/.config/mosaic/tools/git/mosaic-worktree.sh rm <branch>     # removal is part of the task
~/.config/mosaic/tools/git/mosaic-worktree.sh gc [--apply]    # reclaim clean + fully-pushed ones

Worktrees rather than clones, because git worktree list makes every checkout enumerable — a bare clone dropped somewhere on disk can never be safely reclaimed, so it is never reclaimed. rm and gc decide by evidence, never by size or age: a worktree is reclaimable only when git status --porcelain is empty and git rev-list --count HEAD --not --remotes is 0. Anything else is preserved and reported. --force exists and is yours to type deliberately.

wrapper-guard.sh is registered as a Claude Code PreToolUse hook on Bash (see runtime/claude/settings.json). It blocks exactly three things and lets everything else through: a git clone/git worktree add targeting $HOME; a raw provider-API write to an endpoint that already has a wrapper above (reads are untouched — they are how you gather evidence); and the literal "event": "APPROVE". For a genuine gap no wrapper can express, prefix MOSAIC_WRAPPER_OVERRIDE=1. Reaching for the override twice for the same call means the wrapper has a missing flag — extend the wrapper.

~/.config/mosaic/tools/git/issue-create.sh --help
~/.config/mosaic/tools/git/pr-review.sh --pr 42 --event APPROVED --body "..."

# CI queue guard (required before push/merge; defaults to the checked-out branch)
~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose push|merge

Review dialect — the reason pr-review.sh is not optional. Gitea's approve event is APPROVED; GitHub's is APPROVE. Send GitHub's spelling to a Gitea host and it answers HTTP 200, files the review as PENDING, and then rejects the submit with 422 review stay pending — the verdict looks placed and is not. (REQUEST_CHANGES is spelled identically on both, so only the approve path carries the trap.) pr-review.sh sends the correct token for the detected provider. Whatever you use, re-read GET /pulls/{n}/reviews and assert the state before reporting a verdict placed.

The guard exits nonzero for any provider-asserted non-green, missing, or malformed CI state. If credentials or the provider are unavailable, it emits CANNOT_ASSERT and writes a JSONL audit record. Push degrades to exit 0 so recovery work is not bricked; merge holds with retryable exit 75 until the provider recovers, then self-clears without manual reset. Neither outcome is evidence that CI was clear. For a repository with no CI configured at all, pr-merge.sh --no-ci-expected is the sanctioned merge path: it forwards to ci-queue-wait.sh --no-ci-expected, which reclassifies a zero-context merge head as queue-clear only when the acting token holds repository admin and MOSAIC_GIT_IDENTITY names the asserting identity (a caller without one is refused with exit 78 before the admin lookup), and records the assertion (or its refusal) in the same JSONL audit log. pr-merge.sh automatically inspects the exact PR head repository and full commit SHA rather than its main base; this also handles fork PRs without branch-name ambiguity. Pass --expect-head <approved-full-sha> to bind a commit-specific review or merge-gate verdict; Gitea uses atomic head_commit_id and GitHub uses --match-head-commit.

Code Review (Codex)

~/.config/mosaic/tools/codex/codex-code-review.sh --uncommitted
~/.config/mosaic/tools/codex/codex-security-review.sh --uncommitted

Infrastructure — Portainer

~/.config/mosaic/tools/portainer/stack-status.sh -n <stack-name>
~/.config/mosaic/tools/portainer/stack-redeploy.sh -n <stack-name>
~/.config/mosaic/tools/portainer/stack-list.sh
~/.config/mosaic/tools/portainer/endpoint-list.sh

Infrastructure — Coolify (DEPRECATED)

Coolify has been superseded by Portainer Docker Swarm in this stack. Tools remain for reference but should not be used for new deployments.

# DEPRECATED — do not use for new deployments
~/.config/mosaic/tools/coolify/project-list.sh
~/.config/mosaic/tools/coolify/service-list.sh
~/.config/mosaic/tools/coolify/service-status.sh -u <uuid>
~/.config/mosaic/tools/coolify/deploy.sh -u <uuid>
~/.config/mosaic/tools/coolify/env-set.sh -u <uuid> -k KEY -v VALUE

Identity — Authentik

~/.config/mosaic/tools/authentik/user-list.sh
~/.config/mosaic/tools/authentik/user-create.sh -u <username> -n <name> -e <email>
~/.config/mosaic/tools/authentik/group-list.sh
~/.config/mosaic/tools/authentik/app-list.sh
~/.config/mosaic/tools/authentik/flow-list.sh
~/.config/mosaic/tools/authentik/admin-status.sh

CI/CD — Woodpecker

Multi-instance support: -a <instance> selects a named instance. Omit -a to use the default from woodpecker.default in credentials.json.

Instance URL Serves
mosaic (default) ci.mosaicstack.dev Mosaic repos (git.mosaicstack.dev)
usc ci.uscllc.com USC repos (git.uscllc.com)
# List recent pipelines
~/.config/mosaic/tools/woodpecker/pipeline-list.sh [-r owner/repo] [-a instance]

# Check latest or specific pipeline status
~/.config/mosaic/tools/woodpecker/pipeline-status.sh [-r owner/repo] [-n number] [-a instance]

# Trigger a build
~/.config/mosaic/tools/woodpecker/pipeline-trigger.sh [-r owner/repo] [-b branch] [-a instance]

Instance selection rule: match -a to the git remote host of the target repo. If the repo is on git.uscllc.com, use -a usc. If on git.mosaicstack.dev, use -a mosaic (or omit, since it's the default).

DNS — Cloudflare

Multi-instance support: -a <instance> selects a named instance (e.g. personal, work). Omit -a to use the default from cloudflare.default in credentials.json.

# List zones (domains)
~/.config/mosaic/tools/cloudflare/zone-list.sh [-a instance]

# List DNS records (zone by name or ID)
~/.config/mosaic/tools/cloudflare/record-list.sh -z <zone> [-a instance] [-t type] [-n name]

# Create DNS record
~/.config/mosaic/tools/cloudflare/record-create.sh -z <zone> -t <type> -n <name> -c <content> [-a instance] [-p] [-l ttl] [-P priority]

# Update DNS record
~/.config/mosaic/tools/cloudflare/record-update.sh -z <zone> -r <record-id> -t <type> -n <name> -c <content> [-a instance] [-p] [-l ttl]

# Delete DNS record
~/.config/mosaic/tools/cloudflare/record-delete.sh -z <zone> -r <record-id> [-a instance]

IT Service — GLPI

~/.config/mosaic/tools/glpi/ticket-list.sh
~/.config/mosaic/tools/glpi/ticket-create.sh -t <title> -c <content>
~/.config/mosaic/tools/glpi/computer-list.sh
~/.config/mosaic/tools/glpi/user-list.sh

Health Check

# Check all configured services
~/.config/mosaic/tools/health/stack-health.sh

# Check a specific service
~/.config/mosaic/tools/health/stack-health.sh -s portainer

# JSON output for automation
~/.config/mosaic/tools/health/stack-health.sh -f json

Repo Structure Declaration (T51)

# Validate a .mosaic/repo.json declaration (schema v1/v2, host:/ grammar,
# ref grammar, cross-field rules, remote normalization; spec §5)
~/.config/mosaic/tools/structure/validate-repo-json.sh <repo>/.mosaic/repo.json

# CI authoring rule: new/edited declarations must be schema_version 2
~/.config/mosaic/tools/structure/validate-repo-json.sh <repo>/.mosaic/repo.json --require-v2

# Display mode (warns and omits root-dependent checks when MOSAIC_HOST_ROOT unset)
~/.config/mosaic/tools/structure/validate-repo-json.sh <repo>/.mosaic/repo.json --mode display

# Hermetic hostile-input suite (101 arms)
~/.config/mosaic/tools/structure/test-validate-repo-json.sh

Shared Credential Loader

# Source in any script to load service credentials
source ~/.config/mosaic/tools/_lib/credentials.sh
load_credentials <service-name>
# Supported: portainer, coolify, authentik, glpi, github, gitea-mosaicstack, gitea-usc, woodpecker, cloudflare, turbo-cache, openbrain

OpenBrain — Semantic Memory (PRIMARY)

Self-hosted semantic brain backed by pgvector. Primary shared memory layer for all agents across all sessions and harnesses. Stores and retrieves decisions, context, and observations via semantic search.

Credentials: load_credentials openbrain → exports OPENBRAIN_URL, OPENBRAIN_TOKEN

Configure in your credentials.json:

"openbrain": {
  "url": "https://<your-openbrain-host>",
  "api_key": "<your-api-key>"
}

REST API (any language, any harness):

source ~/.config/mosaic/tools/_lib/credentials.sh && load_credentials openbrain

# Search by meaning
curl -s -X POST -H "Authorization: Bearer $OPENBRAIN_TOKEN" -H "Content-Type: application/json" \
  -d '{"query": "your search", "limit": 5}' "$OPENBRAIN_URL/v1/search"

# Capture a thought
curl -s -X POST -H "Authorization: Bearer $OPENBRAIN_TOKEN" -H "Content-Type: application/json" \
  -d '{"content": "...", "source": "agent-name", "metadata": {}}' "$OPENBRAIN_URL/v1/thoughts"

# Recent activity
curl -s -H "Authorization: Bearer $OPENBRAIN_TOKEN" "$OPENBRAIN_URL/v1/thoughts/recent?limit=5"

# Stats
curl -s -H "Authorization: Bearer $OPENBRAIN_TOKEN" "$OPENBRAIN_URL/v1/stats"

Python client (if the OpenBrain client is on your PYTHONPATH):

python tools/openbrain_client.py search "topic"
python tools/openbrain_client.py capture "decision or observation" --source agent-name
python tools/openbrain_client.py recent --limit 5
python tools/openbrain_client.py stats

MCP (Claude Code sessions): When connected, mcp__openbrain__capture/search/recent/stats tools are available natively — prefer those over CLI when in a Claude session.

Rule: capture when you LEARN something. Never when you DO something.

Trigger Action Retention
Session start search + recent to load prior context
Architectural or tooling decision made Capture with rationale long or permanent
Gotcha or non-obvious behavior discovered Capture immediately medium
User preference stated or confirmed Capture permanent
Cross-project pattern identified Capture permanent
Prior decision superseded UPDATE existing thought (keep tier)

Never capture: task started, commit pushed, PR opened, test results, file edits, CI status.

Full protocol and cleanup tools: ~/.config/mosaic/guides/MEMORY.md Smart capture wrapper (enforces schema + dedup): ~/.config/mosaic/tools/openbrain/capture.sh

Excalidraw — Diagram Export (MCP)

Headless .excalidraw → SVG export via @excalidraw/excalidraw. Available as MCP tools in Claude Code sessions.

MCP tools (when connected):

Tool Input Output
mcp__excalidraw__excalidraw_to_svg elements JSON string + optional app_state SVG string
mcp__excalidraw__excalidraw_file_to_svg file_path to .excalidraw SVG string + writes .svg alongside
mcp__excalidraw__list_diagrams (none) Available templates (requires EXCALIDRAW_GEN_PATH)
mcp__excalidraw__generate_diagram name, optional output_path Path to generated .excalidraw
mcp__excalidraw__generate_and_export name, optional output_path Paths to .excalidraw and .svg

Diagram generation (list_diagrams, generate_diagram, generate_and_export) requires EXCALIDRAW_GEN_PATH env var pointing to excalidraw_gen.py. Set in environment or shell profile:

export EXCALIDRAW_GEN_PATH="$HOME/.config/mosaic/tools/excalidraw/excalidraw_gen.py"

Manual registration:

mosaic-ensure-excalidraw           # install deps + register with Claude
mosaic-ensure-excalidraw --check   # verify registration

Git Providers

Instance URL CLI Purpose
(add your git providers here)

Credentials

Location: (configure your credential file path) Loader: source ~/.config/mosaic/tools/_lib/credentials.sh && load_credentials <service>

Never expose actual values. Never commit credential files.

CLI Gotchas

(Add platform-specific CLI gotchas as you discover them.)

Safety Defaults

  • Prefer trash over rm when available — recoverable beats gone forever
  • Never run destructive commands without explicit instruction
  • Write it down — "mental notes" don't survive session restarts; files do