Files
reporting-governance-plugin/docs/plans/2026-04-24-continuity-plugin-mvp.md

37 KiB
Raw Blame History

Continuity Plugin MVP Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Extract the current approved-plan continuity hard-gate into an installable, configurable, testable OpenClaw plugin MVP with bilingual README guidance, example config, and smoke-test flow.

Architecture: Keep the MVP small and adapter-first. Move continuity logic out of the current hard-coded scripts into a plugin package with four clear seams: config schema, continuity evaluator, receipt validator/storage helper, and hook adapter. Preserve current behavior first, then wrap it in plugin packaging, plugin docs, and plugin-level tests so the same continuity gate can be installed and configured without patching core workflow logic.

Tech Stack: Node.js, ESM (.mjs/TypeScript where already present), file-backed JSON receipts, OpenClaw hook/plugin conventions, bilingual Markdown docs, script-level test runners.


Implementation Notes for the Engineer

  • Current behavior already exists in these files and should be treated as the extraction source of truth for MVP parity:
    • scripts/approved_plan_continuity_gate.mjs
    • scripts/approved_plan_dispatch_binding.mjs
    • scripts/test_approved_plan_continuity_gate.mjs
    • hooks/force-recall/handler.ts
    • docs/runbooks/approved-plan-continuity.md
    • state/approved-plan-continuity/README.md
  • The workspace currently has an empty top-level plugins/ directory, so the plan assumes creating a dedicated plugin package there instead of mixing plugin code back into scripts/.
  • Do not widen scope into a generalized workflow engine. MVP means: preserve todays continuity decision model, make it pluggable/configurable, document installation, and prove it with tests and a smoke path.
  • Prefer pure functions for evaluator/validator pieces so they can be tested without spawning hooks.
  • Treat current hard-gate scripts as compatibility fixtures during migration. Only remove or thin them after plugin parity is verified.

Proposed MVP Package Layout

plugins/continuity/
  README.md
  README.zh-TW.md
  package.json
  HOOK.md
  examples/
    openclaw.continuity.example.json
    approved-plan-receipt.example.json
  src/
    index.mjs
    config/
      schema.mjs
      defaults.mjs
    continuity/
      evaluator.mjs
      receipt-validator.mjs
      receipt-store.mjs
      types.md
    adapters/
      force-recall.mjs
      script-bridge.mjs
  test/
    continuity.evaluator.test.mjs
    continuity.receipt-validator.test.mjs
    continuity.plugin.test.mjs
    continuity.smoke.test.mjs

If the repos actual plugin loader requires a different manifest filename or entrypoint shape, adapt the filenames but keep the same responsibilities and test coverage.

Acceptance Target

The MVP is acceptable only when all of the following are true:

  1. Continuity rules are configurable through a plugin config schema instead of only hard-coded constants.
  2. The evaluator can be imported and tested as a standalone module.
  3. Receipt validation is separated from gate decision logic.
  4. A hook adapter can call the plugin and inject the same kind of hard-gate behavior now implemented in hooks/force-recall/handler.ts.
  5. The plugin ships with bilingual install/apply documentation.
  6. The repo contains example config and at least one repeatable smoke test command.
  7. Existing current-script behavior is either preserved through bridge wrappers or explicitly mapped in the README migration section.

Task 1: Capture current continuity behavior as extraction baseline

Files:

  • Review: scripts/approved_plan_continuity_gate.mjs
  • Review: scripts/approved_plan_dispatch_binding.mjs
  • Review: scripts/test_approved_plan_continuity_gate.mjs
  • Review: hooks/force-recall/handler.ts
  • Review: docs/runbooks/approved-plan-continuity.md

Step 1: Create a baseline notes section in the plan worklog

  • Write down the exact current responsibilities:
    • legal terminal states
    • minimum dispatch receipt fields
    • receipt filename convention
    • how force-recall currently invokes continuity
    • which behaviors are already covered by tests

Step 2: Verify nothing was guessed Run:

rg -n "waiting_user|blocked|pending_verification|dispatchReceipt|nextDerivedAction|approved_plan_continuity" \
  scripts/approved_plan_continuity_gate.mjs \
  scripts/approved_plan_dispatch_binding.mjs \
  scripts/test_approved_plan_continuity_gate.mjs \
  hooks/force-recall/handler.ts \
  docs/runbooks/approved-plan-continuity.md

Expected: matching lines confirm all baseline rules come from checked-in files

Step 3: Commit baseline notes

git add docs/plans/2026-04-24-continuity-plugin-mvp.md
git commit -m "docs: capture continuity plugin extraction baseline"

