Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Structured planning workflow that uses files to track tasks, decisions, and project progress.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/attest-plan.sh
1#!/bin/sh2# planning-with-files: lock the current task_plan.md content with a SHA-256 attestation.3#4# Use after you finalise (or intentionally edit) a plan. The hooks then refuse5# to inject plan content into the model context if the file diverges from the6# attested hash, surfacing a "[PLAN TAMPERED]" warning instead.7#8# Resolution:9# 1. $PLAN_ID env var → ./.planning/$PLAN_ID/10# 2. ./.planning/.active_plan11# 3. Newest ./.planning/<dir>/ by mtime12# 4. Legacy ./task_plan.md at project root13#14# Usage:15# sh scripts/attest-plan.sh # attest the active plan16# sh scripts/attest-plan.sh --show # print the stored hash17# sh scripts/attest-plan.sh --clear # remove the attestation (re-open the plan)1819set -u2021SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"22RESOLVER="${SCRIPT_DIR}/resolve-plan-dir.sh"2324resolve_plan_file() {25plan_dir=""26if [ -f "${RESOLVER}" ]; then27plan_dir="$(sh "${RESOLVER}" 2>/dev/null)"28fi29if [ -n "${plan_dir}" ] && [ -f "${plan_dir}/task_plan.md" ]; then30printf "%s\n" "${plan_dir}/task_plan.md"31return 032fi33if [ -f "./task_plan.md" ]; then34printf "%s\n" "./task_plan.md"35return 036fi37return 138}3940attestation_path_for() {41plan_file="$1"42plan_dir="$(dirname "${plan_file}")"43if [ "${plan_dir}" = "." ]; then44# Legacy mode: store at project root.45printf "%s\n" "./.plan-attestation"46else47printf "%s\n" "${plan_dir}/.attestation"48fi49}5051compute_hash() {52target="$1"53if command -v sha256sum >/dev/null 2>&1; then54sha256sum "${target}" | awk '{print $1}'55elif command -v shasum >/dev/null 2>&1; then56shasum -a 256 "${target}" | awk '{print $1}'57else58printf "ERROR: no sha256 utility available\n" >&259return 160fi61}6263mode="attest"64case "${1:-}" in65--show) mode="show" ;;66--clear) mode="clear" ;;67"") mode="attest" ;;68*)69printf "Usage: %s [--show|--clear]\n" "$0" >&270exit 271;;72esac7374plan_file="$(resolve_plan_file)" || {75printf "[plan-attest] No task_plan.md found. Create a plan first.\n" >&276exit 177}7879attestation_file="$(attestation_path_for "${plan_file}")"8081case "${mode}" in82show)83if [ -f "${attestation_file}" ]; then84printf "Plan: %s\n" "${plan_file}"85printf "Attestation: %s\n" "${attestation_file}"86printf "SHA-256: %s\n" "$(cat "${attestation_file}")"87else88printf "[plan-attest] No attestation set for %s.\n" "${plan_file}"89exit 190fi91;;92clear)93if [ -f "${attestation_file}" ]; then94rm -f "${attestation_file}"95printf "[plan-attest] Cleared attestation for %s.\n" "${plan_file}"96else97printf "[plan-attest] No attestation to clear.\n"98fi99;;100attest)101hash_val="$(compute_hash "${plan_file}")" || exit 1102printf "%s\n" "${hash_val}" > "${attestation_file}"103short_hash="$(printf "%s" "${hash_val}" | cut -c1-12)"104printf "[plan-attest] Locked %s\n" "${plan_file}"105printf "[plan-attest] SHA-256: %s... (stored in %s)\n" "${short_hash}" "${attestation_file}"106printf "[plan-attest] Hooks will block injection if the file is modified without re-running this command.\n"107;;108esac109110exit 0111