Files

701 lines
19 KiB
Markdown

# 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.ts` and want to inject the approved-plan continuity gate into the agent prompt.
- You do not have a `force-recall` hook, 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-recall` hook 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-recall` or your own preflight path) can load `plugins/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:
```text
<workspace>/plugins/continuity
```
Recommended layout (adjust as needed for your host):
```text
<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
```text
/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.mjs` if you intend to use the `force-recall` path
- [ ] your workspace is willing to adopt the approved-plan continuity hard gate
- [ ] you understand that `force-recall` is 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:
```bash
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:
```text
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
```text
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:
1. `src/index.mjs`
2. `src/adapters/force-recall.mjs`
3. `src/adapters/generic-preflight.mjs`
4. `src/continuity/evaluator.mjs`
5. `src/continuity/receipt-validator.mjs`
6. `src/continuity/receipt-store.mjs`
7. `examples/openclaw.continuity.example.json`
8. `test/continuity.smoke.test.mjs`
---
## 5. Direct installation steps
### Path A: you are already inside the same repo/workspace
- [ ] confirm `plugins/continuity` exists
- [ ] confirm `package.json` and `src/index.mjs` exist
- [ ] confirm your chosen host entrypoint exists
Verification:
```bash
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:
```bash
cd <source-workspace>
rsync -av plugins/continuity/ <target-workspace>/plugins/continuity/
```
Then verify inside the target workspace:
```bash
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:
```text
plugins/continuity/examples/openclaw.continuity.example.json
```
Example content:
```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"
}
}
}
```
### Step 2: only change the minimum fields first
Usually you only need to verify these first:
- [ ] `enabled`
- [ ] `planMatchers`
- [ ] `legalTerminalStates`
- [ ] `receiptDir`
- [ ] `requireRealDispatchReceipt`
- [ ] `allowReplyClosureWithoutDispatch`
- [ ] `adapter.forceRecall.enabled`
- [ ] `adapter.forceRecall.injectBlockLabel`
- [ ] `adapter.genericPreflight.enabled`
- [ ] `adapter.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 = true`
- `allowReplyClosureWithoutDispatch = false`
#### Situation B: your planner uses a different plan name
Adjust:
```json
{
"planMatchers": ["your-approved-plan-name"]
}
```
#### Situation C: you want a different injected block label
Adjust:
```json
{
"adapter": {
"genericPreflight": {
"enabled": true,
"injectBlockLabel": "YOUR_CONTINUITY_GATE"
}
}
}
```
### Step 4: create the receipt directory up front
```bash
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:
```text
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:
1. run long-task preflight / wrapper, or equivalent host preflight
2. run gate lock if you have one
3. run auto-chain planner, or derive next action in your own planner
4. load the continuity plugin
5. call the appropriate adapter
6. prepend the returned continuity block into the prompt body shown to the agent
### At minimum, look for these symbols
- `plugins/continuity/src/index.mjs`
- `runForceRecallContinuityAdapter`
- `runGenericPreflightContinuityAdapter`
- `runManualContinuityPreflight`
- `APPROVED_PLAN_CONTINUITY_GATE`
Example checks:
```bash
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
```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}`;
}
```
## 7.3 Minimum generic/manual wiring example
If you do **not** have `force-recall`, feed your own preflight result into the generic 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,
},
});
```
If you only need a one-off manual continuity preflight:
```js
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
- [ ] `config` is passed in, at least `defaultConfig` to start
- [ ] when `out.block` is 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:
- `planId`
- `currentTask`
- `nextDerivedAction`
- `dispatchedAt`
- `dispatchRunId`
- `childSessionKey`
- `replyClosureState`
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.mjs` can 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:
```bash
cd <workspace>/plugins/continuity
npm test
```
If you only want a quick plugin-only verification:
```bash
cd <workspace>/plugins/continuity
node test/continuity.smoke.test.mjs
```
### Hook integration smoke test
```bash
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:
1. plugin unit/integration tests
```bash
cd <workspace>/plugins/continuity
npm test
```
2. hook syntax check
```bash
cd <workspace>
node --check hooks/force-recall/handler.ts
```
3. hook preflight smoke test
```bash
cd <workspace>
node scripts/test_force_recall_long_task_preflight.mjs
```
4. manual inspection: confirm the block is really injected
Look for:
```text
[APPROVED_PLAN_CONTINUITY_GATE]
```
---
## 10. Smoke test success criteria
The minimum install is successful only if all of these are true:
- [ ] `npm test` passes
- [ ] `node --check hooks/force-recall/handler.ts` passes, if you use that path
- [ ] `node scripts/test_force_recall_long_task_preflight.mjs` passes, 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`, or `pending_verification` are 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.mjs` exists
- [ ] your host entrypoint exists
- [ ] `plugins/continuity/examples/openclaw.continuity.example.json` exists
- [ ] `plugins/continuity/examples/approved-plan-receipt.example.json` exists
Commands:
```bash
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.block` into the agent prompt/body
### Layer 3: is the config sensible?
Check first:
- [ ] `enabled === true`
- [ ] the chosen adapter is enabled
- [ ] `planMatchers` matches your approved-plan name
- [ ] `receiptDir` is writable
- [ ] `requireRealDispatchReceipt` matches your intended policy
- [ ] `allowReplyClosureWithoutDispatch` has 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 `dispatchRunId` or `childSessionKey`
- 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-recall` path
- 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
```bash
cd <workspace>/plugins/continuity
npm test
```
### Check hook syntax
```bash
cd <workspace>
node --check hooks/force-recall/handler.ts
```
### Check continuity keywords in the handler
```bash
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
```bash
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-recall` is 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 `nextDerivedAction` semantic 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-recall` hook, 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:
1. put the plugin here:
```text
<workspace>/plugins/continuity
```
2. confirm the host is wired to:
- `plugins/continuity/src/index.mjs`
- `runForceRecallContinuityAdapter(...)` or `runGenericPreflightContinuityAdapter(...)`
- prepend `out.block` into the agent prompt/body
3. apply the example config:
```text
plugins/continuity/examples/openclaw.continuity.example.json
```
4. create the receipt directory:
```bash
mkdir -p <workspace>/state/approved-plan-continuity
```
5. run tests:
```bash
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
```
6. confirm the prompt contains:
```text
[APPROVED_PLAN_CONTINUITY_GATE]
```
7. confirm that without a real dispatch receipt, the task is not incorrectly treated as completed.
---
## 16. Reference files
- `plugins/continuity/README.zh-TW.md`
- `plugins/continuity/README.md`
- `plugins/continuity/HOOK.md`
- `plugins/continuity/GENERIC_INTEGRATION.zh-TW.md`
- `plugins/continuity/GENERIC_INTEGRATION.md`
- `plugins/continuity/examples/openclaw.continuity.example.json`
- `plugins/continuity/examples/approved-plan-receipt.example.json`
- `hooks/force-recall/handler.ts`
- `scripts/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.