mirror of
https://github.com/dtzp555-max/memory-continuity.git
synced 2026-07-22 21:45:06 +00:00
feat: add verify.sh — two-layer install verification
- Layer 1: checks all required skill files exist and skill.json is valid JSON - Layer 2: runs 4 doctor unit tests (missing file, placeholder content, high-stakes content, unsurfaced results) to verify the doctor tool behaves correctly - Layer 3: runs doctor against the live workspace - --sample flag prints a high-stakes CURRENT_STATE.md example vs placeholder text, explaining why content quality affects recovery Also updates README: fix install path, add verify.sh to quickstart and file tree, fix doctor --workspace example path.
This commit is contained in:
@@ -55,12 +55,21 @@ v1 direction.
|
||||
### Install
|
||||
|
||||
```bash
|
||||
cd ~/.openclaw/workspace/skills/
|
||||
cd ~/.openclaw/workspace/main/skills/
|
||||
git clone https://github.com/dtzp555-max/memory-continuity.git
|
||||
cd memory-continuity
|
||||
bash scripts/post-install.sh
|
||||
```
|
||||
|
||||
No npm install, no API keys, no external database.
|
||||
|
||||
> **Why `post-install.sh`?**
|
||||
> OpenClaw caches each session's skill list in a `skillsSnapshot`. If you
|
||||
> install this skill while the gateway is stopped (or restart the gateway
|
||||
> after cloning), existing sessions won't detect the new skill until their
|
||||
> snapshot is cleared. The post-install script handles this automatically.
|
||||
> New sessions created after install are unaffected.
|
||||
|
||||
### Test the current skill version
|
||||
|
||||
1. Start a multi-step task with your agent
|
||||
@@ -75,10 +84,26 @@ No npm install, no API keys, no external database.
|
||||
A good recovery should surface the current objective / step / next action,
|
||||
not generic small talk.
|
||||
|
||||
### Verify the install
|
||||
|
||||
```bash
|
||||
bash scripts/verify.sh
|
||||
```
|
||||
|
||||
This runs two layers of checks:
|
||||
- **Layer 1 (static):** Skill files, skill.json validity
|
||||
- **Layer 2 (doctor):** Verifies the doctor tool correctly identifies missing files, placeholder content, and non-empty unsurfaced results
|
||||
- **Layer 3 (live):** Runs doctor against your actual workspace
|
||||
|
||||
```bash
|
||||
# See what high-stakes content looks like vs placeholder text
|
||||
bash scripts/verify.sh --sample
|
||||
```
|
||||
|
||||
### Run the doctor
|
||||
|
||||
```bash
|
||||
python3 scripts/continuity_doctor.py --workspace ~/.openclaw/workspace
|
||||
python3 scripts/continuity_doctor.py --workspace ~/.openclaw/workspace/main
|
||||
```
|
||||
|
||||
## How the current skill version works
|
||||
@@ -158,16 +183,20 @@ Memory continuity is for:
|
||||
|
||||
```text
|
||||
memory-continuity/
|
||||
├── SKILL.md
|
||||
├── SKILL.md # Behavior contract / skill definition
|
||||
├── skill.json # Skill metadata for OpenClaw loader
|
||||
├── _meta.json # Workspace skill registry metadata
|
||||
├── README.md
|
||||
├── LICENSE
|
||||
├── plugin/
|
||||
│ └── lifecycle-prototype.ts # Phase 2 probe / not production yet
|
||||
│ └── lifecycle-prototype.ts # Phase 2 probe / not production yet
|
||||
├── references/
|
||||
│ ├── template.md
|
||||
│ ├── doctor-spec.md
|
||||
│ └── phase2-hook-validation.md
|
||||
└── scripts/
|
||||
├── post-install.sh # Clears stale skill snapshots
|
||||
├── verify.sh # Two-layer install verification
|
||||
└── continuity_doctor.py
|
||||
```
|
||||
|
||||
|
||||
Executable
+310
@@ -0,0 +1,310 @@
|
||||
#!/usr/bin/env bash
|
||||
# verify.sh — Verify memory-continuity skill is installed and working correctly
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/verify.sh [--workspace <path>] [--agent-id <id>]
|
||||
#
|
||||
# Options:
|
||||
# --workspace <path> Agent workspace to verify (default: ~/.openclaw/workspace/main)
|
||||
# --agent-id <id> Agent ID to check skill registration (default: main)
|
||||
# --sample Print a sample high-stakes CURRENT_STATE.md and exit
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 = all checks passed
|
||||
# 1 = warnings (skill works but something needs attention)
|
||||
# 2 = critical failure (skill is not functioning)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Defaults ────────────────────────────────────────────────────────────────
|
||||
WORKSPACE="${HOME}/.openclaw/workspace/main"
|
||||
AGENT_ID="main"
|
||||
SAMPLE_ONLY=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--workspace) WORKSPACE="$2"; shift 2 ;;
|
||||
--agent-id) AGENT_ID="$2"; shift 2 ;;
|
||||
--sample) SAMPLE_ONLY=true; shift ;;
|
||||
-h|--help)
|
||||
sed -n '2,12p' "$0" | sed 's/^# //'
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown option: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
WORKSPACE="${WORKSPACE/#\~/$HOME}"
|
||||
SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
|
||||
# ── Colors ──────────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
|
||||
|
||||
ok() { echo -e " ${GREEN}✓${RESET} $*"; }
|
||||
warn() { echo -e " ${YELLOW}⚠${RESET} $*"; }
|
||||
fail() { echo -e " ${RED}✗${RESET} $*"; }
|
||||
info() { echo -e " ${CYAN}ℹ${RESET} $*"; }
|
||||
|
||||
WARNINGS=0
|
||||
FAILURES=0
|
||||
|
||||
pass_warn() { WARNINGS=$((WARNINGS + 1)); warn "$@"; }
|
||||
pass_fail() { FAILURES=$((FAILURES + 1)); fail "$@"; }
|
||||
|
||||
# ── Sample mode ─────────────────────────────────────────────────────────────
|
||||
if $SAMPLE_ONLY; then
|
||||
cat <<'EOF'
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Sample HIGH-STAKES CURRENT_STATE.md
|
||||
(This is what makes an agent surface state instead of ignoring it)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
# Current State
|
||||
> Last updated: 2026-03-19T07:30:00+10:00
|
||||
|
||||
## Objective
|
||||
Deploy ocp v0.4.0 to production — mid-rollout, 30% traffic on new version
|
||||
|
||||
## Current Step
|
||||
Blue-green deployment in progress. New pod (ocp-v040) is healthy but
|
||||
/health endpoint shows elevated latency (340ms vs baseline 80ms).
|
||||
Root cause not yet found. Rollback is armed but not triggered.
|
||||
|
||||
## Key Decisions
|
||||
- Rollback threshold: p99 latency > 500ms for 5 consecutive minutes
|
||||
- Traffic split: 30% new / 70% old (Tao approved, 2026-03-19 07:15)
|
||||
- Do NOT fully cut over until latency root cause is confirmed
|
||||
|
||||
## Next Action
|
||||
Check ocp-v040 logs for slow Claude API calls:
|
||||
kubectl logs -l app=ocp-v040 --tail=200 | grep "duration_ms"
|
||||
|
||||
## Blockers
|
||||
None — waiting on log analysis results
|
||||
|
||||
## Unsurfaced Results
|
||||
None
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
WHY this works: concrete system at risk, named versions, specific
|
||||
numbers, clear next command, time-stamped decision. An agent reading
|
||||
this knows exactly what to do — it will ALWAYS surface this.
|
||||
|
||||
WHY placeholder content fails: "[One sentence about what you're doing]"
|
||||
reads as template noise. Agents treat it as "nothing important here."
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Header ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo -e "${BOLD}memory-continuity verify${RESET}"
|
||||
echo -e "Workspace : ${WORKSPACE}"
|
||||
echo -e "Agent ID : ${AGENT_ID}"
|
||||
echo -e "Skill dir : ${SKILL_DIR}"
|
||||
echo ""
|
||||
|
||||
# ============================================================================
|
||||
# LAYER 1: Static — skill files
|
||||
# ============================================================================
|
||||
echo -e "${BOLD}── Layer 1: Skill files ──────────────────────────────────────────${RESET}"
|
||||
|
||||
for f in SKILL.md skill.json scripts/continuity_doctor.py scripts/post-install.sh references/template.md; do
|
||||
if [[ -f "${SKILL_DIR}/${f}" ]]; then
|
||||
ok "${f}"
|
||||
else
|
||||
pass_fail "${f} is missing"
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate skill.json
|
||||
if command -v python3 &>/dev/null && [[ -f "${SKILL_DIR}/skill.json" ]]; then
|
||||
if python3 -c "import json,sys; json.load(open('${SKILL_DIR}/skill.json'))" 2>/dev/null; then
|
||||
ok "skill.json is valid JSON"
|
||||
else
|
||||
pass_fail "skill.json is not valid JSON"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================================================
|
||||
# LAYER 2: Static — doctor tool correctness
|
||||
# ============================================================================
|
||||
echo -e "${BOLD}── Layer 2: Doctor tool ──────────────────────────────────────────${RESET}"
|
||||
|
||||
TMPDIR_BASE="$(mktemp -d /tmp/mc-verify-XXXXXX)"
|
||||
trap 'rm -rf "$TMPDIR_BASE"' EXIT
|
||||
|
||||
DOCTOR="${SKILL_DIR}/scripts/continuity_doctor.py"
|
||||
|
||||
# Test 2a: MISSING file → should exit 2 (CRITICAL)
|
||||
WORKSPACE_MISSING="${TMPDIR_BASE}/missing"
|
||||
mkdir -p "${WORKSPACE_MISSING}/memory"
|
||||
OUT=$(python3 "$DOCTOR" --workspace "$WORKSPACE_MISSING" 2>&1) || true
|
||||
if echo "$OUT" | grep -q "CRITICAL"; then
|
||||
ok "Doctor correctly reports CRITICAL when CURRENT_STATE.md is missing"
|
||||
else
|
||||
pass_fail "Doctor failed to report CRITICAL for missing file"
|
||||
fi
|
||||
|
||||
# Test 2b: PLACEHOLDER content → should flag INFO/WARNING
|
||||
WORKSPACE_PLACEHOLDER="${TMPDIR_BASE}/placeholder"
|
||||
mkdir -p "${WORKSPACE_PLACEHOLDER}/memory"
|
||||
cat > "${WORKSPACE_PLACEHOLDER}/memory/CURRENT_STATE.md" << 'PLACEHOLDER'
|
||||
# Current State
|
||||
> Last updated: 2099-01-01T00:00:00Z
|
||||
|
||||
## Objective
|
||||
[One sentence: what are we trying to accomplish]
|
||||
|
||||
## Current Step
|
||||
[What step are we on]
|
||||
|
||||
## Key Decisions
|
||||
- [Decision placeholder]
|
||||
|
||||
## Next Action
|
||||
[Exactly what should happen next]
|
||||
|
||||
## Blockers
|
||||
None
|
||||
|
||||
## Unsurfaced Results
|
||||
None
|
||||
PLACEHOLDER
|
||||
OUT=$(python3 "$DOCTOR" --workspace "$WORKSPACE_PLACEHOLDER" 2>&1) || true
|
||||
if echo "$OUT" | grep -qE "INFO|WARNING"; then
|
||||
ok "Doctor correctly flags placeholder content (agents won't surface this)"
|
||||
else
|
||||
pass_warn "Doctor did not flag placeholder content — agents may ignore it"
|
||||
fi
|
||||
|
||||
# Test 2c: HIGH-STAKES content → should exit 0 (healthy)
|
||||
WORKSPACE_GOOD="${TMPDIR_BASE}/good"
|
||||
mkdir -p "${WORKSPACE_GOOD}/memory"
|
||||
cat > "${WORKSPACE_GOOD}/memory/CURRENT_STATE.md" << 'HIGHSTAKES'
|
||||
# Current State
|
||||
> Last updated: 2099-01-01T00:00:00Z
|
||||
|
||||
## Objective
|
||||
Deploy ocp v0.4.0 to production — mid-rollout, 30% traffic on new version
|
||||
|
||||
## Current Step
|
||||
Blue-green deployment in progress. New pod healthy but latency elevated (340ms vs 80ms baseline).
|
||||
Root cause investigation in progress. Rollback armed.
|
||||
|
||||
## Key Decisions
|
||||
- Rollback threshold: p99 latency > 500ms for 5 consecutive minutes
|
||||
- Traffic split: 30% new / 70% old (approved 2026-03-19 07:15)
|
||||
|
||||
## Next Action
|
||||
kubectl logs -l app=ocp-v040 --tail=200 | grep "duration_ms"
|
||||
|
||||
## Blockers
|
||||
None
|
||||
|
||||
## Unsurfaced Results
|
||||
None
|
||||
HIGHSTAKES
|
||||
EXIT_CODE=0
|
||||
OUT=$(python3 "$DOCTOR" --workspace "$WORKSPACE_GOOD" 2>&1) || EXIT_CODE=$?
|
||||
if [[ $EXIT_CODE -le 1 ]]; then
|
||||
ok "Doctor passes high-stakes content (agents will surface this on recovery)"
|
||||
else
|
||||
pass_fail "Doctor incorrectly rejects valid high-stakes content (exit $EXIT_CODE)"
|
||||
echo " Doctor output:"
|
||||
echo "$OUT" | sed 's/^/ /'
|
||||
fi
|
||||
|
||||
# Test 2d: UNSURFACED RESULTS → should flag WARNING
|
||||
WORKSPACE_UNSURFACED="${TMPDIR_BASE}/unsurfaced"
|
||||
mkdir -p "${WORKSPACE_UNSURFACED}/memory"
|
||||
cat > "${WORKSPACE_UNSURFACED}/memory/CURRENT_STATE.md" << 'UNSURFACED'
|
||||
# Current State
|
||||
> Last updated: 2099-01-01T00:00:00Z
|
||||
|
||||
## Objective
|
||||
Deploy ocp to production
|
||||
|
||||
## Current Step
|
||||
Codex worker returned deployment report, not yet shown to user.
|
||||
|
||||
## Key Decisions
|
||||
- Deploy window confirmed
|
||||
|
||||
## Next Action
|
||||
Show Codex result to Tao
|
||||
|
||||
## Blockers
|
||||
None
|
||||
|
||||
## Unsurfaced Results
|
||||
Codex finished: 3 files changed, tests passed, PR #42 created.
|
||||
UNSURFACED
|
||||
OUT=$(python3 "$DOCTOR" --workspace "$WORKSPACE_UNSURFACED" 2>&1) || true
|
||||
if echo "$OUT" | grep -q "WARNING"; then
|
||||
ok "Doctor correctly warns on non-empty Unsurfaced Results"
|
||||
else
|
||||
pass_warn "Doctor did not warn on non-empty Unsurfaced Results"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================================================
|
||||
# LAYER 3: Live workspace check
|
||||
# ============================================================================
|
||||
echo -e "${BOLD}── Layer 3: Your workspace (${WORKSPACE}) ──────────────────────────${RESET}"
|
||||
|
||||
STATE_FILE="${WORKSPACE}/memory/CURRENT_STATE.md"
|
||||
|
||||
if [[ ! -f "$STATE_FILE" ]]; then
|
||||
info "No CURRENT_STATE.md found — this is normal for a fresh install"
|
||||
info "Create one when you start a task: it's how the agent remembers across sessions"
|
||||
info "Run: bash scripts/verify.sh --sample to see what good content looks like"
|
||||
else
|
||||
EXIT_CODE=0
|
||||
python3 "$DOCTOR" --workspace "$WORKSPACE" 2>&1 | sed 's/^/ /' || EXIT_CODE=$?
|
||||
if [[ $EXIT_CODE -eq 0 ]]; then
|
||||
ok "Live workspace is healthy"
|
||||
elif [[ $EXIT_CODE -eq 1 ]]; then
|
||||
warn "Live workspace has warnings (see above)"
|
||||
WARNINGS=$((WARNINGS + 1))
|
||||
else
|
||||
fail "Live workspace has critical issues (see above)"
|
||||
FAILURES=$((FAILURES + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================================================
|
||||
# Summary
|
||||
# ============================================================================
|
||||
echo -e "${BOLD}── Result ────────────────────────────────────────────────────────${RESET}"
|
||||
|
||||
if [[ $FAILURES -gt 0 ]]; then
|
||||
echo -e " ${RED}${BOLD}FAILED${RESET} — ${FAILURES} critical issue(s), ${WARNINGS} warning(s)"
|
||||
echo ""
|
||||
echo " The skill is not functioning correctly. Check errors above."
|
||||
exit 2
|
||||
elif [[ $WARNINGS -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}${BOLD}WARNINGS${RESET} — ${WARNINGS} issue(s) found"
|
||||
echo ""
|
||||
echo " The skill works but needs attention. Review warnings above."
|
||||
exit 1
|
||||
else
|
||||
echo -e " ${GREEN}${BOLD}ALL CHECKS PASSED${RESET}"
|
||||
echo ""
|
||||
echo " memory-continuity is installed and working correctly."
|
||||
echo ""
|
||||
echo " Quick test:"
|
||||
echo " 1. Start a task with your agent"
|
||||
echo " 2. Send /new to reset the session"
|
||||
echo " 3. Send 'continue' or '刚才说到哪了'"
|
||||
echo " 4. The agent should surface your task state — not ask what you were doing"
|
||||
echo ""
|
||||
echo " Tip: run --sample to see what high-stakes content looks like."
|
||||
exit 0
|
||||
fi
|
||||
Reference in New Issue
Block a user