Task 1 Baseline Worklog (captured 2026-04-24)

Reviewed source-of-truth files

  • scripts/approved_plan_continuity_gate.mjs
  • scripts/approved_plan_dispatch_binding.mjs
  • scripts/test_approved_plan_continuity_gate.mjs
  • scripts/test_force_recall_long_task_preflight.mjs
  • hooks/force-recall/handler.ts
  • docs/runbooks/approved-plan-continuity.md

Current responsibilities baseline

  • scripts/approved_plan_continuity_gate.mjs

    • Reads JSON input from --input <path> and emits one JSON envelope to stdout.
    • Evaluates approved-plan continuity only when:
      • taskState === 'complete'
      • a next action is known via nextDerivedAction ?? derivedAction
      • no valid dispatchReceipt is present
      • replyClosureState is not one of the legal terminal states.
    • Hard-coded legal terminal states today are exactly:
      • waiting_user
      • blocked
      • pending_verification
    • Current failure output is:
      • ok: false
      • status: 'continuity_failure'
      • verdict: 'continuity_failure'
      • reason: 'missing_dispatch_receipt'
    • Current pass output is:
      • ok: true
      • status: 'pass'
      • verdict: 'pass'
    • Always stamps gate: 'approved_plan_continuity' in the response envelope.
    • Current receipt validation inside the gate is intentionally narrow: it only requires planId, currentTask, object-shaped nextDerivedAction, and dispatchedAt to treat dispatchReceipt as valid.
  • scripts/approved_plan_dispatch_binding.mjs

    • Reads JSON input from --input <path> and optional --receipt-dir override.
    • Default receipt dir is state/approved-plan-continuity resolved from process.cwd().
    • Builds a receipt from:
      • planId
      • currentTask
      • nextDerivedAction ?? derivedAction
      • dispatchedAt
      • dispatchRunId
      • childSessionKey
      • replyClosureState
    • Validates presence of all seven fields above before writing.
    • Adds filesystem-safety checks by slugifying planId and dispatchRunId; missing/unsafe values are reported as planId_filesystem_safe / dispatchRunId_filesystem_safe.
    • On success writes receipt-<planIdSafe>-<dispatchRunIdSafe>.json under the receipt dir and returns:
      • ok: true
      • status: 'receipt_written'
      • binding: 'approved_plan_dispatch'
      • receiptPath
      • receipt
    • On validation failure returns:
      • ok: false
      • status: 'missing_required_receipt_fields'
      • binding: 'approved_plan_dispatch'
      • missing: string[]
      • receiptPath: null
  • hooks/force-recall/handler.ts

    • Runs continuity as a hook-time adapter, not a pure module yet.
    • Continuity input is assembled by buildApprovedPlanContinuityInput(wrapperResult, autoChainPlanResult).
    • Hook mapping behavior today:
      • source next action = wrapperResult.nextDerivedAction ?? wrapperResult.derivedAction ?? plannerDerivedAction
      • plannerDerivedAction is synthesized from auto-chain planner output when derivedAction !== 'none'
      • if no next action exists, continuity gate is skipped (null)
      • replyClosureState defaults to:
        • wrapperResult.replyClosureState, else
        • 'waiting_user' when wrapperResult.handoff?.mode === 'button_path', else
        • 'completed'
      • dispatchReceipt is passed through from wrapperResult.dispatchReceipt ?? null
      • taskState defaults to wrapperResult.taskState ?? (plannerDerivedAction ? 'complete' : null)
    • The hook executes scripts/approved_plan_continuity_gate.mjs via JSON-script indirection, then renders a prompt block.

Minimal receipt contract baseline

  • Receipt fields documented/runbook + dispatch binding currently agree on the following MVP minimum shape:
    • planId
    • currentTask
    • nextDerivedAction
    • dispatchedAt
    • dispatchRunId
    • childSessionKey
    • replyClosureState
  • Important parity note: the gate currently enforces only a smaller subset for pass/fail (planId, currentTask, object nextDerivedAction, dispatchedAt), while dispatch binding enforces the full seven-field receipt contract before persisting.
  • Extraction must preserve this mismatch unless explicitly changed in a later task.

Receipt filename / storage convention baseline

  • Receipt directory default: state/approved-plan-continuity
  • Receipt filename pattern: receipt-<planIdSafe>-<dispatchRunIdSafe>.json
  • Safe segments are produced by lowercasing, trimming, replacing non [a-z0-9._-] runs with -, trimming edge dashes, and collapsing repeated dashes.

