From 55de5c5c8bad440438d07cb9570a92cc91d1756e Mon Sep 17 00:00:00 2001 From: casjay Date: Thu, 3 Sep 2026 01:42:41 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Update=20project=20spec=20and=20?= =?UTF-8?q?documentation=20=F0=9F=93=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AI.md --- AI.md | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/AI.md b/AI.md index e972c0a..a8bab1c 100644 --- a/AI.md +++ b/AI.md @@ -30,6 +30,7 @@ This file defines the standards that procedure enforces. | 6 | README.md standard layout | | 7 | CI/CD workflows | | 8 | Verification & commit | +| 9 | Examples from real repos | --- @@ -695,3 +696,134 @@ gitcommit --dir "$(git rev-parse --show-toplevel)" all `git commit` / `git push` directly are forbidden. Never commit with a failing syntax gate. + +## Project Memory (.claude/memory/) + +Durable, repo-specific knowledge discovered during work on this image — a template +quirk, a base-image gotcha, a decision on why something deviates from the generated +default — belongs in `.claude/memory/`, not only in a commit message or chat. Committed +to the repo, not gitignored. One markdown file per topic, YAML frontmatter (`name`, +`description`, `type: project`), indexed by `.claude/memory/MEMORY.md`, read on demand. +Same credential-masking rule as everywhere else — never store secrets. `~/.claude/**` +(global) stays read-only, deployed only via `claudemgr/config`'s `install.sh`; +`.claude/memory/` here is read/write in this repo directly. + +--- + +# PART 9: EXAMPLES FROM REAL REPOS + +Real excerpts from live `casjaysdevdocker` repos, showing how the conventions look +in practice. Use these as reference patterns — do not copy them verbatim into other +repos; adapt names, paths, and versions. + +## 9.1 — App-install `05-custom.sh` (from `casjaysdevdocker/gitea`) + +App repos always own a non-stub `05-custom.sh` — it is where the application binary +is installed. The gitea repo (100 lines) shows the canonical version-resolution and +download pattern: + +```bash +# Set bash options +set -o pipefail +[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set env variables +exitCode=0 +apk add --no-cache ca-certificates 2>/dev/null || true +update-ca-certificates 2>/dev/null || true +GITEA_VERSION="${GITEA_VERSION:-latest}" +GITEA_BIN_FILE="/usr/local/bin/gitea" +ARCH="$(uname -m | tr '[:upper]' '[:lower]')" +case "$ARCH" in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; *) echo "$ARCH is not supported by this script" >&2 && exit 1 ;; esac +# Pinned fallback used when gitea.com is unreachable from the build host +ACT_RUNNER_FALLBACK_VERSION="${ACT_RUNNER_FALLBACK_VERSION:-v1.0.8}" +# Fetch latest version tag from the renamed repo — 30s connect timeout +ACT_VERSIONS="$(curl -q --connect-timeout 30 --max-time 45 -LSsf \ + 'https://gitea.com/api/v1/repos/gitea/runner/releases' \ + -H 'accept: application/json' 2>/dev/null | jq -r '.[].tag_name' | sort -Vr | head -n1)" +# Fall back to pinned version if API is unreachable +[ -z "$ACT_VERSIONS" ] && ACT_VERSIONS="$ACT_RUNNER_FALLBACK_VERSION" +if [ -z "$GITEA_VERSION" ] || [ "$GITEA_VERSION" = "latest" ]; then + _latest_url="$(curl -4sfL -o /dev/null -w '%{url_effective}' https://github.com/go-gitea/gitea/releases/latest 2>/dev/null)" + GITEA_VERSION="$(printf '%s\n' "$_latest_url" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')" +fi +GITEA_URL="https://github.com/go-gitea/gitea/releases/download/v${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-${ARCH}" +``` + +Patterns to note: + +- Version defaults to `latest` but resolves to a concrete number at build time via + the upstream API, with a pinned fallback for offline/rate-limited builds +- Arch mapping (`x86_64→amd64`, `aarch64→arm64`) with a hard error for anything else +- Bounded curl (`--connect-timeout`/`--max-time`), never open-ended +- Downloads land in `/usr/local/bin`, are chmodded, and verified before exit 0 + +## 9.2 — init.d service script config block (from `casjaysdevdocker/gitea` `08-gitea.sh`) + +One init.d script per service, generated by `gen-script` and then configured by +editing ONLY the variable block — the function bodies below it are template code. +The configured block from `08-gitea.sh`: + +```bash +SERVICE_NAME="gitea" +# set data directory +DATA_DIR="/data/gitea" +# set config directory +CONF_DIR="/config/gitea" +# set the containers etc directory +ETC_DIR="/etc/gitea" +# set the temp dir +TMP_DIR="/tmp/gitea" +# set scripts pid dir +RUN_DIR="/run/gitea" +# set log directory +LOG_DIR="/data/logs/gitea" +# Set the working dir +WORK_DIR="/data/gitea" +# port which service is listening on +SERVICE_PORT="80" +# gitea must run as git user, not root +RUNAS_USER="git" +# execute command as another user +SERVICE_USER="git" +# Set the service group +SERVICE_GROUP="git" +# execute command variables - keep single quotes variables will be expanded later +# command to execute +EXEC_CMD_BIN='gitea' +# command arguments +EXEC_CMD_ARGS='web ' +# command arguments +EXEC_CMD_ARGS+='--port $SERVICE_PORT --config $CONF_DIR/app.ini ' +``` + +Patterns to note: + +- Dir vars all derive from `$SERVICE_NAME` (`/data/{svc}`, `/config/{svc}`, + `/run/{svc}`, `/data/logs/{svc}`) +- `EXEC_CMD_BIN`/`EXEC_CMD_ARGS` stay single-quoted — template code expands them + later, after ports and paths are finalized +- Multi-word args are built up with `EXEC_CMD_ARGS+=`, one concern per line + +## 9.3 — Customizing behavior via `*_local()` hooks (from `08-gitea.sh`) + +Template functions (`__pre_execute`, `__update_conf_files`, …) each end by calling +an optional `*_local()` hook. Repo-specific behavior goes in the hook, never inside +the template function body: + +```bash +# function to run before executing +__pre_execute() { + local exitCode=0 + ... + # allow custom functions + if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi + return $exitCode +} +``` + +The stubs (`__pre_execute_local() { true; }` etc.) live near the bottom of the +script — replace a stub's body to customize; regeneration then only requires +re-applying the variable block and the non-stub hooks. Multi-service apps ship one +script per service with two-digit ordering (`05-dockerd.sh`, `08-gitea.sh`, +`zz-act_runner.sh` for run-last).