Co-authored-by: code-be-01 <[email protected]>
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
trashoverrmwhen available — recoverable beats gone forever - Never run destructive commands without explicit instruction
- Write it down — "mental notes" don't survive session restarts; files do