Hook block shape baseline

  • The continuity block currently injected by hooks/force-recall/handler.ts is:
[APPROVED_PLAN_CONTINUITY_GATE]
status=<status>
verdict=<verdict>
reason=<reason?>
- HARD_GATE: Do not close out this reply as normal completion.
- HARD_GATE: Route back to continuity failure until a real next dispatch receipt exists, unless closure state is waiting_user, blocked, or pending_verification.
[/APPROVED_PLAN_CONTINUITY_GATE]
  • reason= is only included when present.
  • The two HARD_GATE lines are only added when result.ok === false.
  • The block is omitted entirely when no continuity input can be constructed.

Current input / output envelopes

  • Continuity gate script envelope:
    • input: JSON file path via --input; optional --compact
    • output keys: ok, status, verdict, reason?, gate, compact, inputPath, input
  • Dispatch binding script envelope:
    • input: JSON file path via --input; optional --receipt-dir; optional --compact
    • output keys on success: ok, status, binding, compact, inputPath, receipt, receiptPath, input
    • output keys on failure: same envelope plus missing, with receiptPath: null

Test coverage baseline already present

  • scripts/test_approved_plan_continuity_gate.mjs covers:
    • JSON envelope skeleton / gate label
    • fail when taskState=complete + known next action + no valid dispatch receipt + non-legal closure
    • fail when planner uses derivedAction without bound receipt
    • fail when dispatchReceipt is fake non-null object without minimum fields
    • pass when valid dispatch receipt exists
    • pass when derivedAction has bound dispatch receipt
    • pass for legal closure states waiting_user, blocked, pending_verification
  • scripts/test_force_recall_long_task_preflight.mjs covers continuity integration in hook preflight:
    • continuity block is emitted in pass-path plumbing
    • dry-run auto-chain dispatch alone still yields status=continuity_failure
    • hook block must surface verdict=continuity_failure and reason=missing_dispatch_receipt
    • hook guidance must route back to continuity failure until a real receipt exists

Known limitations / extraction constraints

  • Continuity rules are hard-coded in scripts and hook glue; there is no plugin config surface yet.
  • Hook integration shells out through script execution instead of importing a shared evaluator.
  • Receipt validation logic is split:
    • gate pass/fail uses a smaller inline validator
    • receipt persistence uses a fuller required-field validator
  • Current gate treats any object-shaped nextDerivedAction as sufficient inside a receipt; action schema is not validated further.
  • Current gate does not read receipts from disk by convention; it only validates the in-memory dispatchReceipt payload passed into it.
  • Hook-generated plannerDerivedAction is dry-run planner intent, not proof of real dispatch; continuity intentionally still fails until a real receipt is attached.

Task 2: Create plugin package skeleton

Files:

  • Create: plugins/continuity/package.json
  • Create: plugins/continuity/README.md
  • Create: plugins/continuity/README.zh-TW.md
  • Create: plugins/continuity/HOOK.md
  • Create: plugins/continuity/src/index.mjs

Step 1: Create the directory tree only Run:

mkdir -p plugins/continuity/src plugins/continuity/src/config plugins/continuity/src/continuity plugins/continuity/src/adapters plugins/continuity/examples plugins/continuity/test

Expected: directories exist

Step 2: Add minimal package metadata and placeholder entrypoint

  • package.json should declare the plugin name, version, ESM type, and test script.
  • src/index.mjs should export placeholders for:
    • config schema/defaults
    • evaluator
    • receipt validator
    • hook adapter factory

Step 3: Verify files exist Run:

test -f plugins/continuity/package.json \
  && test -f plugins/continuity/src/index.mjs \
  && test -f plugins/continuity/README.md \
  && test -f plugins/continuity/README.zh-TW.md \
  && echo OK

Expected: OK

Step 4: Commit

git add plugins/continuity
git commit -m "chore: add continuity plugin package skeleton"

Task 3: Define plugin config schema contract

Files:

  • Create: plugins/continuity/src/config/schema.mjs
  • Create: plugins/continuity/src/config/defaults.mjs
  • Create: plugins/continuity/examples/openclaw.continuity.example.json
  • Modify: plugins/continuity/README.md
  • Modify: plugins/continuity/README.zh-TW.md

Step 1: Write the config keys before implementation code Define exact keys for MVP, for example:

  • enabled
  • planMatchers
  • legalTerminalStates
  • receiptDir
  • requireRealDispatchReceipt
  • allowReplyClosureWithoutDispatch
  • debug
  • adapter.forceRecall.enabled
  • adapter.forceRecall.injectBlockLabel

