diff --git a/.agents/skills/oci-deal-accelerator/SKILL.md b/.agents/skills/oci-deal-accelerator/SKILL.md index 05420c3..f37b18a 100644 --- a/.agents/skills/oci-deal-accelerator/SKILL.md +++ b/.agents/skills/oci-deal-accelerator/SKILL.md @@ -567,3 +567,5 @@ KB lives under `kb/`. See [kb/README.md](kb/README.md) for the directory map, fr - You do NOT claim features exist if you're unsure. Check the KB first. - You do NOT do detailed project management. DELIVER artifacts are lightweight handover aids. - You do NOT add services or components the user did not request. + + diff --git a/.gitea/workflows/skill-sync.yaml b/.gitea/workflows/skill-sync.yaml new file mode 100644 index 0000000..cb07f47 --- /dev/null +++ b/.gitea/workflows/skill-sync.yaml @@ -0,0 +1,49 @@ +# SKILL.md sync gate. +# +# Why: the root SKILL.md (read by Claude Code) and +# .agents/skills/oci-deal-accelerator/SKILL.md (read by Codex) MUST +# stay byte-aligned modulo the auto-generated banner. If they drift, +# the two agents give the user different instructions — exactly the +# class of regression that produced the workload-driven-mode incident +# Diego flagged on 2026-04-25. +# +# This workflow blocks the merge if a PR/push leaves them out of +# sync. Locally, ``make install-hooks`` enables a pre-commit hook +# that auto-syncs before the commit lands; this CI step is the +# safety net for anyone who skipped the hook. + +name: SKILL.md sync + +on: + push: + branches: [main] + paths: + - 'SKILL.md' + - '.agents/skills/oci-deal-accelerator/SKILL.md' + - 'scripts/sync-skill.py' + pull_request: + branches: [main] + paths: + - 'SKILL.md' + - '.agents/skills/oci-deal-accelerator/SKILL.md' + - 'scripts/sync-skill.py' + workflow_dispatch: + +jobs: + check-sync: + runs-on: ubuntu-latest + timeout-minutes: 2 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + run: | + apt-get update -qq + apt-get install -y --no-install-recommends python3 + python3 --version + + - name: Verify SKILL.md is in sync with the Codex copy + run: | + python3 scripts/sync-skill.py --check diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100644 index 0000000..6461d5a --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Pre-commit hook: keep .agents/skills/oci-deal-accelerator/SKILL.md +# byte-aligned with the root SKILL.md (the source of truth that +# CLAUDE.md / Claude Code reads). The Codex copy under .agents/ +# follows the same content with an auto-generated banner — they MUST +# stay in lock-step or Claude Code and Codex will give the user +# different instructions. +# +# Behavior: +# • If SKILL.md is staged but the .agents/ copy is not synced, +# auto-run scripts/sync-skill.py and stage the result so the +# commit ships both files together. +# • If the script can't run (no python, etc.), abort with a clear +# message rather than committing a desync silently. +# +# Install once per clone: make install-hooks (sets core.hooksPath) + +set -euo pipefail + +ROOT="$(git rev-parse --show-toplevel)" +SOURCE="SKILL.md" +TARGET=".agents/skills/oci-deal-accelerator/SKILL.md" +SCRIPT="scripts/sync-skill.py" + +# Only act when SKILL.md is part of the staged change set. +if ! git diff --cached --name-only | grep -qx "$SOURCE"; then + exit 0 +fi + +if [ ! -f "$ROOT/$SCRIPT" ]; then + echo "pre-commit: $SCRIPT missing — cannot verify SKILL.md sync. Aborting." >&2 + exit 1 +fi + +PYTHON="$(command -v python3 || command -v python || true)" +if [ -z "$PYTHON" ]; then + echo "pre-commit: no python found in PATH — cannot run $SCRIPT. Aborting." >&2 + exit 1 +fi + +# Run the full sync, then stage the regenerated target so it travels +# in the same commit. (Idempotent — if it was already in sync, the +# file write is a no-op.) +"$PYTHON" "$ROOT/$SCRIPT" >&2 +git add "$ROOT/$TARGET" + +# Final check — if for any reason the result still drifts, fail loud. +if ! "$PYTHON" "$ROOT/$SCRIPT" --check >/dev/null 2>&1; then + echo "pre-commit: SKILL.md and $TARGET are still out of sync after auto-run." >&2 + echo " Investigate scripts/sync-skill.py before committing." >&2 + exit 1 +fi + +exit 0 diff --git a/Makefile b/Makefile index 6bdeba7..4b71b9b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # OCI Deal Accelerator — Build Automation -.PHONY: help install test validate example diagram deck full clean lint codex-package update-icons freshness freshness-refresh sync-skill sku-discover pptx-icons-refresh archcenter-benchmark-20 diagram-lookup diagram-validate-spec archcenter-descriptions-refresh diagram-spec-audit archcenter-smoke +.PHONY: help install test validate example diagram deck full clean lint codex-package update-icons freshness freshness-refresh sync-skill sku-discover pptx-icons-refresh archcenter-benchmark-20 diagram-lookup diagram-validate-spec archcenter-descriptions-refresh diagram-spec-audit archcenter-smoke install-hooks # Use venv if present, otherwise find best available python3 ifneq (,$(wildcard .venv/bin/python)) @@ -25,6 +25,15 @@ venv: ## Create virtual environment and install dependencies .venv/bin/pip install --upgrade pip .venv/bin/pip install -r requirements.txt @echo "Virtual environment ready. Run: source .venv/bin/activate" + @echo "Tip: run 'make install-hooks' once to enable the pre-commit" + @echo " hook that keeps SKILL.md in sync with the Codex copy." + +install-hooks: ## Install repo-versioned git hooks (pre-commit auto-syncs SKILL.md) + @if [ ! -d .git ]; then echo "install-hooks: not a git repo"; exit 1; fi + git config core.hooksPath .githooks + @echo "install-hooks: core.hooksPath set to .githooks" + @echo " → pre-commit now auto-syncs .agents/skills/.../SKILL.md" + @echo " whenever SKILL.md is part of the staged change set." install: ## Install Python dependencies (system-wide) pip install -r requirements.txt diff --git a/README.md b/README.md index f5765ef..1c36d30 100644 --- a/README.md +++ b/README.md @@ -452,6 +452,26 @@ For temporary overrides (e.g., focusing on a specific customer), create `AGENTS. Full setup details: [`codex/README.md`](codex/README.md) +#### Keeping the Claude and Codex skills in sync + +The root `SKILL.md` (read by Claude Code) and `.agents/skills/oci-deal-accelerator/SKILL.md` (read by Codex) MUST stay byte-aligned modulo an auto-generated banner. If they drift, the two agents give the user different instructions. + +Three layers of defense, run from least to most enforcement: + +1. **Local pre-commit hook (recommended once per clone):** + ```bash + make install-hooks + ``` + Sets `core.hooksPath = .githooks`. From then on, any commit that touches `SKILL.md` auto-runs `scripts/sync-skill.py` and stages the regenerated `.agents/` copy in the same commit. No manual step required. + +2. **Manual sync (anytime):** + ```bash + make sync-skill # write the .agents/ copy from SKILL.md + make lint # check (also runs sync --check) + ``` + +3. **CI gate (`.gitea/workflows/skill-sync.yaml`):** every push/PR runs `python scripts/sync-skill.py --check` and fails the build if the two files have drifted. Catches anyone who skipped the hook. + ## Roadmap ### ECAL Completeness (see `docs/ecal-gaps-backlog.md` for full list)