diff --git a/skills/continuity-guard/SKILL.md b/skills/continuity-guard/SKILL.md new file mode 100644 index 0000000..34edcb8 --- /dev/null +++ b/skills/continuity-guard/SKILL.md @@ -0,0 +1,92 @@ +--- +name: continuity-guard +description: Maintain short-term continuity and anti-silence discipline for OpenClaw agents using memory/CURRENT_STATE.md plus dual reporting rules. Use when creating/updating agent workspaces, after OpenClaw upgrades/restarts, when continuity seems broken, when a session may have lost context, or when you need to doctor/repair CURRENT_STATE coverage and reporting protocol drift across agents. +--- + +# Continuity Guard + +Use `memory/CURRENT_STATE.md` as a small overwrite-oriented workbench, not as a journal. + +## Core rules + +- Ensure every agent workspace has `memory/CURRENT_STATE.md` +- Keep `CURRENT_STATE.md` small + - main: target 25-40 lines, hard cap 50 + - other agents: target 15-25 lines, hard cap 30 +- Required sections: + - `In Flight` + - `Blocked / Waiting` + - `Recently Finished` + - `Next` + - `Reset Summary` +- Update only on state changes, not on a timer +- Remove stale items instead of endlessly appending + +## Dual reporting protocol + +### Worker → main +Execution agents must report to main at: +- accepted +- blocked +- milestone +- done +- model/environment abnormal + +Preferred reply format: +- `status` +- `summary` +- `evidence` +- `risk` +- `next` + +### main → Tao +Main must report to Tao at: +- task accepted / formally started +- worker dispatched +- blocked +- milestone reached +- task/phase completed + +Preferred Tao update format: +- who +- status +- output +- next + +Ordering rule: +- When a worker reports milestone/completion/blocker, first update `CURRENT_STATE.md`, then update Tao, then continue with review/commit/next dispatch. +- If no evidence point exists yet (sessionKey / commit / branch / PR / log), do not claim work has already started. + +## When to use the doctor +Run `scripts/continuity_doctor.py` when: +- OpenClaw was upgraded +- gateway restarted and continuity feels suspicious +- an agent seems to have lost short-term context +- you need to confirm `CURRENT_STATE.md` coverage across workspaces + +## How to use the doctor +From the main workspace: + +```bash +python3 skills/continuity-guard/scripts/continuity_doctor.py \ + --main-workspace /Users/taodeng/.openclaw/workspace/main \ + --agents-root /Users/taodeng/.openclaw/workspaces +``` + +The doctor checks: +- main `memory/CURRENT_STATE.md` exists +- all agent workspaces have `memory/CURRENT_STATE.md` +- required sections exist +- line-count caps are respected +- `AGENTS.md` still contains continuity + dual reporting rules + +## Repair strategy +If drift is found: +1. Restore/create missing `memory/CURRENT_STATE.md` +2. Restore continuity guidance in `AGENTS.md` +3. Re-run doctor +4. Only then investigate deeper behavioral failures + +## References +- For template and limits: read `references/template.md` +- For doctor semantics and PASS/WARN/FAIL meanings: read `references/doctor-spec.md` diff --git a/skills/continuity-guard/references/doctor-spec.md b/skills/continuity-guard/references/doctor-spec.md new file mode 100644 index 0000000..4a9d7b6 --- /dev/null +++ b/skills/continuity-guard/references/doctor-spec.md @@ -0,0 +1,34 @@ +# continuity doctor spec + +## PASS +The checked item exists and matches the required structure. + +## WARN +The item exists but is drifting: +- file too long +- required text partly missing +- structure present but not ideal + +## FAIL +The item is missing or materially broken: +- missing CURRENT_STATE.md +- missing required sections +- missing continuity rules in AGENTS.md + +## Minimal checks +1. `main/memory/CURRENT_STATE.md` exists +2. each agent workspace has `memory/CURRENT_STATE.md` +3. every `CURRENT_STATE.md` contains: + - `## In Flight` + - `## Blocked / Waiting` + - `## Recently Finished` + - `## Next` + - `## Reset Summary` +4. main `AGENTS.md` contains continuity guidance and dual reporting protocol markers +5. line-count caps are respected + +## Suggested actions on failure +- create missing files from template +- restore missing AGENTS continuity section +- trim oversized CURRENT_STATE files +- rerun doctor after repair diff --git a/skills/continuity-guard/references/template.md b/skills/continuity-guard/references/template.md new file mode 100644 index 0000000..229118c --- /dev/null +++ b/skills/continuity-guard/references/template.md @@ -0,0 +1,51 @@ +# CURRENT_STATE template + +## main agent (expanded) + +```md +# CURRENT_STATE + +_Last updated: YYYY-MM-DD HH:MM Australia/Brisbane_ + +## In Flight +- [status] task — owner — latest milestone + +## Blocked / Waiting +- item — blocker / waiting on + +## Recently Finished +- result — why it still matters now + +## Next +- next action + +## Reset Summary +- one short paragraph explaining what matters if a new session starts now +``` + +Capacity: +- target 25-40 lines +- hard cap 50 lines +- In Flight max 5 +- Blocked / Waiting max 5 +- Recently Finished max 3 +- Next max 5 + +## other agents (standard) +Use the same template, but keep it smaller. + +Capacity: +- target 15-25 lines +- hard cap 30 lines +- In Flight max 3 +- Blocked / Waiting max 3 +- Recently Finished max 2 +- Next max 3 + +## Allowed status values +- planned +- dispatched +- in_progress +- blocked +- reviewing +- done diff --git a/skills/continuity-guard/scripts/continuity_doctor.py b/skills/continuity-guard/scripts/continuity_doctor.py new file mode 100755 index 0000000..d3bbcc6 --- /dev/null +++ b/skills/continuity-guard/scripts/continuity_doctor.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +from pathlib import Path + +REQUIRED_SECTIONS = [ + '## In Flight', + '## Blocked / Waiting', + '## Recently Finished', + '## Next', + '## Reset Summary', +] + +AGENTS_MARKERS = [ + 'CURRENT_STATE.md - Your Short-Term Workbench', + 'Dual reporting protocol', + 'Execution agent → main', + 'main → Tao', +] + + +def result(level: str, msg: str) -> tuple[str, str]: + print(f'{level:<5} {msg}') + return level, msg + + +def line_count(path: Path) -> int: + try: + return len(path.read_text().splitlines()) + except Exception: + return 0 + + +def has_sections(path: Path) -> list[str]: + text = path.read_text() + missing = [s for s in REQUIRED_SECTIONS if s not in text] + return missing + + +def main() -> int: + ap = argparse.ArgumentParser(description='Check continuity/CURRENT_STATE coverage and drift.') + ap.add_argument('--main-workspace', required=True) + ap.add_argument('--agents-root', required=True) + args = ap.parse_args() + + main_ws = Path(args.main_workspace) + agents_root = Path(args.agents_root) + + failures = 0 + warns = 0 + + print('continuity doctor\n') + + # main AGENTS.md + agents_md = main_ws / 'AGENTS.md' + if not agents_md.exists(): + failures += 1 + result('FAIL', f'missing {agents_md}') + else: + text = agents_md.read_text() + missing = [m for m in AGENTS_MARKERS if m not in text] + if missing: + failures += 1 + result('FAIL', f'AGENTS continuity markers missing: {", ".join(missing)}') + else: + result('PASS', 'AGENTS continuity rules present') + + # main CURRENT_STATE + main_cs = main_ws / 'memory' / 'CURRENT_STATE.md' + if not main_cs.exists(): + failures += 1 + result('FAIL', 'main CURRENT_STATE missing') + else: + missing = has_sections(main_cs) + if missing: + failures += 1 + result('FAIL', f'main CURRENT_STATE missing sections: {", ".join(missing)}') + else: + result('PASS', 'main CURRENT_STATE sections present') + n = line_count(main_cs) + if n > 50: + warns += 1 + result('WARN', f'main CURRENT_STATE too long: {n} lines (cap 50)') + else: + result('PASS', f'main CURRENT_STATE length ok: {n} lines') + + # agent workspaces + checked = 0 + missing_files = [] + missing_sections = [] + oversize = [] + + if agents_root.exists(): + for ws in sorted([p for p in agents_root.iterdir() if p.is_dir()]): + checked += 1 + cs = ws / 'memory' / 'CURRENT_STATE.md' + if not cs.exists(): + missing_files.append(ws.name) + continue + missing = has_sections(cs) + if missing: + missing_sections.append((ws.name, missing)) + n = line_count(cs) + if n > 30: + oversize.append((ws.name, n)) + + if missing_files: + failures += 1 + result('FAIL', f'agent CURRENT_STATE missing: {", ".join(missing_files)}') + else: + result('PASS', f'agent CURRENT_STATE files present: {checked}/{checked}') + + if missing_sections: + failures += 1 + details = '; '.join(f'{name}: {", ".join(m)}' for name, m in missing_sections) + result('FAIL', f'agent CURRENT_STATE missing sections: {details}') + else: + result('PASS', 'agent CURRENT_STATE sections present') + + if oversize: + warns += 1 + details = '; '.join(f'{name}: {n} lines' for name, n in oversize) + result('WARN', f'agent CURRENT_STATE oversize: {details}') + else: + result('PASS', 'agent CURRENT_STATE length caps respected') + + print('\nSummary') + print(f'- failures: {failures}') + print(f'- warnings: {warns}') + + if failures: + print('\nSuggested actions:') + print('1. create/restore missing CURRENT_STATE files') + print('2. restore AGENTS continuity section if missing') + print('3. trim oversized CURRENT_STATE files') + print('4. rerun continuity doctor') + return 2 + return 0 + + +if __name__ == '__main__': + raise SystemExit(main())