Step 2: Add schema/default exports

  • schema.mjs should export the allowed key list, required types, and validation helper contract.
  • defaults.mjs should export a concrete defaults object aligned with todays behavior.

Step 3: Add example config

  • Put a fully populated example JSON under plugins/continuity/examples/openclaw.continuity.example.json.

Step 4: Verify example config matches schema keys Run:

node -e "import('./plugins/continuity/src/config/defaults.mjs').then(m=>console.log(Object.keys(m.defaultConfig||m.defaults||{})))"

Expected: prints the default key list without runtime error

Step 5: Commit

git add plugins/continuity/src/config plugins/continuity/examples/openclaw.continuity.example.json plugins/continuity/README.md plugins/continuity/README.zh-TW.md
git commit -m "feat: define continuity plugin config schema and defaults"

Task 4: Write failing tests for config validation

Files:

  • Create: plugins/continuity/test/continuity.config.test.mjs
  • Test: plugins/continuity/src/config/schema.mjs

Step 1: Write fail-first tests for valid config Cover:

  • accepts default config
  • accepts custom receipt directory
  • accepts custom legal terminal states list

Step 2: Write fail-first tests for invalid config Cover:

  • rejects non-array legalTerminalStates
  • rejects empty receiptDir
  • rejects unknown terminal state type entries
  • rejects disabled adapter object shape if malformed

Step 3: Run tests to verify failure Run:

node plugins/continuity/test/continuity.config.test.mjs

Expected: FAIL because validator behavior is not fully implemented yet

Step 4: Commit

git add plugins/continuity/test/continuity.config.test.mjs
git commit -m "test: add fail-first continuity plugin config validation tests"

Task 5: Implement minimal config validator

Files:

  • Modify: plugins/continuity/src/config/schema.mjs
  • Modify: plugins/continuity/src/config/defaults.mjs
  • Modify: plugins/continuity/test/continuity.config.test.mjs

Step 1: Implement the smallest validator that passes the tests

  • Normalize missing fields from defaults.
  • Reject malformed fields with explicit error codes/messages.
  • Preserve current terminal states: waiting_user, blocked, pending_verification.

Step 2: Run tests Run:

node plugins/continuity/test/continuity.config.test.mjs

Expected: PASS

Step 3: Commit

git add plugins/continuity/src/config/schema.mjs plugins/continuity/src/config/defaults.mjs plugins/continuity/test/continuity.config.test.mjs
git commit -m "feat: validate continuity plugin config"

Task 6: Extract receipt validator contract

Files:

  • Create: plugins/continuity/src/continuity/receipt-validator.mjs
  • Create: plugins/continuity/src/continuity/types.md
  • Modify: plugins/continuity/README.md
  • Modify: plugins/continuity/README.zh-TW.md

Step 1: Document the receipt shape in one place Define these fields as the MVP minimum:

  • planId
  • currentTask
  • nextDerivedAction
  • dispatchedAt
  • dispatchRunId
  • childSessionKey
  • replyClosureState

Step 2: Export validator API shape

  • validateReceipt(receipt) returns { ok, errors, normalizedReceipt }
  • isValidReceipt(receipt) returns boolean

Step 3: Verify file exists and exports load Run:

node -e "import('./plugins/continuity/src/continuity/receipt-validator.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))"

Expected: export list includes validator functions

Step 4: Commit

git add plugins/continuity/src/continuity/receipt-validator.mjs plugins/continuity/src/continuity/types.md plugins/continuity/README.md plugins/continuity/README.zh-TW.md
git commit -m "chore: define continuity receipt validator contract"

Task 7: Write failing tests for receipt validator

Files:

  • Create: plugins/continuity/test/continuity.receipt-validator.test.mjs
  • Test: plugins/continuity/src/continuity/receipt-validator.mjs

Step 1: Write success-path tests Cover:

  • valid receipt with all minimum fields passes
  • filesystem-safe IDs are accepted

Step 2: Write failure-path tests Cover:

  • missing planId
  • missing dispatchRunId
  • non-object nextDerivedAction
  • empty childSessionKey
  • fake non-null receipt object fails

Step 3: Run tests to verify failure Run:

node plugins/continuity/test/continuity.receipt-validator.test.mjs

Expected: FAIL

Step 4: Commit

git add plugins/continuity/test/continuity.receipt-validator.test.mjs
git commit -m "test: add fail-first continuity receipt validator tests"

Task 8: Implement receipt validator

