Remove references to crush.json, hooks/, and Crush-specific enforcement from README, AGENTS.md, BASELINE-PROMPT.md, and PATTERNS.md. Generalize the commit footer to be harness-agnostic (<harness/tool> placeholder). Update PATTERNS.md decisions and scorecard to reflect the reversal: Crush hooks were studied but deliberately not shipped. The only remaining Crush mention explicitly states it is avoided for portability. The .crush/memory/ dir is kept as an optional Crush feature. 💘 Generated with Crush Assisted-by: Crush via Crush <crush@charm.land>
16 KiB
Cross-Project Pattern Extraction
Scope: 18 projects surveyed across two machines:
- Local (
ultix-streaming): 12 infra/stack projects —dotfiles,EngineeringWorkstation,EngStack,football,hermes-rceo-streaming,KNEL-AIMiddleware,KNELIAC,netbird,PFVCluster,TSYSDevStack-SupportStack-Cloudron,WorkstationStack,TSYSDevStack-SupportStack-LocalWorkstation. - Remote (
ultix-offstage): 6 personal/business projects —CharlesNWybleResume,rceo-automation-espanso-private,RCEO-PersonalAssistant,ReachableCEO-Profile-FullTimeEmployment,RevGen-TimeForMoney,ThreeYearPlan.
This document records the patterns that recur, the inconsistencies between them, and the decisions the repo makes to drive inconsistency to zero.
1. AGENTS.md — recurring structure
A canonical section set emerges from the 12 files that have one (8 local + 4 remote):
| Section | Prevalence |
|---|---|
| Git commit & push policy | 12/12 |
| Project overview / context | 11/12 |
| Key commands / build cheat sheet | 10/12 |
| Repository layout (ASCII tree) | 9/12 |
| Status / journal maintenance | 9/12 |
| Conventions & naming | 8/12 |
| DO / DON'T | 7/12 |
| Validation / testing | 7/12 |
| Key files reference | 6/12 |
| Quick start / onboarding | 5/12 |
Decision: the template's AGENTS.md ships all ten sections in a fixed order,
so every project has the same skeleton. Filler is bracketed for replacement.
2. Shared cross-project preferences (the house style)
These recur strongly and are baked into the template:
- Auto-commit + push is mandatory and non-negotiable. Stated with ALL-CAPS force in nearly every file. The template states the override-once and lets the hooks enforce it.
- Atomic commits — one logical change per commit. Universal.
- Conventional-commit format (
feat:/fix:/docs:/…). Universal, but the 💘 Crush attribution footer is inconsistent: mandated only byfootballandKNELIAC; absent on the remote entirely. Decision: the template mandates the footer once, in the AGENTS.md commit block. - Docker-only host hygiene. The single most consistent convention across both machines (
KNEL-AIMiddleware,EngStack,LocalWorkstation,RCEO-PersonalAssistant,ThreeYearPlan,CharlesNWybleResume). Decision: the template'scheck-rules.shenforces host hygiene via the Docker-only rule (no:latesttags, container naming) andscripts/docker-run.shprovides the canonical container wrapper. The Crush-specificenforce-bash.shhook was removed for harness portability; the policy lives in AGENTS.md prose. - Sub-agents encouraged. Explicit in
football,ThreeYearPlan,RCEO-PersonalAssistant. Decision: standard section in the template. - No secrets in git (infra genre). Inverted on the remote private repos (
RCEO-PersonalAssistantdeliberately commits credentials). Decision: the template keeps the infra stance (.envgitignored) as the default; private repos may opt out.
Inconsistencies the template resolves:
shellcheckis mandated byPFVClusterandfootballbut unmentioned elsewhere → the template mandates it for all shell, via Docker.- "Keep the host clean" is phrased four different ways → one canonical phrasing.
- Auto-commit override language varies in strength → stated once, authoritatively.
3. Git hooks — the biggest gap, now standardized
Finding: custom git hooks are essentially unused. Only 3 of 18 projects have any:
| Project | Hook | Mechanism | Installer |
|---|---|---|---|
football |
pre-commit (4-check SDLC gate: shellcheck, unit tests, coverage, doc-sync) |
core.hooksPath githooks/ |
scripts/setup-githooks.sh |
KNEL-AIMiddleware |
pre-push (block on dirty tree) |
core.hooksPath .githooks/ |
none (manual git config) |
RCEO-PersonalAssistant |
pre-commit (fast audit) + pre-push (full Docker tests) |
copy into .git/hooks/ |
scripts/setup-hooks.sh |
Three different install mechanisms; one project has no installer at all.
Decision: the template uses the copy approach (most portable: works on any clone, no config mutation, idempotent) with a single scripts/setup-hooks.sh, and combines both policy philosophies:
pre-commit= fast audit with a hot-path bypass forSTATUS.md/JOURNAL.md/WORKING.md(so frequent status commits stay frictionless) — proven in RCEO.pre-push= full audit (incl.make test) — proven in RCEO — plus the dirty-tree gate — proven in KNEL-AIMiddleware.
4. Crush hooks — an entirely untapped capability (except one project)
Finding: Crush hooks are used by exactly one project — RCEO-PersonalAssistant. Every other crush.json (and most projects have none) defines only lsp/mcp/options, never hooks. All process enforcement elsewhere is prose in AGENTS.md — manually enforced, violable.
RCEO's crush.json wires five PreToolUse hooks that form a behavioral guardrail layer complementing the git hooks:
| Hook | Matcher | Effect |
|---|---|---|
block-todos.sh |
^todos$ |
bans the todos tool; WORKING.md is the only tracker |
enforce-bash.sh |
^bash$ |
blocks banned commands + host language toolchains |
enforce-rules.sh |
^(edit|write|multiedit)$ |
blocks banned file types; TDD reminder on source edits |
audit-before-git.sh |
^bash$ |
runs the fast audit before any git commit/git push |
exit-protocol.sh |
.* |
blocks stopping while WORKING.md has unchecked tasks |
Decision: the Crush hooks were studied as the proof-of-concept and their policies (ban todos, Docker-only, banned file types, audit before git, exit protocol) were ported into AGENTS.md prose and check-rules.sh mechanical checks. The harness-specific crush.json + hooks/ layer was deliberately removed for portability — the user is shifting away from Crush to OpenWebUI/Hermes, so all enforcement is git hooks + prose only.
5. The rules engine — check-rules.sh
RCO's check-rules.sh is the best reusable artifact found. Its core abstractions:
- A
check()accumulator classifying each rule as pass / warn / fail, withFAIL > 0 ⇒ exit 1andWARNnon-fatal. - A
--fastmode (used by pre-commit) that silences per-check output and skips slow checks. - Self-checking categories: shellcheck, Docker image pinning (no
:latest), required-files manifest, doc freshness (STATUS.md/JOURNAL.md touched today), git state, hooks-installed, WORKING.md completion, unresolvedCNW:markers.
Decision: the template's check-rules.sh generalizes this — language-specific checks (Go test coverage, gofmt) are dropped or made opt-in via PROJECT_* env; universal checks (shellcheck, image pinning, required files, doc freshness, hygiene, WORKING.md, CNW markers, merge-conflict markers) are kept. The check() accumulator and --fast/--quiet flags move into scripts/lib/common.sh so any script can reuse them.
6. Scripts — driving the shebang/boilerplate chaos to zero
Findings:
- Three incompatible shebang variants across projects:
#!/usr/bin/env bash(best),#!/bin/bash,#!/usr/bin/bash(non-portable). - Four different
set-flag policies:set -euo pipefail(best),set -eonly,set -uo pipefail, none. KNEL-AIMiddleware usesset -eonly — piped failures silently swallowed;BuildAll.sh'sdocker compose … | tailcan report green on failure. - The ANSI color block is copy-pasted into ~10 scripts.
log_*helpers are redefined per project (and per-script in KNEL-AIMiddleware, where they aren't even functions).- Repo-root resolution is re-rolled in nearly every script.
- No shared cross-project library exists. Only
EngStackfactors helpers (scripts/lib.shbuild-time +lib/common.shruntime).
Decision: scripts/lib/common.sh provides the deduplicated primitives once: ANSI colors, log_info/ok/warn/error/step, have(), die(), repo_root(), as_root(), docker_run(), and the init_counters/check/print_summary_and_exit audit helpers. All template scripts use #!/usr/bin/env bash + set -euo pipefail.
7. Task runners — five conventions, standardized to one
Findings: no Makefile/Taskfile/justfile exists anywhere. Five incompatible conventions for the same semantic verbs:
| Project | Convention |
|---|---|
| football | ./run.sh <subcommand> |
| KNEL-AIMiddleware | scripts/<Verb>.sh |
| EngStack | scripts/<verb>-<noun>.sh |
| PFVCluster | tests/<name>.sh |
| hermes-agent | npm workspace scripts |
The recurring semantic targets — build, test, lint, validate, status, clean, setup — map cleanly onto one target set that doesn't exist.
Decision: a single Makefile provides setup, validate, fast, lint, test, status, clean, help. It is pure dispatch to scripts/; projects override test/clean for their stack. CI, hooks, and humans now share one set of verbs.
8. CI — present in exactly one project
Only hermes-agent has CI (22 GitHub Actions workflows — an exemplar: change-detection orchestrator, reusable-workflow lanes, SHA-pinned actions, supply-chain/OSV scans, live PR-comment bot). The other 17 have none.
Decision: the template doesn't ship CI (it's stack-dependent), but make validate + make lint give any future workflow a uniform entry point. The hermes-agent ci.yml orchestrator is the documented growth path.
9. Crush configuration layers — documented but unused
Crush defines a priority chain ($HOME/.config/crush/crush.json → crush.json → .crush.json). In practice:
- The global config (
dotfiles) is trivial (attribution style only) — no shared LSP/MCP baseline. - Only 2 projects have a project-local
crush.json(KNEL-AIMiddleware: 4 LSP + 36 MCP via wrappers; RCEO-PersonalAssistant: hooks only). - The highest-priority
.crush.jsonlayer is unused anywhere. - No project sets
modelorproviderin config.
Decision: no Crush config is shipped. The hooks layer was removed for harness portability. LSP/MCP remain project-local concerns.
10. Crush memory — a singleton, now a template
Only PFVCluster has operational memory (.crush/memory/operational.md). Its format — Identity → Tracking Systems (with READY/PARTIAL/BLOCKED status) → Tooling → Access chokepoints → Key commands → Mandatory rules → Credential TODOs — is strong and reusable.
Decision: the template ships .crush/memory/operational.md as a fill-in skeleton (optional, for projects using Crush).
11. KNEL-AIMiddleware wrapper ecosystem — a standardization opportunity (not in the template)
KNEL-AIMiddleware hand-maintains 38 near-identical wrapper scripts (mcp-*-wrapper.sh, lsp-*-wrapper.sh) for its MCP/LSP fleet. ~90% of each file is duplicated boilerplate (container-cleanup stanza, docker run -i --rm --name, env passthrough). Drift is already visible (default style, double-passed creds, one structurally-different LSP wrapper). There is no generator; they were hand-cloned by an agent over many sessions.
Recommendation (out of scope for the template): replace the 38 files with one parameterized launcher driven by a declarative servers.yaml manifest, plus a gen-wrappers.sh. The template's docker-run.sh + lib/common.sh show the direction; the same idea applies at fleet scale.
12. Workflow documents — WORKING.md / STATUS.md / JOURNAL.md
The remote personal genre contributes a discipline absent from infra: a task/state/document triad enforced by hooks:
- WORKING.md — the only task tracker (todos tool banned); commits blocked while
- [ ]remain; cleared before responding. - STATUS.md — agent-maintained dashboard humans read; staleness is a warning.
- JOURNAL.md — append-only ADR/pattern log; no today-entry is a warning.
CNW:markers — flag unresolved questions for the human; empty markers are a warning.
Decision: all four are in the template, and check-rules.sh enforces their freshness/completion.
Standardization scorecard
| Inconsistency | Was | Now |
|---|---|---|
| Shebangs | 3 variants | #!/usr/bin/env bash |
set flags |
4 policies | set -euo pipefail |
| Color/log boilerplate | copy-pasted ~10× | lib/common.sh |
| Task runner | 5 conventions | one Makefile |
| Git hook install | 3 mechanisms, 1 missing | one setup-hooks.sh (copy) |
| Git hook coverage | 3/18 projects | every project, two hooks |
| Crush hooks | 1/18 projects | not used (harness-agnostic; git hooks only) |
| Rules engine | 1 project (Go-specific) | generalized, project-agnostic |
| Crush memory | 1 project | skeleton in template (optional, Crush-only) |
| AGENTS.md structure | bespoke per project | canonical 10-section skeleton |
| 💘 commit footer | 2/18 projects | mandated in template (harness-agnostic) |
13. Global baseline prompt integration
After the initial extraction, the owner shared a draft "global baseline prompt"
(an Apple Note of operating observations gathered over weeks of working with
agents). It encodes principles that cut across every project and that the
template now reflects. The cleaned canonical version lives in
BASELINE-PROMPT.md; the project-level specialization is
in AGENTS.md. New artifacts and checks added:
New policy encoded
| Principle (baseline §) | How the template enforces it |
|---|---|
| Stop over-thinking; ask early (§1, §9) | questions-v1.md skeleton + AGENTS.md "Questions" section; required-files check fails if absent |
| Token efficiency / farm to tooling (§2) | make lint runs shellcheck in Docker; AGENTS.md "Working Style" forbids parsing huge code in context |
| Redmine = SoR for work; Discourse = SoR for docs (§3) | AGENTS.md "Systems of Record" section; make garden flags oversized non-Discourse .md |
| Git .md = stubs to Discourse (§3) | scripts/garden.sh reports oversized .md lacking a Discourse URL |
tea CLI for PRs; off-workstation → PR (§4) |
AGENTS.md "Git Workflow" policy |
| Shift-left CI/CD, lockstep local + hosted (§5) | AGENTS.md "CI/CD" section; make fast runs at pre-commit |
| Docker/k8s for everything; container naming (§6) | new container-naming rule in check-rules.sh (every compose service needs container_name); docker-compose.yml.example + scripts/up.sh / scripts/down.sh |
| STATUS.md = scratchpad, not SoR; has Inbox (§8) | STATUS.md reframed; Inbox section for mid-task interruptions ("don't pivot") |
| Questions file (§9) | questions-v1.md artifact + required-files check |
| Belt-and-suspenders enforcement (§10) | already present (git hooks + Crush hooks) — now documented as policy |
| Gardening loop (§11) | scripts/garden.sh + make garden target |
| Sub-agents as subcontractors (§12) | AGENTS.md "Working Style" |
| TDD + linters (§13) | AGENTS.md "TDD & Linting"; enforce-rules.sh TDD reminder (opt-in via PROJECT_SOURCE_SUFFIXES) |
New template artifacts
BASELINE-PROMPT.md— the cleaned canonical global prompt (lives in the meta root; projects inherit).questions-v1.md— git-tracked question log skeleton.docker-compose.yml.example— lifecycle template with project-prefix naming.scripts/up.sh,scripts/down.sh— compose lifecycle wrappers.scripts/garden.sh— doc-sprawl / Discourse-migration report.
New check-rules.sh checks
- Container naming (§6): every service in a
docker-compose*.y*mlmust declarecontainer_name:; failure otherwise. - Questions file required:
questions-v1.mdmust exist (required-files manifest).
New Makefile targets
make garden, make up, make down — standard verbs across every project.
What stayed project-level (not globalized)
sectestbed-/preprod-VM testing semantics — IAC-workstream-specific; left as AGENTS.md prose, not a mechanical check.- Redmine Gantt / dependency modeling — workflow-specific.
- Specific DNS/cloudron/SITER production details — out of scope.