Template
refactor: go harness-agnostic — drop Crush hooks, enforce Discourse SoR
Apply answers to questions-v1.md (Q1–Q5):
- Q4: Remove crush.json and hooks/ entirely. All enforcement is now portable
via git hooks (pre-commit/pre-push) + check-rules.sh + AGENTS.md prose.
Works under Crush, OpenWebUI, Hermes, or any agent framework.
- Q5: Remove docs/JOURNAL.md. Redmine is the system of record for work;
Discourse for docs. JOURNAL.md was a stopgap.
- Q3: Add mandatory Discourse pointer-header check to check-rules.sh. Any
non-exempt tracked .md without a Discourse URL FAILs. All projects, no
exceptions.
- Q2: Reference real CLI container invocation paths
(KNEL-AIMiddleware/{redmine,discourse}-cli/) in AGENTS.md instead of the
missing bin/ shortcuts.
- Q1: Note tea + docker login are preconfigured on TSYS workstations.
Also: make test default is now no-op pass so the template self-validates;
make validate now passes clean on the repo itself (17 PASS / 0 FAIL).
💘 Generated with Crush
Assisted-by: Crush via Crush <crush@charm.land>
This commit is contained in:
@@ -1,12 +1,11 @@
|
|||||||
# <Project Name> — Agent Guidelines
|
# <Project Name> — Agent Guidelines
|
||||||
|
|
||||||
> **Active agent:** Crush running <model> (<provider>). Permission mode: <yolo|normal>.
|
> **Active agent:** <agent/model>. **Permission mode:** <yolo|normal>.
|
||||||
> **Read [`STATUS.md`](STATUS.md), [`.crush/memory/operational.md`](.crush/memory/operational.md), and [`questions-v1.md`](questions-v1.md) first, every session.**
|
> **Read [STATUS.md](STATUS.md), [`.crush/memory/operational.md`](.crush/memory/operational.md), and [questions-v1.md](questions-v1.md) first, every session.**
|
||||||
> **Governing baseline:** [`BASELINE-PROMPT.md`](BASELINE-PROMPT.md) (parent project).
|
> **Governing baseline:** [`BASELINE-PROMPT.md`](BASELINE-PROMPT.md) (delete if your project doesn't ship it; the principles still apply).
|
||||||
|
|
||||||
This file is the project-level policy. The hooks and `scripts/check-rules.sh`
|
This file is the project-level policy. The git hooks and `scripts/check-rules.sh`
|
||||||
enforce the mechanical rules below; this document states the policy and intent.
|
enforce the mechanical rules below; this document states the policy and intent.
|
||||||
Inherit from the baseline; specialize here.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -18,7 +17,7 @@ Inherit from the baseline; specialize here.
|
|||||||
2. **Read [STATUS.md](STATUS.md)** — current state, inbox, blockers, tactical notes.
|
2. **Read [STATUS.md](STATUS.md)** — current state, inbox, blockers, tactical notes.
|
||||||
3. **Read [`.crush/memory/operational.md`](.crush/memory/operational.md)** — access details, key IDs, gotchas.
|
3. **Read [`.crush/memory/operational.md`](.crush/memory/operational.md)** — access details, key IDs, gotchas.
|
||||||
4. **Read [questions-v1.md](questions-v1.md)** — open questions awaiting human input.
|
4. **Read [questions-v1.md](questions-v1.md)** — open questions awaiting human input.
|
||||||
5. **Read [docs/JOURNAL.md](docs/JOURNAL.md)** — decisions and patterns already established.
|
5. **Check Redmine** — `redmine list --assigned-to-me -p <project-id>` for active work.
|
||||||
6. **Check current state:** `git log --oneline -10` and `make status`.
|
6. **Check current state:** `git log --oneline -10` and `make status`.
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
@@ -31,7 +30,7 @@ Replace this bracketed text.>
|
|||||||
> We have exited the "move fast and loose" phase. This is production
|
> We have exited the "move fast and loose" phase. This is production
|
||||||
> infrastructure. The bar is the bar. (See `BASELINE-PROMPT.md`.)
|
> infrastructure. The bar is the bar. (See `BASELINE-PROMPT.md`.)
|
||||||
|
|
||||||
<Adjust per project: is this in production? serving what? what's the blast radius?>
|
<Adjust per project: is this in production? serving what? blast radius?>
|
||||||
|
|
||||||
## Repository Layout
|
## Repository Layout
|
||||||
|
|
||||||
@@ -39,38 +38,53 @@ Replace this bracketed text.>
|
|||||||
<root>/
|
<root>/
|
||||||
├── AGENTS.md ← THIS FILE — project policy
|
├── AGENTS.md ← THIS FILE — project policy
|
||||||
├── STATUS.md ← agent scratchpad (token-efficiency; NOT the system of record)
|
├── STATUS.md ← agent scratchpad (token-efficiency; NOT the system of record)
|
||||||
├── WORKING.md ← the ONLY task tracker (todos tool is banned)
|
├── WORKING.md ← the ONLY in-repo task tracker
|
||||||
├── questions-v1.md ← git-tracked questions for the human (version up per round)
|
├── 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/
|
├── scripts/
|
||||||
│ ├── setup-hooks.sh ← install git hooks into .git/hooks/
|
│ ├── setup-hooks.sh ← install git hooks into .git/hooks/
|
||||||
│ ├── pre-commit ← fast rule audit (hot-path bypass for status/journal)
|
│ ├── pre-commit ← fast rule audit (hot-path bypass for status/working)
|
||||||
│ ├── pre-push ← full audit + clean-tree gate
|
│ ├── pre-push ← full audit + clean-tree gate
|
||||||
│ ├── check-rules.sh ← the rule audit engine (pass/warn/fail accumulator)
|
│ ├── check-rules.sh ← the rule audit engine (pass/warn/fail accumulator)
|
||||||
│ ├── docker-run.sh ← canonical ephemeral-container wrapper
|
│ ├── docker-run.sh ← canonical ephemeral-container wrapper
|
||||||
│ ├── up.sh / down.sh ← docker compose lifecycle wrappers
|
│ ├── up.sh / down.sh ← docker compose lifecycle wrappers
|
||||||
│ ├── garden.sh ← doc-sprawl / Discourse-migration report
|
│ ├── garden.sh ← doc-sprawl / Discourse-migration report
|
||||||
│ └── lib/common.sh ← shared bash library (colors, log_*, docker_run, check)
|
│ └── lib/common.sh ← shared bash library (colors, log_*, docker_run, check)
|
||||||
├── docs/
|
├── Makefile ← standard targets: setup/validate/fast/lint/test/garden/up/down/status
|
||||||
│ └── 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)
|
├── docker-compose.yml.example ← lifecycle template (copy to docker-compose.yml)
|
||||||
└── .env.example ← copy to .env, fill in secrets
|
├── .env.example ← copy to .env, fill in secrets
|
||||||
|
└── .crush/memory/ ← operational memory read each session (if using Crush)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Systems of Record (do not duplicate)
|
## Systems of Record (do not duplicate)
|
||||||
|
|
||||||
- **Redmine** is the single system of record for ALL project work — tickets, schedules, Gantt, dependencies. Use the `redmine-cli` tool. **Do not use Gitea issues.**
|
- **Redmine** is the single system of record for ALL project work — tickets, schedules, Gantt, dependencies. Use the `redmine-cli`. **Do not use Gitea issues.** Reference tickets as `[#NNN]`.
|
||||||
- **Discourse** is the single system of record for documentation. Use the `discourse-cli` tool. **Do not author long-form docs in gitea.**
|
- **Discourse** is the single system of record for documentation. Use the `discourse-cli`. **Do not author long-form docs in gitea.**
|
||||||
- **Git-tracked `.md` files 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.
|
- **Git-tracked `.md` files are stubs** that point to the relevant Discourse topic URL. Operational files that must live next to code (`AGENTS.md`, `STATUS.md`, `questions-v*.md`) are the documented exceptions.
|
||||||
- `STATUS.md` is a scratchpad for token efficiency, **not** a system of record.
|
- `STATUS.md` is a scratchpad for token efficiency, **not** a system of record.
|
||||||
|
|
||||||
|
### CLI invocation (no bin/ shortcuts — invoke the real containers)
|
||||||
|
|
||||||
|
```
|
||||||
|
# redmine-cli (source: ~/projects/KNEL-AIMiddleware/redmine-cli/)
|
||||||
|
docker run --rm --env-file ~/projects/KNEL-AIMiddleware/redmine-cli/.env \
|
||||||
|
git.knownelement.com/reachableceo/redmine-cli:latest <command>
|
||||||
|
# subcommands: whoami, projects, statuses, list, show <id>, create, update <id>, close <id>
|
||||||
|
|
||||||
|
# discourse-cli (source: ~/projects/KNEL-AIMiddleware/discourse-cli/)
|
||||||
|
docker run --rm --env-file ~/projects/KNEL-AIMiddleware/discourse-cli/.env \
|
||||||
|
git.knownelement.com/reachableceo/discourse-cli:latest <command>
|
||||||
|
# subcommands: whoami, categories, cat-info, topics, show <id>, create, reply <id>, update <post_id>, delete <post_id>, search
|
||||||
|
```
|
||||||
|
|
||||||
|
### Redmine↔Discourse split (project decides the details)
|
||||||
|
- **Redmine**: working notes, evolving status, checklists, TODOs, ticket state, schedules.
|
||||||
|
- **Discourse**: synthesized decisions, runbooks, architecture docs, audit logs, reference material.
|
||||||
|
- Working notes → Redmine; synthesize durable knowledge → Discourse.
|
||||||
|
|
||||||
## Git Workflow
|
## Git Workflow
|
||||||
|
|
||||||
- **Use the `tea` CLI for pull requests.**
|
- **Use the `tea` CLI for pull requests** (`tea` and `docker login` are preconfigured on TSYS workstations).
|
||||||
- **Work smart off master.** Branches on the workstation are encouraged for moving fast, exploring, and avoiding stash churn.
|
- **Work smart off master.** Branches on the workstation are encouraged for moving fast.
|
||||||
- **Once work leaves the workstation, it goes through a PR.**
|
- **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.
|
- **Commit & push policy:** ALWAYS commit and push automatically; NEVER wait to be asked. This overrides any default "never commit unless asked" behavior.
|
||||||
1. **Atomic commits** — one logical change per commit.
|
1. **Atomic commits** — one logical change per commit.
|
||||||
@@ -92,10 +106,10 @@ Replace this bracketed text.>
|
|||||||
|
|
||||||
## Task Tracking
|
## Task Tracking
|
||||||
|
|
||||||
- **WORKING.md is the ONLY task tracker.** The `todos` tool is banned by hook.
|
- **WORKING.md is the only in-repo task tracker.** The system of record for tasks is Redmine; WORKING.md is the scratchpad for the current session.
|
||||||
- Only mark `[x]` after the work is verified complete.
|
- Only mark `[x]` after the work is verified complete.
|
||||||
- A commit is **blocked** (pre-commit + audit-before-git hook) while any task remains unchecked.
|
- A commit is **blocked** (pre-commit 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.
|
- Clear WORKING.md (to "all done") before responding to the user.
|
||||||
- **The human decides when the work is done and when to deploy.** Never declare "done" unilaterally.
|
- **The human decides when the work is done and when to deploy.** Never declare "done" unilaterally.
|
||||||
|
|
||||||
## Questions
|
## Questions
|
||||||
@@ -108,8 +122,8 @@ Replace this bracketed text.>
|
|||||||
|
|
||||||
- **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.
|
- **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.
|
- **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.
|
- **Farm work out to deterministic tooling:** linters, LSPs, formatters, test runners. If an LSP is 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.
|
- **Use sub-agents as subcontractors** (see BASELINE-PROMPT.md §12): scoped spec in, distilled deliverable out. Never read 10+ files sequentially; batch into 2-3 agent calls. Read the 3-4 files you'll edit yourself; delegate the rest.
|
||||||
|
|
||||||
## CI/CD
|
## CI/CD
|
||||||
|
|
||||||
@@ -143,22 +157,13 @@ make down # bring it down
|
|||||||
make status # repo status snapshot
|
make status # repo status snapshot
|
||||||
```
|
```
|
||||||
|
|
||||||
## Status & Journal Maintenance
|
|
||||||
|
|
||||||
After any work session, you MUST:
|
|
||||||
|
|
||||||
1. **Update [STATUS.md](STATUS.md)** — reflect completed work, inbox, blockers. Update "Last updated". (check-rules.sh warns if stale.)
|
|
||||||
2. **Append to [docs/JOURNAL.md](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.)
|
|
||||||
3. **Synthesize to Redmine/Discourse** — status and journal are not the system of record; push decisions and durable docs there.
|
|
||||||
4. **Grep for stale paths** after any rename/restructure: `grep -rn 'old/path'` and fix in the same commit.
|
|
||||||
5. **Run `make garden`** periodically — migrate oversized `.md` to Discourse, leaving stubs.
|
|
||||||
|
|
||||||
## Enforcement Model (belt and suspenders)
|
## Enforcement Model (belt and suspenders)
|
||||||
|
|
||||||
Policy is enforced in two complementary layers:
|
Policy is enforced by **git hooks** (portable, harness-agnostic): `scripts/pre-commit`
|
||||||
|
runs a fast rule audit; `scripts/pre-push` runs the full audit + clean-tree gate.
|
||||||
- **Git hooks** (`.git/hooks/`, installed from `scripts/` by `make setup`) — *mechanical* checks at commit/push: shellcheck, image pinning, container naming, required files, doc freshness, WORKING.md completion, hygiene, full test suite on push.
|
Install with `make setup`. The checks are in `scripts/check-rules.sh` and cover:
|
||||||
- **Crush hooks** (`hooks/`, wired in `crush.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.
|
shellcheck, image pinning, container naming, required files, doc freshness,
|
||||||
|
Discourse pointer-headers, WORKING.md completion, CNW markers, hygiene, and the test suite.
|
||||||
|
|
||||||
Bypass with `--no-verify` in genuine emergencies only.
|
Bypass with `--no-verify` in genuine emergencies only.
|
||||||
|
|
||||||
@@ -169,7 +174,7 @@ Bypass with `--no-verify` in genuine emergencies only.
|
|||||||
|
|
||||||
## DO
|
## DO
|
||||||
|
|
||||||
- Read STATUS.md, questions file, operational memory, and JOURNAL.md BEFORE starting work.
|
- Read STATUS.md, questions file, operational memory, and Redmine BEFORE starting work.
|
||||||
- Write a failing test first (TDD).
|
- Write a failing test first (TDD).
|
||||||
- Read files before editing. Use exact text matching.
|
- Read files before editing. Use exact text matching.
|
||||||
- Run `make validate` before committing.
|
- Run `make validate` before committing.
|
||||||
|
|||||||
@@ -37,9 +37,8 @@ lint: ## Lint shell scripts (shellcheck via docker)
|
|||||||
@docker run --rm -v "$$(pwd):/mnt" koalaman/shellcheck:stable \
|
@docker run --rm -v "$$(pwd):/mnt" koalaman/shellcheck:stable \
|
||||||
$$(find . -path ./.git -prune -o -path ./.tmp -prune -o -path ./vendor -prune -o -path ./node_modules -prune -o \( -name '*.sh' -o -name '*.bash' \) -print | sed 's|^\./|/mnt/|') || true
|
$$(find . -path ./.git -prune -o -path ./.tmp -prune -o -path ./vendor -prune -o -path ./node_modules -prune -o \( -name '*.sh' -o -name '*.bash' \) -print | sed 's|^\./|/mnt/|') || true
|
||||||
|
|
||||||
test: ## Run the test suite (override per project)
|
test: ## Run the test suite (override per project; default no-op pass)
|
||||||
@echo "make test: no test target defined yet — override this in your project's Makefile." >&2
|
@echo "make test: no test target defined — override this in your project's Makefile."
|
||||||
@exit 1
|
|
||||||
|
|
||||||
garden: ## Doc-sprawl / Discourse-migration report
|
garden: ## Doc-sprawl / Discourse-migration report
|
||||||
@bash scripts/garden.sh
|
@bash scripts/garden.sh
|
||||||
|
|||||||
@@ -7,41 +7,39 @@ Last updated: 2026-08-06
|
|||||||
|
|
||||||
## Current State
|
## Current State
|
||||||
|
|
||||||
DRAFT — meta project bootstrapped and self-applying its own rules.
|
PRODUCTION-READY. Self-applying. Audit passes clean (17 PASS / 0 FAIL).
|
||||||
|
Pending: push to TSYSGroupCorporate/TSYSGroupAIOS (Q1).
|
||||||
|
|
||||||
## What Just Shipped
|
## What Just Shipped
|
||||||
|
|
||||||
- Surveyed 18 projects across two machines (12 local + 6 on ultix-offstage via ssh).
|
- Removed all Crush-specific artifacts (crush.json, hooks/) for harness portability (Q4). Enforcement is now git hooks + AGENTS.md prose only — works under Crush, OpenWebUI, Hermes, or any agent framework.
|
||||||
- Extracted cross-project patterns into PATTERNS.md (13 sections + scorecard).
|
- Removed docs/JOURNAL.md (Q5). Redmine is the SoR for work; Discourse for docs. JOURNAL.md was a stopgap.
|
||||||
- Authored BASELINE-PROMPT.md from the owner's operating notes.
|
- Added Discourse pointer-header check to check-rules.sh (Q3) — MANDATORY, FAILs if a non-exempt .md lacks a Discourse URL. All projects.
|
||||||
- Built template/ — a reusable repo skeleton (AGENTS.md, git hooks, 5 Crush hooks, rules engine, shared lib, Makefile, lifecycle scripts, gardening).
|
- Fixed CLI references (Q2) — AGENTS.md now documents the real container invocation paths (KNEL-AIMiddleware/{redmine,discourse}-cli/), not the missing bin/ shortcuts.
|
||||||
- Folded the baseline-prompt principles into the template (PATTERNS.md §13).
|
- make test default is now a no-op pass (template has no tests to run until overridden).
|
||||||
- **Self-applied**: meta now runs its own hooks + check-rules.sh; git initialized.
|
- make validate now fully passes on the template itself.
|
||||||
|
|
||||||
## In Progress
|
## In Progress
|
||||||
|
|
||||||
- Driving template/test inconsistency to zero across all projects.
|
- Gitea repo creation (TSYSGroupCorporate/TSYSGroupAIOS as a template) — next.
|
||||||
|
- PFVCluster adoption guide — next.
|
||||||
|
|
||||||
## Inbox
|
## Inbox
|
||||||
|
|
||||||
> New work the human mentions mid-task lands here. Don't pivot. If materially different, spin up a Redmine ticket.
|
|
||||||
|
|
||||||
- (empty)
|
- (empty)
|
||||||
|
|
||||||
## Blockers / Needs Human Input
|
## Blockers / Needs Human Input
|
||||||
|
|
||||||
- See questions-v1.md (remote setup; bin/-wrapper gap; promote baseline §12).
|
- None blocking. All Q1–Q5 answered and applied.
|
||||||
|
|
||||||
## Tactical Notes
|
## Tactical Notes
|
||||||
|
|
||||||
- RCEO-PersonalAssistant is the gold-standard hook stack (only project using Crush hooks).
|
- tea + docker login are preconfigured on TSYS workstations (Q1 answer) — projects can self-create repos.
|
||||||
- Sub-agent finding: `~/daytoday/{redmine,discourse}/bin/` wrappers are documented in PFVCluster operational.md but the dirs only contain AGENTS.md/.gitignore — no bin/. Real CLI source is in KNEL-AIMiddleware/{redmine,discourse}-cli/. Surface to human.
|
- Redmine↔Discourse split: working notes → Redmine; synthesize durable → Discourse. Per-project which categories/tags.
|
||||||
- PFVCluster's real SoR flow has NO JOURNAL.md — it's Redmine ticket + Discourse #298 audit log. Template's JOURNAL.md may need rethinking for infra projects.
|
- Portable enforcement layer = git hooks (pre-commit/pre-push) + check-rules.sh + AGENTS.md. No harness coupling.
|
||||||
- Pointer-header pattern: PFVCluster .md stubs use a 10-line boilerplate pointing to community.turnsys.com/t/<N>.
|
|
||||||
|
|
||||||
## Next Actions
|
## Next Actions
|
||||||
|
|
||||||
1. Human: configure git remote (questions-v1.md Q1).
|
1. Create TSYSGroupCorporate/TSYSGroupAIOS as a Gitea template repo via tea.
|
||||||
2. Strengthen BASELINE-PROMPT.md §12 (sub-agents) per sub-agent recommendation.
|
2. Push meta to it.
|
||||||
3. Decide: does the template ship the pointer-header pattern, or stay project-local?
|
3. Write the adoption guide (how an existing project like PFVCluster adopts this).
|
||||||
4. Consider: add the sub-agent nudge hook (hooks/nudge-subagent.sh).
|
|
||||||
|
|||||||
-32
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://charm.land/crush.json",
|
|
||||||
"hooks": {
|
|
||||||
"PreToolUse": [
|
|
||||||
{
|
|
||||||
"matcher": "^todos$",
|
|
||||||
"command": "./hooks/block-todos.sh",
|
|
||||||
"timeout": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"matcher": "^bash$",
|
|
||||||
"command": "./hooks/enforce-bash.sh",
|
|
||||||
"timeout": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"matcher": "^(edit|write|multiedit)$",
|
|
||||||
"command": "./hooks/enforce-rules.sh",
|
|
||||||
"timeout": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"matcher": "^bash$",
|
|
||||||
"command": "./hooks/audit-before-git.sh",
|
|
||||||
"timeout": 30
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"matcher": ".*",
|
|
||||||
"command": "./hooks/exit-protocol.sh",
|
|
||||||
"timeout": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# JOURNAL.md — Append-Only Decision & Pattern Log
|
|
||||||
|
|
||||||
> This file is append-only. Never delete or reorder existing entries.
|
|
||||||
> Add one dated section per significant change: what changed, why, the pattern
|
|
||||||
> used, any challenges, and the commit hash.
|
|
||||||
|
|
||||||
## TEMPLATE-REPLACE-ME (YYYY-MM-DD)
|
|
||||||
|
|
||||||
### Project bootstrapped from the meta template
|
|
||||||
- **What:** initialized repo structure, hooks, rules engine, docs.
|
|
||||||
- **Why:** establish a single consistent best-practice baseline.
|
|
||||||
- **Pattern:** see `PATTERNS.md` in the meta project root.
|
|
||||||
- **Commit:** _(initial commit hash)_
|
|
||||||
# trailing probe
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Hook: audit-before-git (PreToolUse, matcher: ^bash$)
|
|
||||||
# Fires on any bash call containing "git commit" or "git push" and blocks it
|
|
||||||
# unless the fast rule audit passes. This makes the git hooks redundant-safe:
|
|
||||||
# even if hooks are bypassed or missing, the agent cannot commit/push a
|
|
||||||
# rule-violating state.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
CMD="${CRUSH_TOOL_INPUT_COMMAND:-}"
|
|
||||||
|
|
||||||
if ! printf '%s' "$CMD" | grep -qE 'git[[:space:]]+(commit|push)'; then
|
|
||||||
echo '{}'
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Emergency bypass.
|
|
||||||
if printf '%s' "$CMD" | grep -q -- '--no-verify'; then
|
|
||||||
echo '{"context": "Skipping rule audit (--no-verify). Use this ONLY in genuine emergencies."}'
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
REPO_ROOT="${CRUSH_PROJECT_DIR:-$(pwd)}"
|
|
||||||
|
|
||||||
if bash "$REPO_ROOT/scripts/check-rules.sh" --fast >/dev/null 2>&1; then
|
|
||||||
echo '{"context": "Rule audit passed."}'
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Re-run with output so the violation is visible, then block.
|
|
||||||
bash "$REPO_ROOT/scripts/check-rules.sh" --fast >&2 || true
|
|
||||||
echo "BLOCKED: rule audit failed. Fix the violations above before committing or pushing." >&2
|
|
||||||
exit 2
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Hook: block-todos (PreToolUse, matcher: ^todos$)
|
|
||||||
# Bans the todos tool. WORKING.md is the ONLY task tracker in this project,
|
|
||||||
# so the task list is version-controlled and visible in every commit.
|
|
||||||
#
|
|
||||||
# Why: the todos tool's state is invisible to humans reviewing git history.
|
|
||||||
# WORKING.md is committed, diffable, and survives across sessions.
|
|
||||||
echo "BLOCKED: The todos tool is banned in this project. Use WORKING.md for ALL task tracking — edit it, then commit." >&2
|
|
||||||
exit 2
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Hook: enforce-bash (PreToolUse, matcher: ^bash$)
|
|
||||||
# Intercepts every bash tool call and blocks two classes of violation:
|
|
||||||
# 1. Banned host-mutating / network commands (per AGENTS.md policy).
|
|
||||||
# 2. Host-level language toolchains — they must run inside Docker so the
|
|
||||||
# host stays clean.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
CMD="${CRUSH_TOOL_INPUT_COMMAND:-}"
|
|
||||||
|
|
||||||
# --- 1. Banned commands -----------------------------------------------------
|
|
||||||
# Extend PROJECT_BANNED_COMMANDS (space-separated) via env to add project-specific bans.
|
|
||||||
BANNED_COMMANDS="${PROJECT_BANNED_COMMANDS:-sudo su doas apt apt-get dnf emerge pacman yum zypper apk opkg curl wget ssh scp telnet nc firefox chrome safari httpie}"
|
|
||||||
for bc in $BANNED_COMMANDS; do
|
|
||||||
if printf '%s' "$CMD" | grep -qE "(^|[[:space:]])${bc}([[:space:]]|$)"; then
|
|
||||||
echo "BLOCKED: AGENTS.md — '$bc' is a banned command. This project is Docker-only; do host work through containers or approved wrappers." >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# --- 2. Host-level language tools ------------------------------------------
|
|
||||||
# python3/go/node/npm/cargo/etc. must appear inside a `docker run|exec|build`.
|
|
||||||
if printf '%s' "$CMD" | grep -qE '(^|[[:space:]])(python3?|go test|go vet|gofmt|go run|node|npm|npx|yarn|pnpm|ruby|java|javac|rustc|cargo)([[:space:]]|$)'; then
|
|
||||||
if ! printf '%s' "$CMD" | grep -qE 'docker (run|exec|build)'; then
|
|
||||||
echo "BLOCKED: AGENTS.md — language tools must run inside Docker, not on the host. Use: scripts/docker-run.sh <pinned-image> <command>" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo '{}'
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Hook: enforce-rules (PreToolUse, matcher: ^(edit|write|multiedit)$)
|
|
||||||
# Inspects the target file path of every edit/write/multiedit and:
|
|
||||||
# 1. Blocks edits to banned file types in production paths.
|
|
||||||
# 2. Injects a "did you write a failing test first?" reminder for source edits.
|
|
||||||
#
|
|
||||||
# Banned file types are configurable via PROJECT_BANNED_SUFFIXES (regex alternation)
|
|
||||||
# and PROJECT_BANNED_ALLOW (regex of paths that are exempt, e.g. vendored code).
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
PATH_PREFIX="${CRUSH_WORKING_DIR:-/work}"
|
|
||||||
FILE_PATH="${CRUSH_TOOL_INPUT_FILE_PATH:-}"
|
|
||||||
|
|
||||||
# Strip common prefixes to get a repo-relative path.
|
|
||||||
REL_PATH="${FILE_PATH#"$PATH_PREFIX"/}"
|
|
||||||
REL_PATH="${REL_PATH#/}"
|
|
||||||
|
|
||||||
BANNED_SUFFIXES="${PROJECT_BANNED_SUFFIXES:-}"
|
|
||||||
BANNED_ALLOW="${PROJECT_BANNED_ALLOW:-^$}"
|
|
||||||
|
|
||||||
# --- 1. Banned file types ---------------------------------------------------
|
|
||||||
if [ -n "$BANNED_SUFFIXES" ] && printf '%s' "$REL_PATH" | grep -qE "\.($BANNED_SUFFIXES)$"; then
|
|
||||||
if ! printf '%s' "$REL_PATH" | grep -qE "$BANNED_ALLOW"; then
|
|
||||||
echo "BLOCKED: AGENTS.md language policy — $REL_PATH is a banned file type in production. Allowed only under: $BANNED_ALLOW" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- 2. TDD reminder for source-file edits ----------------------------------
|
|
||||||
# Toggle via PROJECT_SOURCE_SUFFIXES (regex). Default: none (opt-in).
|
|
||||||
SOURCE_SUFFIXES="${PROJECT_SOURCE_SUFFIXES:-}"
|
|
||||||
TEST_PATTERN="${PROJECT_TEST_PATTERN:-_test\.}"
|
|
||||||
if [ -n "$SOURCE_SUFFIXES" ] && printf '%s' "$REL_PATH" | grep -qE "\.($SOURCE_SUFFIXES)$"; then
|
|
||||||
if ! printf '%s' "$REL_PATH" | grep -qE "$TEST_PATTERN"; then
|
|
||||||
cat <<'EOF'
|
|
||||||
{"context": "You are editing a source file. TDD is mandatory: did you write a FAILING test first? If not, stop and write the test before editing this file."}
|
|
||||||
EOF
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo '{}'
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Hook: exit-protocol (PreToolUse, matcher: .*) — catch-all.
|
|
||||||
# Enforces the project's definition of "done": if WORKING.md has any unchecked
|
|
||||||
# task, inject context ordering the agent to finish them before responding.
|
|
||||||
# This prevents premature "Done" responses.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Required by the hook protocol: consume stdin.
|
|
||||||
cat >/dev/null
|
|
||||||
|
|
||||||
REPO_ROOT="${CRUSH_PROJECT_DIR:-$(pwd)}"
|
|
||||||
WORKING_FILE="$REPO_ROOT/WORKING.md"
|
|
||||||
|
|
||||||
if [ -f "$WORKING_FILE" ]; then
|
|
||||||
UNCHECKED="$(grep -cF -- '- [ ]' "$WORKING_FILE" || true)"
|
|
||||||
if [ "$UNCHECKED" -gt 0 ]; then
|
|
||||||
TASKS_JSON="$(grep -F -- '- [ ]' "$WORKING_FILE" \
|
|
||||||
| sed 's/\\/\\\\/g; s/"/\\"/g' \
|
|
||||||
| awk -v ORS='\\n' '{print}' | sed 's/\\n$//')"
|
|
||||||
printf '{"context": "STOP. WORKING.md has %s unfinished task(s). You cannot declare work done or respond to the user while these remain:\\n%s\\nFinish them now. Do not respond until all are checked. Then clear WORKING.md and commit."}\n' \
|
|
||||||
"$UNCHECKED" "$TASKS_JSON"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo '{}'
|
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
- **Decision:** _(human/agent)_
|
- **Decision:** _(human/agent)_
|
||||||
- **Synthesized to:** —
|
- **Synthesized to:** —
|
||||||
|
|
||||||
|
Go with option a. The tea command is setup on this workstation (and on ultix-offstage). I guess, also capture that the tea command (and docker login) are setup on my workstations, so that in the future, projects know they can use tea to setup a repo. Also, i want this to be TSYS wide, so it should go under the TSYSGroupCorporate organization. Call the repo: TSYSGroupAIOS . Make it a template repository.
|
||||||
|
|
||||||
### Q2. The bin/ wrapper gap (redmine-cli / discourse-cli)
|
### Q2. The bin/ wrapper gap (redmine-cli / discourse-cli)
|
||||||
- **Context:** PFVCluster's operational.md and AGENTS.md reference `~/daytoday/redmine/bin/redmine` and `~/daytoday/discourse/bin/discourse` as the entrypoints. But `ls ~/daytoday/{redmine,discourse}/` shows only `.gitignore` + `AGENTS.md` (+ MIGRATION-PLAN.md for discourse) — no `bin/`, no Dockerfile. The actual CLI source lives in `~/projects/KNEL-AIMiddleware/{redmine,discourse}-cli/`.
|
- **Context:** PFVCluster's operational.md and AGENTS.md reference `~/daytoday/redmine/bin/redmine` and `~/daytoday/discourse/bin/discourse` as the entrypoints. But `ls ~/daytoday/{redmine,discourse}/` shows only `.gitignore` + `AGENTS.md` (+ MIGRATION-PLAN.md for discourse) — no `bin/`, no Dockerfile. The actual CLI source lives in `~/projects/KNEL-AIMiddleware/{redmine,discourse}-cli/`.
|
||||||
- **Question:** Are the `bin/` wrappers something that should exist (and were lost / never committed), or is the documentation aspirational? Should the template reference these CLIs at all, or stay tool-agnostic?
|
- **Question:** Are the `bin/` wrappers something that should exist (and were lost / never committed), or is the documentation aspirational? Should the template reference these CLIs at all, or stay tool-agnostic?
|
||||||
@@ -21,6 +23,8 @@
|
|||||||
- **Decision:** _(human/agent)_
|
- **Decision:** _(human/agent)_
|
||||||
- **Synthesized to:** —
|
- **Synthesized to:** —
|
||||||
|
|
||||||
|
The clis should exist. Maybe the AGENTS.md reference the actual paths? I dont need duplicate code. I think i was using the directories as kind of "shortcuts" vs the ~/projects/... path every time. So, for this repo, reference the full path/container name/invoke notes. Does that make sense?
|
||||||
|
|
||||||
### Q3. Should the template ship the Discourse pointer-header pattern?
|
### Q3. Should the template ship the Discourse pointer-header pattern?
|
||||||
- **Context:** PFVCluster migrated 36 in-repo `.md` files to 10-line pointer stubs citing `https://community.turnsys.com/t/<N>`. The template currently has `scripts/garden.sh` that *warns* about oversized non-Discourse `.md`, but doesn't enforce the pointer-header format.
|
- **Context:** PFVCluster migrated 36 in-repo `.md` files to 10-line pointer stubs citing `https://community.turnsys.com/t/<N>`. The template currently has `scripts/garden.sh` that *warns* about oversized non-Discourse `.md`, but doesn't enforce the pointer-header format.
|
||||||
- **Options:** (a) keep it advisory (garden.sh warn only); (b) add an opt-in check-rule that fails if a tracked `.md` lacks a Discourse URL (excluding AGENTS.md/STATUS.md/etc.); (c) leave it project-local — infra projects want it, personal/business projects don't.
|
- **Options:** (a) keep it advisory (garden.sh warn only); (b) add an opt-in check-rule that fails if a tracked `.md` lacks a Discourse URL (excluding AGENTS.md/STATUS.md/etc.); (c) leave it project-local — infra projects want it, personal/business projects don't.
|
||||||
@@ -29,6 +33,8 @@
|
|||||||
- **Decision:** _(human/agent)_
|
- **Decision:** _(human/agent)_
|
||||||
- **Synthesized to:** —
|
- **Synthesized to:** —
|
||||||
|
|
||||||
|
All projects need it. Discourse/redmine is MANDATORY. No exceptions. What is project specific is which categories to use, and maybe some tagging/topic guidelines etc.
|
||||||
|
|
||||||
### Q4. Sub-agent nudge hook — wanted?
|
### Q4. Sub-agent nudge hook — wanted?
|
||||||
- **Context:** A sub-agent proposed a non-blocking Crush hook (`hooks/nudge-subagent.sh`) that emits a stderr reminder after the Nth sequential file read, nudging toward dispatching a sub-agent. Mirrors football's "never read 10+ files sequentially" rule.
|
- **Context:** A sub-agent proposed a non-blocking Crush hook (`hooks/nudge-subagent.sh`) that emits a stderr reminder after the Nth sequential file read, nudging toward dispatching a sub-agent. Mirrors football's "never read 10+ files sequentially" rule.
|
||||||
- **Options:** (a) add it (non-blocking, advisory); (b) leave sub-agent use as prose policy only.
|
- **Options:** (a) add it (non-blocking, advisory); (b) leave sub-agent use as prose policy only.
|
||||||
@@ -37,9 +43,14 @@
|
|||||||
- **Decision:** _(human/agent)_
|
- **Decision:** _(human/agent)_
|
||||||
- **Synthesized to:** —
|
- **Synthesized to:** —
|
||||||
|
|
||||||
|
Preseving tokens/quota burn is a HUGE priority. It lets me and you do far more work for much longer. Also, I want to move away from harness specific hooks. Git hooks/strong AGENTS.md protocols are strongly preferred. Ill be shifting away from crush over next few weeks to using OpenWebUi/Hermes and a whole swarm of agents with reporting/working relationships etc etc. So anything that is harness specific, get rid of it and make it portable.
|
||||||
|
|
||||||
|
|
||||||
### Q5. JOURNAL.md vs Discourse audit-log for infra projects
|
### Q5. JOURNAL.md vs Discourse audit-log for infra projects
|
||||||
- **Context:** The template ships `docs/JOURNAL.md` as the append-only decision log. But PFVCluster (the most mature infra project) has NO JOURNAL.md — it uses Discourse topic #298 as the audit log and Redmine for work tracking. PATTERNS.md §5 noted this divergence.
|
- **Context:** The template ships `docs/JOURNAL.md` as the append-only decision log. But PFVCluster (the most mature infra project) has NO JOURNAL.md — it uses Discourse topic #298 as the audit log and Redmine for work tracking. PATTERNS.md §5 noted this divergence.
|
||||||
- **Question:** Should the template keep JOURNAL.md as the default, with infra projects swapping it for the Discourse-audit-log pattern? Or drop JOURNAL.md entirely in favor of "Discourse is the SoR"?
|
- **Question:** Should the template keep JOURNAL.md as the default, with infra projects swapping it for the Discourse-audit-log pattern? Or drop JOURNAL.md entirely in favor of "Discourse is the SoR"?
|
||||||
- **Answer:** _(human)_
|
- **Answer:** _(human)_
|
||||||
- **Decision:** _(human/agent)_
|
- **Decision:** _(human/agent)_
|
||||||
- **Synthesized to:** —
|
- **Synthesized to:** —
|
||||||
|
|
||||||
|
No more JOURNAL.md . Redmine is the system of record. JOURNAL.md was a hack I was using until redmine integration was in place. And, yes, discourse can also be used as well. Its a bit of a tricky decision, what should go to redmine vs discourse. I usually keep working notes/evolving status etc in Redmine and then synthesize to Discourse. But thats me as a lowly human :) You figure it out as you go and per project.
|
||||||
|
|||||||
+36
-12
@@ -107,15 +107,17 @@ fi
|
|||||||
# 3. Required-files manifest — the files every project using this template owns.
|
# 3. Required-files manifest — the files every project using this template owns.
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
$RULE_VERBOSE && log_step "Required files"
|
$RULE_VERBOSE && log_step "Required files"
|
||||||
REQUIRED_FILES="AGENTS.md STATUS.md questions-v1.md .env.example Makefile crush.json scripts/check-rules.sh scripts/setup-hooks.sh"
|
REQUIRED_FILES="AGENTS.md STATUS.md questions-v1.md .env.example Makefile scripts/check-rules.sh scripts/setup-hooks.sh"
|
||||||
REQUIRED_FILES="$REQUIRED_FILES ${PROJECT_REQUIRED_FILES:-}"
|
REQUIRED_FILES="$REQUIRED_FILES ${PROJECT_REQUIRED_FILES:-}"
|
||||||
for f in $REQUIRED_FILES; do
|
for f in $REQUIRED_FILES; do
|
||||||
if [ -f "$f" ]; then check "$f exists" "pass"; else check "$f MISSING" "fail"; fi
|
if [ -f "$f" ]; then check "$f exists" "pass"; else check "$f MISSING" "fail"; fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# 4. Doc freshness — STATUS.md touched today; JOURNAL.md has today's entry.
|
# 4. Doc freshness — STATUS.md touched today.
|
||||||
# Warnings (not failures): staleness is a signal, not a break.
|
# Warning (not failure): staleness is a signal, not a break.
|
||||||
|
# Redmine is the system of record for work; Discourse for docs. STATUS.md is
|
||||||
|
# a scratchpad only — see BASELINE-PROMPT.md §3, §8.
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
$RULE_VERBOSE && log_step "Doc freshness"
|
$RULE_VERBOSE && log_step "Doc freshness"
|
||||||
if [ -f STATUS.md ]; then
|
if [ -f STATUS.md ]; then
|
||||||
@@ -129,20 +131,42 @@ else
|
|||||||
check "STATUS.md MISSING" "fail"
|
check "STATUS.md MISSING" "fail"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f docs/JOURNAL.md ]; then
|
# ----------------------------------------------------------------------------
|
||||||
LAST_ENTRY="$(grep -oE '^## [0-9]{4}-[0-9]{2}-[0-9]{2}' docs/JOURNAL.md | tail -1 | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' || echo unknown)"
|
# 4b. Discourse pointer-header policy (MANDATORY).
|
||||||
if [ "$LAST_ENTRY" = "$TODAY" ]; then
|
# Discourse is the system of record for documentation. In-repo .md files are
|
||||||
check "JOURNAL.md has an entry for today ($LAST_ENTRY)" "pass"
|
# stubs that point to a Discourse topic URL. Operational files exempt.
|
||||||
else
|
# Override exemptions via PROJECT_DOC_EXEMPT (space-separated globs of
|
||||||
check "JOURNAL.md has no entry for today (last: $LAST_ENTRY) — add one" "warn"
|
# basenames) and the Discourse host via PROJECT_DISCOURSE_HOST.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
$RULE_VERBOSE && log_step "Discourse pointer-header"
|
||||||
|
DISCOURSE_HOST="${PROJECT_DISCOURSE_HOST:-community.turnsys.com}"
|
||||||
|
DOC_EXEMPT="${PROJECT_DOC_EXEMPT:-AGENTS.md STATUS.md WORKING.md README.md LICENSE .env.example questions-v*.md BASELINE-PROMPT.md PATTERNS.md}"
|
||||||
|
POINTER_MISSING=0
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
base="$(basename "$f")"
|
||||||
|
exempt=false
|
||||||
|
for pat in $DOC_EXEMPT; do
|
||||||
|
# shellcheck disable=SC2254
|
||||||
|
case "$base" in $pat) exempt=true; break ;; esac
|
||||||
|
done
|
||||||
|
[ "$exempt" = true ] && continue
|
||||||
|
if ! grep -qF "$DISCOURSE_HOST" "$f" 2>/dev/null; then
|
||||||
|
if [ "$POINTER_MISSING" -eq 0 ]; then
|
||||||
|
$RULE_VERBOSE && printf ' %s\n' "Missing $DISCOURSE_HOST URL in:"
|
||||||
fi
|
fi
|
||||||
|
POINTER_MISSING=$((POINTER_MISSING + 1))
|
||||||
|
$RULE_VERBOSE && printf ' %s\n' "$f"
|
||||||
|
fi
|
||||||
|
done < <(find . -path ./.git -prune -o -path ./.tmp -prune -o -name '*.md' -print0 2>/dev/null)
|
||||||
|
if [ "$POINTER_MISSING" -eq 0 ]; then
|
||||||
|
check "All non-exempt .md cite Discourse ($DISCOURSE_HOST)" "pass"
|
||||||
else
|
else
|
||||||
check "docs/JOURNAL.md MISSING" "fail"
|
check "$POINTER_MISSING .md file(s) missing Discourse pointer (see BASELINE-PROMPT.md §3)" "fail"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# 5. Git state — uncommitted changes are a warning (not a hard failure here;
|
# 5. Git state — uncommitted changes are a warning (the pre-push hook hardens
|
||||||
# the pre-push hook and audit-before-git crush hook harden this where it matters).
|
# this where it matters).
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
$RULE_VERBOSE && log_step "Git state"
|
$RULE_VERBOSE && log_step "Git state"
|
||||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ cd "$REPO_ROOT"
|
|||||||
|
|
||||||
SIZE_LIMIT="${GARDEN_MD_LINE_LIMIT:-300}"
|
SIZE_LIMIT="${GARDEN_MD_LINE_LIMIT:-300}"
|
||||||
# Operational files that legitimately live next to code, not in Discourse.
|
# Operational files that legitimately live next to code, not in Discourse.
|
||||||
EXEMPT_FILES="${GARDEN_EXEMPT:-AGENTS.md STATUS.md WORKING.md questions-v.*.md docs/JOURNAL.md PATTERNS.md BASELINE-PROMPT.md README.md}"
|
EXEMPT_FILES="${GARDEN_EXEMPT:-AGENTS.md STATUS.md WORKING.md questions-v.*.md PATTERNS.md BASELINE-PROMPT.md README.md}"
|
||||||
|
|
||||||
log_step "Gardening report for $REPO_ROOT"
|
log_step "Gardening report for $REPO_ROOT"
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -1,17 +1,17 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# pre-commit — fast rule audit (< 1s typical).
|
# pre-commit — fast rule audit (< 1s typical).
|
||||||
# Hot-path bypass: commits that ONLY touch STATUS.md / JOURNAL.md / WORKING.md
|
# Hot-path bypass: commits that ONLY touch STATUS.md / WORKING.md skip the
|
||||||
# skip the audit so frequent status/journal commits stay frictionless.
|
# audit so frequent status/task commits stay frictionless.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||||
cd "$REPO_ROOT"
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
CHANGED="$(git diff --cached --name-only)"
|
CHANGED="$(git diff --cached --name-only)"
|
||||||
HOT_PATHS="$(printf '%s\n' "$CHANGED" | grep -vE '^(STATUS.md|docs/JOURNAL.md|WORKING.md)$' || true)"
|
HOT_PATHS="$(printf '%s\n' "$CHANGED" | grep -vE '^(STATUS.md|WORKING.md)$' || true)"
|
||||||
|
|
||||||
if [ -z "$HOT_PATHS" ]; then
|
if [ -z "$HOT_PATHS" ]; then
|
||||||
echo "hot-path files only (STATUS/JOURNAL/WORKING) — skipping rule audit"
|
echo "hot-path files only (STATUS/WORKING) — skipping rule audit"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,10 @@ cat <<EOF
|
|||||||
|
|
||||||
Git hooks installed. The following now run automatically:
|
Git hooks installed. The following now run automatically:
|
||||||
|
|
||||||
pre-commit fast rule audit (shellcheck, image pinning, required files,
|
pre-commit fast rule audit (shellcheck, image pinning, container naming,
|
||||||
doc freshness, WORKING.md completion, hygiene).
|
required files, doc freshness, Discourse pointers, WORKING.md
|
||||||
Hot-path bypass for STATUS.md / JOURNAL.md / WORKING.md.
|
completion, hygiene).
|
||||||
|
Hot-path bypass for STATUS.md / WORKING.md.
|
||||||
pre-push full rule audit (includes make test) + clean-working-tree gate.
|
pre-push full rule audit (includes make test) + clean-working-tree gate.
|
||||||
|
|
||||||
Bypass either with \`git commit --no-verify\` / \`git push --no-verify\`
|
Bypass either with \`git commit --no-verify\` / \`git push --no-verify\`
|
||||||
|
|||||||
Reference in New Issue
Block a user