Files:

  • Modify: plugins/continuity/src/continuity/receipt-validator.mjs
  • Modify: plugins/continuity/test/continuity.receipt-validator.test.mjs

Step 1: Implement field validation and normalization

  • Reuse current minimum field expectations from scripts/approved_plan_dispatch_binding.mjs and scripts/approved_plan_continuity_gate.mjs.
  • Keep validation separate from file I/O.

Step 2: Run tests Run:

node plugins/continuity/test/continuity.receipt-validator.test.mjs

Expected: PASS

Step 3: Commit

git add plugins/continuity/src/continuity/receipt-validator.mjs plugins/continuity/test/continuity.receipt-validator.test.mjs
git commit -m "feat: implement continuity receipt validator"

Task 9: Extract receipt store helper

Files:

  • Create: plugins/continuity/src/continuity/receipt-store.mjs
  • Modify: plugins/continuity/examples/approved-plan-receipt.example.json
  • Modify: plugins/continuity/README.md
  • Modify: plugins/continuity/README.zh-TW.md

Step 1: Create the example receipt JSON

  • Add a real-looking valid receipt example matching the documented minimum shape.

Step 2: Implement file naming helpers only Export small functions for:

  • slugifying planId
  • slugifying dispatchRunId
  • building receipt-<planId>-<dispatchRunId>.json
  • resolving the receipt path from config

Step 3: Verify helper exports load Run:

node -e "import('./plugins/continuity/src/continuity/receipt-store.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))"

Expected: helper export names print successfully

Step 4: Commit

git add plugins/continuity/src/continuity/receipt-store.mjs plugins/continuity/examples/approved-plan-receipt.example.json plugins/continuity/README.md plugins/continuity/README.zh-TW.md
git commit -m "chore: add continuity receipt store helpers and examples"

Task 10: Write failing tests for receipt store behavior

Files:

  • Create: plugins/continuity/test/continuity.receipt-store.test.mjs
  • Test: plugins/continuity/src/continuity/receipt-store.mjs

Step 1: Write tests for path generation Cover:

  • builds correct filename from safe IDs
  • normalizes unsafe characters
  • resolves receipt path inside configured receipt dir

Step 2: Write tests for write/read round-trip Cover:

  • writes validated receipt JSON
  • reads back same logical payload
  • rejects invalid receipt before write

Step 3: Run tests to verify failure Run:

node plugins/continuity/test/continuity.receipt-store.test.mjs

Expected: FAIL until read/write helpers exist

Step 4: Commit

git add plugins/continuity/test/continuity.receipt-store.test.mjs
git commit -m "test: add fail-first continuity receipt store tests"

Task 11: Implement receipt store helpers

Files:

  • Modify: plugins/continuity/src/continuity/receipt-store.mjs
  • Modify: plugins/continuity/test/continuity.receipt-store.test.mjs

Step 1: Implement the minimum store API Export functions for:

  • buildReceiptFilename
  • resolveReceiptPath
  • writeReceipt
  • readReceipt

Step 2: Run tests Run:

node plugins/continuity/test/continuity.receipt-store.test.mjs

Expected: PASS

Step 3: Commit

git add plugins/continuity/src/continuity/receipt-store.mjs plugins/continuity/test/continuity.receipt-store.test.mjs
git commit -m "feat: implement continuity receipt store helpers"

Task 12: Extract continuity evaluator contract

Files:

  • Create: plugins/continuity/src/continuity/evaluator.mjs
  • Modify: plugins/continuity/src/index.mjs
  • Modify: plugins/continuity/README.md
  • Modify: plugins/continuity/README.zh-TW.md

Step 1: Define evaluator input/output shape Input should support:

  • taskState
  • nextDerivedAction
  • derivedAction
  • replyClosureState
  • dispatchReceipt
  • config override for legal terminal states

Output should support:

  • ok
  • status
  • verdict
  • reason
  • gate

Step 2: Stub the evaluator exports

  • evaluateContinuity(payload, config)
  • buildContinuityGateBlock(result, config)

Step 3: Verify exports load Run:

node -e "import('./plugins/continuity/src/continuity/evaluator.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))"

Expected: export list prints successfully

Step 4: Commit

git add plugins/continuity/src/continuity/evaluator.mjs plugins/continuity/src/index.mjs plugins/continuity/README.md plugins/continuity/README.zh-TW.md
git commit -m "chore: define continuity evaluator contract"

Task 13: Write failing tests for continuity evaluator parity

Files:

  • Create: plugins/continuity/test/continuity.evaluator.test.mjs
  • Test: plugins/continuity/src/continuity/evaluator.mjs
  • Reference: scripts/test_approved_plan_continuity_gate.mjs

