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:
+36
-12
@@ -107,15 +107,17 @@ fi
|
||||
# 3. Required-files manifest — the files every project using this template owns.
|
||||
# ----------------------------------------------------------------------------
|
||||
$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:-}"
|
||||
for f in $REQUIRED_FILES; do
|
||||
if [ -f "$f" ]; then check "$f exists" "pass"; else check "$f MISSING" "fail"; fi
|
||||
done
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 4. Doc freshness — STATUS.md touched today; JOURNAL.md has today's entry.
|
||||
# Warnings (not failures): staleness is a signal, not a break.
|
||||
# 4. Doc freshness — STATUS.md touched today.
|
||||
# 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"
|
||||
if [ -f STATUS.md ]; then
|
||||
@@ -129,20 +131,42 @@ else
|
||||
check "STATUS.md MISSING" "fail"
|
||||
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)"
|
||||
if [ "$LAST_ENTRY" = "$TODAY" ]; then
|
||||
check "JOURNAL.md has an entry for today ($LAST_ENTRY)" "pass"
|
||||
else
|
||||
check "JOURNAL.md has no entry for today (last: $LAST_ENTRY) — add one" "warn"
|
||||
# ----------------------------------------------------------------------------
|
||||
# 4b. Discourse pointer-header policy (MANDATORY).
|
||||
# Discourse is the system of record for documentation. In-repo .md files are
|
||||
# stubs that point to a Discourse topic URL. Operational files exempt.
|
||||
# Override exemptions via PROJECT_DOC_EXEMPT (space-separated globs of
|
||||
# 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
|
||||
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
|
||||
check "docs/JOURNAL.md MISSING" "fail"
|
||||
check "$POINTER_MISSING .md file(s) missing Discourse pointer (see BASELINE-PROMPT.md §3)" "fail"
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 5. Git state — uncommitted changes are a warning (not a hard failure here;
|
||||
# the pre-push hook and audit-before-git crush hook harden this where it matters).
|
||||
# 5. Git state — uncommitted changes are a warning (the pre-push hook hardens
|
||||
# this where it matters).
|
||||
# ----------------------------------------------------------------------------
|
||||
$RULE_VERBOSE && log_step "Git state"
|
||||
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}"
|
||||
# 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"
|
||||
|
||||
|
||||
+4
-4
@@ -1,17 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# pre-commit — fast rule audit (< 1s typical).
|
||||
# Hot-path bypass: commits that ONLY touch STATUS.md / JOURNAL.md / WORKING.md
|
||||
# skip the audit so frequent status/journal commits stay frictionless.
|
||||
# Hot-path bypass: commits that ONLY touch STATUS.md / WORKING.md skip the
|
||||
# audit so frequent status/task commits stay frictionless.
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
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
|
||||
echo "hot-path files only (STATUS/JOURNAL/WORKING) — skipping rule audit"
|
||||
echo "hot-path files only (STATUS/WORKING) — skipping rule audit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -33,9 +33,10 @@ cat <<EOF
|
||||
|
||||
Git hooks installed. The following now run automatically:
|
||||
|
||||
pre-commit fast rule audit (shellcheck, image pinning, required files,
|
||||
doc freshness, WORKING.md completion, hygiene).
|
||||
Hot-path bypass for STATUS.md / JOURNAL.md / WORKING.md.
|
||||
pre-commit fast rule audit (shellcheck, image pinning, container naming,
|
||||
required files, doc freshness, Discourse pointers, WORKING.md
|
||||
completion, hygiene).
|
||||
Hot-path bypass for STATUS.md / WORKING.md.
|
||||
pre-push full rule audit (includes make test) + clean-working-tree gate.
|
||||
|
||||
Bypass either with \`git commit --no-verify\` / \`git push --no-verify\`
|
||||
|
||||
Reference in New Issue
Block a user