Extract patterns from 18 projects across two machines (12 local infra + 6 remote personal/business via ssh survey). Ship a reusable Gitea template with AGENTS.md, 5 Crush PreToolUse hooks, git pre-commit/pre-push, a generalized rules engine, shared bash library, Makefile, lifecycle scripts, and gardening loop. Includes the canonical BASELINE-PROMPT.md (13 sections) and PATTERNS.md (standardization scorecard). The repo self-applies: it passes its own shellcheck (zero info-level), make fast, and all check-rules.sh checks. 💘 Generated with Crush Assisted-by: Crush via Crush <crush@charm.land>
10 KiB
— Agent Guidelines
Active agent: Crush running (). Permission mode: <yolo|normal>. Read
STATUS.md,.crush/memory/operational.md, andquestions-v1.mdfirst, every session. Governing baseline:BASELINE-PROMPT.md(parent project).
This file is the project-level policy. The hooks and scripts/check-rules.sh
enforce the mechanical rules below; this document states the policy and intent.
Inherit from the baseline; specialize here.
Quick Start
You are an AI agent working on this project. Your first actions, in order:
- Set up the environment:
make setup(installs git hooks — idempotent). - Read STATUS.md — current state, inbox, blockers, tactical notes.
- Read
.crush/memory/operational.md— access details, key IDs, gotchas. - Read questions-v1.md — open questions awaiting human input.
- Read docs/JOURNAL.md — decisions and patterns already established.
- Check current state:
git log --oneline -10andmake status.
Project Overview
<1–3 paragraphs: what this project is, the stack, and the hard constraints. Replace this bracketed text.>
Phase
We have exited the "move fast and loose" phase. This is production infrastructure. The bar is the bar. (See
BASELINE-PROMPT.md.)
<Adjust per project: is this in production? serving what? what's the blast radius?>
Repository Layout
<root>/
├── AGENTS.md ← THIS FILE — project policy
├── STATUS.md ← agent scratchpad (token-efficiency; NOT the system of record)
├── WORKING.md ← the ONLY task tracker (todos tool is banned)
├── questions-v1.md ← git-tracked questions for the human (version up per round)
├── crush.json ← Crush PreToolUse hooks (behavioral guardrails)
├── .crush/memory/ ← operational memory read each session
├── hooks/ ← Crush agent hooks (block-todos, enforce-*, audit-*, exit-protocol)
├── scripts/
│ ├── setup-hooks.sh ← install git hooks into .git/hooks/
│ ├── pre-commit ← fast rule audit (hot-path bypass for status/journal)
│ ├── pre-push ← full audit + clean-tree gate
│ ├── check-rules.sh ← the rule audit engine (pass/warn/fail accumulator)
│ ├── docker-run.sh ← canonical ephemeral-container wrapper
│ ├── up.sh / down.sh ← docker compose lifecycle wrappers
│ ├── garden.sh ← doc-sprawl / Discourse-migration report
│ └── lib/common.sh ← shared bash library (colors, log_*, docker_run, check)
├── docs/
│ └── JOURNAL.md ← append-only decision & pattern log
├── Makefile ← standard targets: setup/validate/lint/test/garden/up/down/status
├── docker-compose.yml.example ← lifecycle template (copy to docker-compose.yml)
└── .env.example ← copy to .env, fill in secrets
Systems of Record (do not duplicate)
- Redmine is the single system of record for ALL project work — tickets, schedules, Gantt, dependencies. Use the
redmine-clitool. Do not use Gitea issues. - Discourse is the single system of record for documentation. Use the
discourse-clitool. Do not author long-form docs in gitea. - Git-tracked
.mdfiles are stubs that point to the relevant Discourse URL. Operational files that must live next to code (AGENTS.md,STATUS.md,questions-v*.md,docs/JOURNAL.md) are the documented exceptions. STATUS.mdis a scratchpad for token efficiency, not a system of record.
Git Workflow
- Use the
teaCLI for pull requests. - Work smart off master. Branches on the workstation are encouraged for moving fast, exploring, and avoiding stash churn.
- Once work leaves the workstation, it goes through a PR.
- Commit & push policy: ALWAYS commit and push automatically; NEVER wait to be asked. This overrides any default "never commit unless asked" behavior.
- Atomic commits — one logical change per commit.
- Commit after every logical unit of work; push immediately.
- Never leave uncommitted or unpushed changes at session end.
- If blocked: commit and push what IS done, then report the blocker.
- Conventional commit format:
Types:
<type>(<scope>): <subject — 50 chars max, imperative, no period> <body: WHAT changed, WHY, and the context> 💘 Generated with Crush Assisted-by: <AI-Model> via Crush <crush@charm.land>feat,fix,docs,refactor,test,chore,security. - Never interrupt current work when the human tosses new work mid-task. Log it in the Inbox section of
STATUS.md. If materially different, spin up a Redmine ticket.
Task Tracking
- WORKING.md is the ONLY task tracker. The
todostool is banned by hook. - Only mark
[x]after the work is verified complete. - A commit is blocked (pre-commit + audit-before-git hook) while any task remains unchecked.
- Clear WORKING.md (to "all done") before responding to the user; the exit-protocol hook will not let you stop otherwise.
- The human decides when the work is done and when to deploy. Never declare "done" unilaterally.
Questions
- Capture questions for the human in a git-tracked
questions-v(N).mdfile. - The human reviews and edits it inline. Version up when a round of answers lands.
- Questions, answers, and the reasoning behind decisions are often more important than the code. Synthesize resolved Q&A into Discourse (decisions) and Redmine (work items).
Working Style
- Stop over-thinking. Get to code and output faster. Explore with code; gather ground truth. Do not burn tokens reasoning about things a quick command answers.
- Ask questions early via
questions-v(N).md. Don't ruminate or self-debate at length. - Farm work out to deterministic tooling: linters, LSPs, formatters, test runners. If Crush has an LSP wired up, use it; otherwise pull a Docker image and lint inside it. Do not parse huge code blocks in context.
- Use sub-agents as subcontractors for well-defined parallel deliverables, not as staff augmentation.
CI/CD
- The local workstation must be able to run the same CI/CD the hosted infrastructure runs. Maintain them in lockstep.
- Shift left: catch issues at
make fast(pre-commit) before push, before PR, before merge.
Conventions
- Docker/Kubernetes for everything — cluster of 1 or 100 is the same. Don't presume scale.
- All development work happens in containers — custom, off-the-shelf, or a mix.
docker pullfreely without asking. Usescripts/docker-run.sh <pinned-image>for one-offs. - Container naming: never use Docker's default. Always name with a project prefix (e.g.
<project>-<service>). Enforced bycheck-rules.sh. - Pin every Docker image — no
:latesttags (enforced). - Use Docker Compose with lifecycle scripts (
scripts/up.sh,scripts/down.sh) to bring services up/down. - Shell scripts use
#!/usr/bin/env bash+set -euo pipefailand must passshellcheckwith zero warnings, including info-level. - Shared helpers live in
scripts/lib/common.sh; source it rather than re-pasting boilerplate. - Names: lowercase, hyphen-separated.
- Secrets: NEVER commit secrets. Credentials come from env vars /
.env(gitignored). Use placeholders in.env.example. - IAC testing: test against the corresponding
sectestbed-VM (snapshot to base state).preprod-VMs for vendor-upgrade testing. Do not require AWX as a prerequisite.
Key Commands
make setup # install git hooks (run once after clone)
make fast # fast rule audit (pre-commit equivalent)
make validate # full audit (includes the test suite)
make lint # shellcheck via docker
make test # run the test suite (define per project)
make garden # doc-sprawl / Discourse-migration report
make up # bring up the docker-compose stack
make down # bring it down
make status # repo status snapshot
Status & Journal Maintenance
After any work session, you MUST:
- Update STATUS.md — reflect completed work, inbox, blockers. Update "Last updated". (check-rules.sh warns if stale.)
- Append to docs/JOURNAL.md — one section per change (what, why, pattern, challenges, commit hash). Never delete or reorder. (check-rules.sh warns if no today-entry.)
- Synthesize to Redmine/Discourse — status and journal are not the system of record; push decisions and durable docs there.
- Grep for stale paths after any rename/restructure:
grep -rn 'old/path'and fix in the same commit. - Run
make gardenperiodically — migrate oversized.mdto Discourse, leaving stubs.
Enforcement Model (belt and suspenders)
Policy is enforced in two complementary layers:
- Git hooks (
.git/hooks/, installed fromscripts/bymake setup) — mechanical checks at commit/push: shellcheck, image pinning, container naming, required files, doc freshness, WORKING.md completion, hygiene, full test suite on push. - Crush hooks (
hooks/, wired incrush.json) — behavioral guardrails at agent-tool-call time: ban the todos tool, block banned commands and host language tools, block edits to banned file types, run the fast audit before any commit/push, enforce the exit protocol.
Bypass with --no-verify in genuine emergencies only.
TDD & Linting
- Red/green TDD for all code. Write the failing test first.
- Linters on all code, as early as possible. Let deterministic tools find the issues.
DO
- Read STATUS.md, questions file, operational memory, and JOURNAL.md BEFORE starting work.
- Write a failing test first (TDD).
- Read files before editing. Use exact text matching.
- Run
make validatebefore committing. - Use sub-agents to parallelize scoped work.
- Log interruptions to the STATUS.md Inbox.
DO NOT
- Wait to be asked before committing/pushing.
- Batch unrelated changes into one commit.
- Edit files you haven't read.
- Install language toolchains on the host.
- Use
:latestimage tags or Docker's default container naming. - Author long-form docs in gitea — use Discourse.
- Commit secrets.
- Run destructive git operations without explicit instruction.
- Declare the work "done" — the human decides that.
- Pivot to new mid-task requests — log them in the Inbox.
Last Updated: TEMPLATE-REPLACE-ME