Step 1: Port the current continuity gate cases into plugin tests Cover at least:

  • fail when task complete + next action known + no dispatch receipt + closure not legal
  • fail when planner returns derivedAction without bound dispatch receipt
  • fail when fake non-null receipt object is supplied
  • pass when valid dispatch receipt exists
  • pass when closure is waiting_user
  • pass when closure is blocked
  • pass when closure is pending_verification

Step 2: Add one plugin-specific config override case

  • custom legal terminal states list works

Step 3: Run tests to verify failure Run:

node plugins/continuity/test/continuity.evaluator.test.mjs

Expected: FAIL

Step 4: Commit

git add plugins/continuity/test/continuity.evaluator.test.mjs
git commit -m "test: add fail-first continuity evaluator parity tests"

Task 14: Implement continuity evaluator

Files:

  • Modify: plugins/continuity/src/continuity/evaluator.mjs
  • Modify: plugins/continuity/src/continuity/receipt-validator.mjs
  • Modify: plugins/continuity/test/continuity.evaluator.test.mjs

Step 1: Implement the smallest evaluator that matches current behavior

  • Reuse receipt validator instead of inline checks.
  • Preserve current failure reason: missing_dispatch_receipt.
  • Preserve current legal closure state behavior.

Step 2: Run tests Run:

node plugins/continuity/test/continuity.evaluator.test.mjs

Expected: PASS

Step 3: Commit

git add plugins/continuity/src/continuity/evaluator.mjs plugins/continuity/src/continuity/receipt-validator.mjs plugins/continuity/test/continuity.evaluator.test.mjs
git commit -m "feat: implement continuity evaluator"

Task 15: Add script bridge for backward compatibility

Files:

  • Create: plugins/continuity/src/adapters/script-bridge.mjs
  • Modify: scripts/approved_plan_continuity_gate.mjs
  • Modify: scripts/approved_plan_dispatch_binding.mjs

Step 1: Write failing bridge tests first

  • The old scripts should still produce compatible JSON envelopes by delegating to plugin modules.

Step 2: Implement thin bridge wiring

  • Keep CLI parsing in scripts if easiest.
  • Move decision logic to plugin modules.

Step 3: Run existing script tests Run:

node scripts/test_approved_plan_continuity_gate.mjs

Expected: PASS with plugin-backed logic

Step 4: Commit

git add plugins/continuity/src/adapters/script-bridge.mjs scripts/approved_plan_continuity_gate.mjs scripts/approved_plan_dispatch_binding.mjs
git commit -m "refactor: bridge legacy continuity scripts to plugin modules"

Task 16: Extract hook adapter contract

Files:

  • Create: plugins/continuity/src/adapters/force-recall.mjs
  • Modify: plugins/continuity/HOOK.md
  • Modify: plugins/continuity/src/index.mjs

Step 1: Define hook adapter responsibilities The adapter should:

  • accept hook context and plugin config
  • build continuity input from hook state
  • call the evaluator
  • return a prompt block or structured gate result
  • avoid duplicating evaluator rules

Step 2: Stub the factory export Export something like:

  • createForceRecallContinuityAdapter(config)
  • runForceRecallContinuityAdapter(ctx, config)

Step 3: Verify exports load Run:

node -e "import('./plugins/continuity/src/adapters/force-recall.mjs').then(m=>console.log(Object.keys(m).sort().join(',')))"

Expected: export names print successfully

Step 4: Commit

git add plugins/continuity/src/adapters/force-recall.mjs plugins/continuity/HOOK.md plugins/continuity/src/index.mjs
git commit -m "chore: define force-recall continuity adapter contract"

Task 17: Write failing tests for hook adapter

Files:

  • Create: plugins/continuity/test/continuity.plugin.test.mjs
  • Test: plugins/continuity/src/adapters/force-recall.mjs
  • Reference: hooks/force-recall/handler.ts

Step 1: Write success-path adapter tests Cover:

  • returns no block when no approved-plan continuity context exists
  • returns pass block when receipt is valid

Step 2: Write fail-path adapter tests Cover:

  • returns hard-gate block when continuity fails
  • includes expected gate label and reason
  • honors config override for block label/debug mode

Step 3: Run tests to verify failure Run:

node plugins/continuity/test/continuity.plugin.test.mjs

Expected: FAIL

Step 4: Commit

git add plugins/continuity/test/continuity.plugin.test.mjs
git commit -m "test: add fail-first continuity hook adapter tests"

