19 KiB
Continuity Plugin MVP: Agent Installation and Operations Guide
Audience: OpenClaw agents / implementers
This is a hands-on runbook and checklist, not a conceptual overview. If you only need to know whether to install it, how to wire it, and how to verify it, start here instead of reading the full README first.
0. When should you install this plugin?
Recommended situations
Install this plugin if any of the following are true in your workspace:
- You run approved-plan style long-running or multi-step tasks.
- You do not want the agent to treat a finished task as “the whole job is done” by default.
- You need the agent to decide whether there is a next task to dispatch inside the same approved plan.
- You need a dispatch receipt as evidence that the next step was actually dispatched, instead of only saying so in prose.
- You already use
hooks/force-recall/handler.tsand want to inject the approved-plan continuity gate into the agent prompt. - You do not have a
force-recallhook, but you do have your own preflight / planner / orchestrator and want to call the generic continuity adapter directly.
Cases where you can skip it for now
You can defer installation, or treat this plugin as reference only, when:
- Your workspace has no approved-plan / auto-chain / dispatch flow.
- You only need ordinary single-turn chat behavior and do not need a continuity hard gate.
- You do not have a
force-recallhook and you also do not plan to add generic glue code in your own host/orchestrator.
1. Installation target and expected outcome
After installation, the minimum expected result is:
- your host (for example
force-recallor your own preflight path) can loadplugins/continuity/src/index.mjs - the host calls one of these during preflight:
runForceRecallContinuityAdapter(...)runGenericPreflightContinuityAdapter(...)runManualContinuityPreflight(...)
- the agent prompt contains a visible
[APPROVED_PLAN_CONTINUITY_GATE] ... [/APPROVED_PLAN_CONTINUITY_GATE]block - when an approved-plan task is finished but there is no real next-step dispatch receipt, the gate blocks an incorrect closure
- plugin tests and the relevant host smoke path pass
2. Where should it live?
Standard location
Place the plugin here inside the workspace:
<workspace>/plugins/continuity
Recommended layout (adjust as needed for your host):
<workspace>/
hooks/
force-recall/
handler.ts
HOOK.md
plugins/
continuity/
AGENT_GUIDE.zh-TW.md
AGENT_GUIDE.md
README.zh-TW.md
README.md
HOOK.md
GENERIC_INTEGRATION.zh-TW.md
GENERIC_INTEGRATION.md
package.json
examples/
src/
test/
scripts/
test_force_recall_long_task_preflight.mjs
Actual path for this document set
/home/alice/.openclaw/workspace/plugins/continuity
3. Pre-install checklist
Before you start, confirm:
- your workspace has
hooks/force-recall/handler.ts, or you already know which generic/manual host path will call the plugin - your workspace has
scripts/test_force_recall_long_task_preflight.mjsif you intend to use theforce-recallpath - your workspace is willing to adopt the approved-plan continuity hard gate
- you understand that
force-recallis the most mature adapter, but not the only host path - you understand that the receipt is a minimum contract, not a complete workflow engine
Quick checks:
cd <workspace>
ls plugins/continuity/package.json
ls plugins/continuity/src/index.mjs
ls hooks/force-recall/handler.ts
ls scripts/test_force_recall_long_task_preflight.mjs
If you do not have force-recall, see GENERIC_INTEGRATION.zh-TW.md or GENERIC_INTEGRATION.md for the generic/manual path.
4. Required files
Required files
At minimum, you should have:
plugins/continuity/
package.json
src/index.mjs
src/adapters/force-recall.mjs
src/adapters/generic-preflight.mjs
src/config/defaults.mjs
src/config/schema.mjs
src/continuity/evaluator.mjs
src/continuity/receipt-validator.mjs
src/continuity/receipt-store.mjs
examples/openclaw.continuity.example.json
examples/approved-plan-receipt.example.json
Strongly recommended files
plugins/continuity/
README.zh-TW.md
README.md
HOOK.md
AGENT_GUIDE.zh-TW.md
AGENT_GUIDE.md
GENERIC_INTEGRATION.zh-TW.md
GENERIC_INTEGRATION.md
test/continuity.config.test.mjs
test/continuity.receipt-validator.test.mjs
test/continuity.receipt-store.test.mjs
test/continuity.evaluator.test.mjs
test/continuity.plugin.test.mjs
test/continuity.smoke.test.mjs
If files are missing, what should you restore first?
Priority order:
src/index.mjssrc/adapters/force-recall.mjssrc/adapters/generic-preflight.mjssrc/continuity/evaluator.mjssrc/continuity/receipt-validator.mjssrc/continuity/receipt-store.mjsexamples/openclaw.continuity.example.jsontest/continuity.smoke.test.mjs
5. Direct installation steps
Path A: you are already inside the same repo/workspace
- confirm
plugins/continuityexists - confirm
package.jsonandsrc/index.mjsexist - confirm your chosen host entrypoint exists
Verification:
cd <workspace>
find plugins/continuity -maxdepth 3 -type f | sort
Path B: you want to copy it into another OpenClaw workspace
From the source workspace:
cd <source-workspace>
rsync -av plugins/continuity/ <target-workspace>/plugins/continuity/
Then verify inside the target workspace:
cd <target-workspace>
find plugins/continuity -maxdepth 3 -type f | sort
6. How to apply the example config
Step 1: copy the example continuity config
Source example:
plugins/continuity/examples/openclaw.continuity.example.json
Example content:
{
"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"
}
}
}
Step 2: only change the minimum fields first
Usually you only need to verify these first:
enabledplanMatcherslegalTerminalStatesreceiptDirrequireRealDispatchReceiptallowReplyClosureWithoutDispatchadapter.forceRecall.enabledadapter.forceRecall.injectBlockLabeladapter.genericPreflight.enabledadapter.genericPreflight.injectBlockLabel
Step 3: recommended minimum application strategy
Situation A: you want the current approved-plan MVP behavior
Use the example as-is in most cases:
planMatchers = ["approved-plan"]legalTerminalStates = ["waiting_user", "blocked", "pending_verification"]requireRealDispatchReceipt = trueallowReplyClosureWithoutDispatch = false
Situation B: your planner uses a different plan name
Adjust:
{
"planMatchers": ["your-approved-plan-name"]
}
Situation C: you want a different injected block label
Adjust:
{
"adapter": {
"genericPreflight": {
"enabled": true,
"injectBlockLabel": "YOUR_CONTINUITY_GATE"
}
}
}
Step 4: create the receipt directory up front
cd <workspace>
mkdir -p state/approved-plan-continuity
7. How to wire the host/hook
7.1 Integration points to confirm
The most mature integration point is still:
hooks/force-recall/handler.ts
But that is no longer the only path. A generic or manual preflight host can also call the plugin directly.
A typical host-side flow should look like this:
- run long-task preflight / wrapper, or equivalent host preflight
- run gate lock if you have one
- run auto-chain planner, or derive next action in your own planner
- load the continuity plugin
- call the appropriate adapter
- prepend the returned continuity block into the prompt body shown to the agent
At minimum, look for these symbols
plugins/continuity/src/index.mjsrunForceRecallContinuityAdapterrunGenericPreflightContinuityAdapterrunManualContinuityPreflightAPPROVED_PLAN_CONTINUITY_GATE
Example checks:
cd <workspace>
grep -n "runForceRecallContinuityAdapter" hooks/force-recall/handler.ts
grep -n "APPROVED_PLAN_CONTINUITY_GATE" hooks/force-recall/handler.ts
7.2 Minimum force-recall wiring example
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}`;
}
7.3 Minimum generic/manual wiring example
If you do not have force-recall, feed your own preflight result into the generic adapter:
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,
},
});
If you only need a one-off manual continuity preflight:
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',
});
7.4 Real checks implementers should perform
- the host can import
plugins/continuity/src/index.mjs - the chosen adapter function exists
- relevant input is passed in
configis passed in, at leastdefaultConfigto start- when
out.blockis non-empty, it is prepended to the agent-facing prompt/body - the final agent prompt really contains the continuity gate block
7.5 Relationship between receipt and continuity input
If your flow really dispatches the next step, do not only say “dispatched” in plain text. Emit a real dispatchReceipt.
Minimum receipt shape:
planIdcurrentTasknextDerivedActiondispatchedAtdispatchRunIdchildSessionKeyreplyClosureState
Reference example: plugins/continuity/examples/approved-plan-receipt.example.json
8. Suggested implementation workflow
Checklist: first-time plugin integration into an existing workspace
- create/copy
plugins/continuity - confirm
src/index.mjscan be loaded by the host - confirm the example config is readable
- create
state/approved-plan-continuity/ - confirm your host has a continuity adapter call site
- confirm the continuity block is prepended into the agent prompt/body
- if a real dispatch occurs, persist a receipt
- run plugin tests
- run the host smoke path
- confirm the injected prompt block is present
Checklist: first-time receipt persistence
- prepare a valid receipt object
- validate it with
validateReceipt()/isValidReceipt()first - persist it with
writeReceipt({ receiptDir, receipt }) - confirm the receipt file lands in
state/approved-plan-continuity/ - rerun continuity smoke tests so you do not mistake “looks like a receipt” for a real passing state
9. How to run smoke tests after installation
Minimum smoke test
Run the plugin tests first:
cd <workspace>/plugins/continuity
npm test
If you only want a quick plugin-only verification:
cd <workspace>/plugins/continuity
node test/continuity.smoke.test.mjs
Hook integration smoke test
cd <workspace>
node scripts/test_force_recall_long_task_preflight.mjs
node --check hooks/force-recall/handler.ts
Recommended full smoke order
This order makes failures easier to localize:
- plugin unit/integration tests
cd <workspace>/plugins/continuity
npm test
- hook syntax check
cd <workspace>
node --check hooks/force-recall/handler.ts
- hook preflight smoke test
cd <workspace>
node scripts/test_force_recall_long_task_preflight.mjs
- manual inspection: confirm the block is really injected
Look for:
[APPROVED_PLAN_CONTINUITY_GATE]
10. Smoke test success criteria
The minimum install is successful only if all of these are true:
npm testpassesnode --check hooks/force-recall/handler.tspasses, if you use that pathnode scripts/test_force_recall_long_task_preflight.mjspasses, if you use that path- the continuity gate block is visible in test output or debug prompt output
- when there is no receipt, the gate fails / hard-gates the missing-dispatch case
- legal terminal states such as
waiting_user,blocked, orpending_verificationare not misclassified
11. What to check first when something fails
Follow this order. Do not start by changing random code.
Layer 1: path and file existence
plugins/continuity/src/index.mjsexists- your host entrypoint exists
plugins/continuity/examples/openclaw.continuity.example.jsonexistsplugins/continuity/examples/approved-plan-receipt.example.jsonexists
Commands:
cd <workspace>
ls plugins/continuity/src/index.mjs
ls hooks/force-recall/handler.ts
ls plugins/continuity/examples/openclaw.continuity.example.json
ls plugins/continuity/examples/approved-plan-receipt.example.json
Layer 2: is the host really calling the plugin?
- your host imports or dynamically loads the continuity plugin
- your host calls the correct adapter function
- your host prepends
out.blockinto the agent prompt/body
Layer 3: is the config sensible?
Check first:
enabled === true- the chosen adapter is enabled
planMatchersmatches your approved-plan namereceiptDiris writablerequireRealDispatchReceiptmatches your intended policyallowReplyClosureWithoutDispatchhas not accidentally weakened the gate
Layer 4: is the receipt real, not placeholder data?
Common problems:
- only “planning to dispatch”, but no real receipt
- incomplete receipt shape
- empty
dispatchRunIdorchildSessionKey - invalid
replyClosureState - writing to the wrong directory
Layer 5: is the host preflight data sufficient?
The continuity adapter depends on preflight inputs such as:
- wrapper/planner output in the
force-recallpath - normalized continuity source data in the generic path
So verify:
- the host really carries forward long-task / approved-plan state
- the planner really produced
derivedAction/nextDerivedAction - the continuity input can be built from host data
- closure state is derived correctly
12. Quick debugging commands
Run the plugin test suite
cd <workspace>/plugins/continuity
npm test
Check hook syntax
cd <workspace>
node --check hooks/force-recall/handler.ts
Check continuity keywords in the handler
cd <workspace>
grep -n "runForceRecallContinuityAdapter" hooks/force-recall/handler.ts
grep -n "APPROVED_PLAN_CONTINUITY_GATE" hooks/force-recall/handler.ts
Check whether receipts are actually written
cd <workspace>
find state/approved-plan-continuity -maxdepth 2 -type f | sort
13. Current limitations
Accept these limitations before installation:
- this plugin is an extracted approved-plan continuity hard gate, not a general workflow engine
force-recallis still the most mature adapter, but not the only adapter- if your workspace has no
force-recall, you still need to connect host data into the generic/manual path yourself - config is still “module defaults + caller input”, not a full installer/registry flow
- the receipt store only writes files; it does not manage retention, cleanup, or indexing
- the receipt validator checks only the minimum contract; it does not deeply validate every
nextDerivedActionsemantic variant - if you only perform dry-run planning and never create a real dispatch receipt, the gate may still fail by design; that is expected behavior, not a bug
14. Recommended delivery standard: what counts as “another agent can follow this”?
If you hand this plugin to another agent or implementer, the handoff should at least satisfy all of the following:
- they understand the plugin purpose without re-reading the entire conversation
- they know where the files should live
- they know which files must be copied
- they know how to wire the
force-recallhook, if applicable - they know which example config fields to check first
- they know how to run smoke tests
- they know the first debugging layers to inspect
- they understand the current limits and do not mistake this for a full workflow framework
If all eight points are covered, this has reached the “agent can follow it” bar.
15. One-page execution summary
If you are in a hurry, do only these:
- put the plugin here:
<workspace>/plugins/continuity
- confirm the host is wired to:
plugins/continuity/src/index.mjsrunForceRecallContinuityAdapter(...)orrunGenericPreflightContinuityAdapter(...)- prepend
out.blockinto the agent prompt/body
- apply the example config:
plugins/continuity/examples/openclaw.continuity.example.json
- create the receipt directory:
mkdir -p <workspace>/state/approved-plan-continuity
- run tests:
cd <workspace>/plugins/continuity && npm test
cd <workspace> && node --check hooks/force-recall/handler.ts
cd <workspace> && node scripts/test_force_recall_long_task_preflight.mjs
- confirm the prompt contains:
[APPROVED_PLAN_CONTINUITY_GATE]
- confirm that without a real dispatch receipt, the task is not incorrectly treated as completed.
16. Reference files
plugins/continuity/README.zh-TW.mdplugins/continuity/README.mdplugins/continuity/HOOK.mdplugins/continuity/GENERIC_INTEGRATION.zh-TW.mdplugins/continuity/GENERIC_INTEGRATION.mdplugins/continuity/examples/openclaw.continuity.example.jsonplugins/continuity/examples/approved-plan-receipt.example.jsonhooks/force-recall/handler.tsscripts/test_force_recall_long_task_preflight.mjs
If you need the Traditional Chinese operator version, use AGENT_GUIDE.zh-TW.md first; this file is the English counterpart.