# Continuity Plugin (MVP → generalized checkpoint) > 中文版:`README.zh-TW.md` This package extracts the current approved-plan continuity hard gate into a small installable, testable OpenClaw plugin. The package still preserves the current approved-plan behavior, but it now moves one step closer to a more general **engine + adapter** structure: - a host-agnostic continuity engine input/output contract - the existing `force-recall` parity adapter - a new `generic-preflight` adapter and manual runner for non-`force-recall` integration ## What this package currently provides - continuity config validation - dispatch receipt contract validation - receipt file writing - approved-plan continuity gate evaluation - prompt block generation for the continuity gate - a `force-recall` adapter that maps hook wrapper/planner output into continuity input - a `generic-preflight` adapter that accepts host-agnostic continuity input directly - a manual preflight runner for workspaces that do not use `force-recall` ## Install location Recommended location inside an OpenClaw workspace: ```text /plugins/continuity ``` Possible integration layouts now include both the original `force-recall` path and a more generic path: ```text / hooks/ force-recall/ handler.ts HOOK.md plugins/ continuity/ README.zh-TW.md README.md HOOK.md package.json examples/ src/ test/ scripts/ test_force_recall_long_task_preflight.mjs ``` ## Directory structure ```text plugins/continuity/ README.zh-TW.md README.md HOOK.md package.json examples/ approved-plan-receipt.example.json openclaw.continuity.example.json src/ index.mjs adapters/ force-recall.mjs generic-preflight.mjs config/ defaults.mjs schema.mjs continuity/ engine.mjs evaluator.mjs receipt-store.mjs receipt-validator.mjs types.md test/ continuity.config.test.mjs continuity.evaluator.test.mjs continuity.plugin.test.mjs continuity.receipt-store.test.mjs continuity.receipt-validator.test.mjs continuity.smoke.test.mjs ``` ## Public surface - `src/config/schema.mjs` - `src/config/defaults.mjs` - `src/continuity/engine.mjs` - `src/continuity/evaluator.mjs` - `src/continuity/receipt-validator.mjs` - `src/continuity/receipt-store.mjs` - `src/adapters/force-recall.mjs` - `src/adapters/generic-preflight.mjs` - `src/index.mjs` `src/index.mjs` currently re-exports: - `defaultConfig` - `cloneDefaultConfig()` - `validateContinuityConfig()` / `normalizeContinuityConfig()` - `normalizeContinuityEngineInput()` - `createContinuityEngineResult()` / `createContinuityEngineContract()` - `evaluateContinuity()` / `buildContinuityGateBlock()` - `validateReceipt()` / `isValidReceipt()` - `slugifyReceiptSegment()` / `buildReceiptFilename()` / `writeReceipt()` - `buildApprovedPlanContinuityInput()` - `createForceRecallContinuityAdapter()` / `runForceRecallContinuityAdapter()` - `buildGenericContinuityInput()` - `createGenericPreflightContinuityAdapter()` / `runGenericPreflightContinuityAdapter()` - `runManualContinuityPreflight()` ## Host-agnostic engine contract The generalized engine accepts a normalized continuity input with fields such as: - `planId` - `currentTask` - `taskState` - `nextDerivedAction` - `replyClosureState` - `dispatchReceipt` - `nextTaskKnown` - `sameApprovedPlan` - `taskBoundaryStop` - `highRiskStop` Generalized adapters return a common contract: - `input` - `result` - `evaluation` - `block` - `meta.adapterName` - `meta.hostAgnostic` See `src/continuity/types.md` for the concise contract notes. ## Example config Start from `examples/openclaw.continuity.example.json`: ```json { "enabled": true, "planMatchers": ["approved-plan"], "legalTerminalStates": [ "waiting_user", "blocked", "pending_verification" ], "receiptDir": "state/approved-plan-continuity", "requireRealDispatchReceipt": true, "allowReplyClosureWithoutDispatch": false, "debug": false, "adapter": { "forceRecall": { "enabled": true, "injectBlockLabel": "APPROVED_PLAN_CONTINUITY_GATE" }, "genericPreflight": { "enabled": true, "injectBlockLabel": "APPROVED_PLAN_CONTINUITY_GATE" } } } ``` Defaults are defined in `src/config/defaults.mjs`. ## Integration path A: `force-recall` The original MVP integration point remains `hooks/force-recall/handler.ts`. ```js import plugin from './plugins/continuity/src/index.mjs'; const out = plugin.runForceRecallContinuityAdapter({ config: plugin.defaultConfig, wrapperResult, autoChainPlanResult, }); if (out?.block) { context.bodyForAgent = `${out.block}\n${context.bodyForAgent}`; } ``` ## Integration path B: generic/manual preflight If your workspace does **not** use `force-recall`, you can still install and use the plugin by calling the generalized adapter or the manual runner directly. ### Generic preflight adapter ```js import plugin from './plugins/continuity/src/index.mjs'; const out = plugin.runGenericPreflightContinuityAdapter({ config: plugin.defaultConfig, source: { planId: 'approved-plan-1', currentTask: 'task-3', taskState: 'complete', nextTaskKnown: true, sameApprovedPlan: true, taskBoundaryStop: true, nextTaskId: 'task-4', nextDerivedAction: { type: 'message_subagent', task: 'continue' }, replyClosureState: 'completed', dispatchReceipt: null, }, }); ``` ### Manual runner ```js import plugin from './plugins/continuity/src/index.mjs'; const out = plugin.runManualContinuityPreflight({ config: plugin.defaultConfig, planId: 'approved-plan-1', currentTask: 'task-3', taskState: 'complete', nextDerivedAction: { type: 'message_subagent', task: 'continue' }, replyClosureState: 'waiting_user', }); ``` If `out.block` is non-empty, prepend it into the prompt/body seen by the agent. ## Receipt contract Minimum receipt shape: - `planId` - `currentTask` - `nextDerivedAction` - `dispatchedAt` - `dispatchRunId` - `childSessionKey` - `replyClosureState` To persist a receipt: ```js import { writeReceipt } from './src/index.mjs'; await writeReceipt({ receiptDir: 'state/approved-plan-continuity', receipt, }); ``` ## Smoke test / verification Required plugin verification: ```bash cd plugins/continuity npm test node test/continuity.smoke.test.mjs ``` If your workspace uses `force-recall`, also run: ```bash cd /path/to/workspace node scripts/test_force_recall_long_task_preflight.mjs node --check hooks/force-recall/handler.ts ``` ## Install and apply steps for another OpenClaw workspace 1. Copy `plugins/continuity` into your workspace. 2. Choose one integration path: - `force-recall`: load `runForceRecallContinuityAdapter(...)` - no `force-recall`: call `runGenericPreflightContinuityAdapter(...)` or `runManualContinuityPreflight(...)` 3. Adjust config as needed, especially: - `planMatchers` - `legalTerminalStates` - `receiptDir` - `adapter.forceRecall.injectBlockLabel` - `adapter.genericPreflight.injectBlockLabel` 4. If your dispatch flow creates child runs/sessions, persist a real receipt. 5. Run plugin tests and the relevant workspace smoke path. 6. Confirm the agent prompt contains the continuity gate block and that dry-run dispatch alone does not pass the gate. ## Current limitations - This is still centered on the approved-plan continuity hard gate, not a full general workflow engine. - The generalized engine contract is intentionally minimal and conservative. - `force-recall` remains the most battle-tested adapter. - The receipt store only writes files; it does not manage retention, cleanup, or indexing. - The receipt validator checks the minimum contract only; it does not deeply validate every `nextDerivedAction` subtype. ## Notes - Default legal terminal states are `waiting_user`, `blocked`, and `pending_verification` - The evaluator preserves current behavior, including `missing_dispatch_receipt` and `missing_auto_next_dispatch` - The new generic path makes the plugin more reusable even without the `force-recall` hook - `HOOK.md` describes the plugin/hook adapter contract boundary, not the full installation guide ## Chinese documentation See `README.zh-TW.md` for the Traditional Chinese version.