Task 18: Implement hook adapter

Files:

  • Modify: plugins/continuity/src/adapters/force-recall.mjs
  • Modify: plugins/continuity/src/continuity/evaluator.mjs
  • Modify: plugins/continuity/test/continuity.plugin.test.mjs

Step 1: Implement adapter logic with minimal hook assumptions

  • Build gate input from hook payload.
  • Delegate decisions to evaluator.
  • Build the hard-gate block string in one place.

Step 2: Run tests Run:

node plugins/continuity/test/continuity.plugin.test.mjs

Expected: PASS

Step 3: Commit

git add plugins/continuity/src/adapters/force-recall.mjs plugins/continuity/src/continuity/evaluator.mjs plugins/continuity/test/continuity.plugin.test.mjs
git commit -m "feat: implement continuity force-recall adapter"

Task 19: Wire force-recall hook to the plugin adapter

Files:

  • Modify: hooks/force-recall/handler.ts
  • Test: scripts/test_force_recall_long_task_preflight.mjs
  • Reference: plugins/continuity/src/adapters/force-recall.mjs

Step 1: Write the smallest integration change

  • Replace inline continuity-specific logic in handler.ts with plugin adapter invocation.
  • Keep unrelated long-task governor behavior unchanged.

Step 2: Run targeted verification Run:

node scripts/test_approved_plan_continuity_gate.mjs
node scripts/test_force_recall_long_task_preflight.mjs
node --check hooks/force-recall/handler.ts

Expected: PASS

Step 3: Commit

git add hooks/force-recall/handler.ts
git commit -m "refactor: route force-recall continuity gate through plugin adapter"

Task 20: Add plugin-level smoke test

Files:

  • Create: plugins/continuity/test/continuity.smoke.test.mjs
  • Modify: plugins/continuity/package.json
  • Modify: plugins/continuity/examples/openclaw.continuity.example.json

Step 1: Write a smoke test that exercises the public plugin path Smoke path should:

  • load config
  • validate config
  • validate receipt
  • evaluate a failing continuity payload
  • evaluate a passing payload with valid receipt

Step 2: Run the smoke test Run:

node plugins/continuity/test/continuity.smoke.test.mjs

Expected: PASS

Step 3: Expose a package script Add package script, for example:

{
  "scripts": {
    "test": "node test/continuity.config.test.mjs && node test/continuity.receipt-validator.test.mjs && node test/continuity.receipt-store.test.mjs && node test/continuity.evaluator.test.mjs && node test/continuity.plugin.test.mjs && node test/continuity.smoke.test.mjs"
  }
}

Step 4: Verify package test command Run:

cd plugins/continuity && npm test

Expected: PASS

Step 5: Commit

git add plugins/continuity/package.json plugins/continuity/test/continuity.smoke.test.mjs plugins/continuity/examples/openclaw.continuity.example.json
git commit -m "test: add continuity plugin smoke test and package test script"

Task 21: Write bilingual README installation/apply instructions

Files:

  • Modify: plugins/continuity/README.md
  • Modify: plugins/continuity/README.zh-TW.md
  • Reference: plugins/continuity/HOOK.md
  • Reference: plugins/continuity/examples/openclaw.continuity.example.json

Step 1: Add English README sections Include:

  • what problem the plugin solves
  • MVP scope/non-goals
  • install location and package layout
  • config reference table/list
  • example config snippet
  • receipt format summary
  • hook adapter usage
  • smoke test command
  • migration note from hard-coded scripts

Step 2: Add Traditional Chinese README sections with parity Include the same sections as the English README.

Step 3: Verify both READMEs mention the same critical commands Run:

rg -n "npm test|openclaw|receiptDir|waiting_user|pending_verification|blocked" plugins/continuity/README.md plugins/continuity/README.zh-TW.md

Expected: both files contain the same core operational terms

Step 4: Commit

git add plugins/continuity/README.md plugins/continuity/README.zh-TW.md plugins/continuity/HOOK.md
git commit -m "docs: add bilingual continuity plugin installation and usage guides"

Task 22: Add example application note for root workspace config

Files:

  • Modify: plugins/continuity/README.md
  • Modify: plugins/continuity/README.zh-TW.md
  • Optional Create: docs/runbooks/continuity-plugin-apply.md

Step 1: Document how to apply the plugin in a real OpenClaw workspace Show a concrete example of:

  • where the plugin folder lives
  • how config points at state/approved-plan-continuity
  • how force-recall should load/use the adapter

Step 2: Add a do-not-do list Explicitly warn against:

  • changing core continuity rules during extraction
  • using fake dispatch receipts for pass-through
  • removing current scripts before parity tests pass

Step 3: Verify paths are exact Run:

test -d plugins/continuity && test -d state/approved-plan-continuity && test -f hooks/force-recall/handler.ts && echo OK

Expected: OK

Step 4: Commit

git add plugins/continuity/README.md plugins/continuity/README.zh-TW.md docs/runbooks/continuity-plugin-apply.md
git commit -m "docs: add continuity plugin apply guidance for workspace integration"

Task 23: Run full verification suite

Files:

  • Test: plugins/continuity/test/*.mjs
  • Test: scripts/test_approved_plan_continuity_gate.mjs
  • Test: scripts/test_force_recall_long_task_preflight.mjs
  • Check: hooks/force-recall/handler.ts

Step 1: Run plugin package tests Run:

cd plugins/continuity && npm test

Expected: PASS

Step 2: Run compatibility tests from repo root Run:

node scripts/test_approved_plan_continuity_gate.mjs
node scripts/test_force_recall_long_task_preflight.mjs
node --check hooks/force-recall/handler.ts

Expected: PASS

Step 3: Record exact verification results in the plan tail or PR notes

  • Copy exact commands
  • Copy PASS summary counts
  • Note any skipped tests

Step 4: Commit

git add plugins/continuity hooks/force-recall/handler.ts scripts/approved_plan_continuity_gate.mjs scripts/approved_plan_dispatch_binding.mjs docs/plans/2026-04-24-continuity-plugin-mvp.md
git commit -m "chore: verify continuity plugin MVP end-to-end"

Task 24: Final acceptance checklist and handoff

Files:

  • Modify: docs/plans/2026-04-24-continuity-plugin-mvp.md
  • Review: plugins/continuity/README.md
  • Review: plugins/continuity/README.zh-TW.md

Step 1: Add a checked acceptance checklist to the bottom of the plan Include:

  • config schema implemented
  • evaluator extracted
  • receipt validator extracted
  • hook adapter wired
  • plugin-level tests passing
  • bilingual README complete
  • example config present
  • smoke test present
  • compatibility path preserved

Step 2: Mark remaining risks explicitly List at least:

  • plugin loader assumptions may differ from current repo conventions
  • current repo lacks an existing continuity plugin precedent
  • future non-force-recall adapters are out of MVP scope

Step 3: Leave status as pending verification, not complete

  • Follow the workspace rule that implementation is not “done” until verified by the owner flow.

Step 4: Commit

git add docs/plans/2026-04-24-continuity-plugin-mvp.md
git commit -m "docs: finalize continuity plugin MVP implementation plan"

MVP Validation Checklist

  • plugins/continuity/ package exists with entrypoint, docs, examples, and tests
  • Config schema/defaults exist and are test-covered
  • Receipt validator exists and is test-covered
  • Receipt store helpers exist and are test-covered
  • Continuity evaluator exists and matches current hard-gate behavior
  • Legacy scripts bridge to plugin logic or are otherwise compatibility-covered
  • hooks/force-recall/handler.ts consumes plugin adapter instead of continuity-specific inline logic
  • English README explains install/config/test/migration
  • Traditional Chinese README explains install/config/test/migration
  • Example config and example receipt are checked in
  • Smoke test passes
  • Existing continuity and force-recall tests still pass

Risks / Open Questions

  1. The repo currently has an empty plugins/ directory, so actual OpenClaw plugin manifest/loading conventions may need one discovery slice before implementation.
  2. hooks/force-recall/handler.ts currently mixes several long-task concerns; extracting only continuity logic must avoid accidental behavior drift in unrelated gate-lock/auto-chain code.
  3. Current script tests cover continuity decisions but not yet the full plugin install path, so smoke coverage is mandatory for MVP credibility.
  4. The bilingual README must stay behaviorally aligned with actual example config and commands; drift here would make the plugin “documented” but not really adoptable.

Plan complete and saved to docs/plans/2026-04-24-continuity-plugin-mvp.md. Two execution options:

1. Subagent-Driven (this session) - I dispatch fresh subagent per task, review between tasks, fast iteration

2. Parallel Session (separate) - Open new session with executing-plans, batch execution with checkpoints

Which approach?

If Subagent-Driven chosen:

  • REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
  • Stay in this session
  • Fresh subagent per task + code review

If Parallel Session chosen:

  • Guide them to open new session in worktree
  • REQUIRED SUB-SKILL: New session uses superpowers:executing-plans