From efde217d4e0f00048150f36dec035eec94af9741 Mon Sep 17 00:00:00 2001 From: moss Date: Tue, 19 May 2026 16:09:12 +0700 Subject: [PATCH 1/2] docs: add OpenClaw joinpoint availability tiers (A/B/C) to v0.1 model Classify catalog joinpoints by plugin hooks, agent event stream, wrapper, and upstream gaps; reconcile with bridge strong vs observe-only paths. Co-authored-by: Cursor --- .../adr/0011-openclaw-joinpoint-model-v0.1.md | 2 +- .../opencoat-openclaw-joinpoint-model-v0.1.md | 110 +++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/docs/adr/0011-openclaw-joinpoint-model-v0.1.md b/docs/adr/0011-openclaw-joinpoint-model-v0.1.md index b2dd8b2..7f1bb93 100644 --- a/docs/adr/0011-openclaw-joinpoint-model-v0.1.md +++ b/docs/adr/0011-openclaw-joinpoint-model-v0.1.md @@ -37,7 +37,7 @@ task indexes). form. Pointcuts may use either form. 6. **Full model:** Documented in [`docs/design/opencoat-openclaw-joinpoint-model-v0.1.md`](../design/opencoat-openclaw-joinpoint-model-v0.1.md) - (14 domains). Implementation is phased (P0 catalog aliases → P2 plugin hooks → + (14 domains; **§5 A/B/C availability tiers** for OpenClaw vs catalog). Implementation is phased (P0 catalog aliases → P2 plugin hooks → P3 bridge runtime observers for observe-only MVP emits). ## Consequences diff --git a/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md b/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md index a42d45d..a00f47b 100644 --- a/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md +++ b/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md @@ -397,7 +397,115 @@ Default: `runtimeObservers: true`, `observerPollMs: 500`. Full hook table: [brid --- -## 5. Joinpoint map (tree) +## 5. OpenClaw availability tiers (A / B / C) + +Many catalog joinpoints are **OpenCOAT cut points** — valid for pointcuts and DCN — that OpenClaw does **not** yet expose as synchronous host hooks. Classify every integration path as: + +```text +A. Usable now — OpenClaw event, plugin hook, or stable runtime API the bridge can call +B. Wrapper tier — wrap a public function or adapter boundary without mutating internal Maps +C. Not direct — needs OpenClaw middleware/hook PR, or is OpenCOAT-internal (COPR / span / token) +``` + +### 5.1 One-line conclusion + +**Best signals today:** plugin hooks (`before_prompt_build`, `before_tool_call`, …), **`api.runtime.events.onAgentEvent`** (`plan`, `tool`, `item`, `approval`, `command_output`, `patch`, `compaction`, `lifecycle`), task registry APIs, queue depth / followup run observability. + +**Weakest / internal-only:** `token.*`, `span.*`, `prompt.section.*` (until host passes structured sections), implicit planner steps, true memory read/write on every path, unified `response.before_final` verifier (partial via `message_sending` only). + +**Strong control gap (upstream):** synchronous veto at `enqueueFollowupRun`, full `reply_run.phase.*`, and any path where only post-hoc agent events exist today. + +### 5.2 Tier A — usable now + +| Surface | OpenClaw anchor | v0.1 / legacy JP | Bridge today | Control | +| --- | --- | --- | --- | --- | +| Plugin hooks | `before_prompt_build`, `llm_*`, `agent_end` | `before_response`, reasoning JPs | yes | **weave** (`prependSystemContext`) | +| Plugin hooks | `before_tool_call` | `tool.before_call` | yes | **block** / param guard | +| Plugin hooks | `message_sending` | `before_response` | yes | **cancel** outbound | +| Plugin hooks | `subagent_spawning` | `task.before_create` | yes | spawn **veto** | +| Plugin hooks | `before_compaction` / `after_compaction` | memory JPs | yes | observe (+ same boundary as internal compact hook) | +| Agent event stream | `stream: plan` | `planning.plan_updated` | observer | observe | +| Agent event stream | `stream: approval` (phase requested) | `approval.requested` | observer | observe | +| Agent event stream | `stream: compaction` start/end | memory JPs | observer | observe | +| Agent event stream | `stream: lifecycle` start | `reply_run.before_begin` | observer | observe | +| Agent event stream | `stream: tool` / `item` / `assistant` after start | `reply_run.phase.running` | observer | observe | +| Agent event stream | `stream: command_output`, `patch` | (catalog TBD) | not wired | observe (future) | +| Task API | `runtime.tasks.runs.bindSession().list()` | `task.*` | poll diff | observe | +| Task hooks | `subagent_*` | `task.after_create`, `task.before_terminal` | yes | observe / spawn veto | +| Input | `message_received`, `inbound_claim`, `before_dispatch` | `input.received` | yes | observe / extract | + +**Important correction:** OpenClaw’s plugin hook `before_tool_call` **is** a pre-execute guard — do not confuse it with `onAgentEvent` `stream: tool`, which fires around tool **start** and is observe-only. Catalog name `tool.before_call` maps to the plugin hook, not `tool.started`. + +### 5.3 Tier B — wrapper or weak modulation + +| Joinpoint (design) | How to attach | Bridge / OpenCOAT today | +| --- | --- | --- | +| `queue.before_enqueue` / `after_enqueue` | wrap `enqueueFollowupRun` or depth poll | poll only (late) | +| `queue.before_drain` | wrap `scheduleFollowupDrain` | not wired | +| `input.before_enqueue` | adapter before enqueue | partial (`on_user_input` buffer) | +| `prompt.before_send_to_model` | `FollowupRun.extraSystemPrompt`, hook fold | plugin + discovery | +| `model.before_select` | wrap `runAgentTurnWithFallback` | not wired | +| `reply_run.phase.*` (fine phases) | wrap `ReplyOperation.setPhase` | approximated via lifecycle only | +| `response.streaming_delta` | `onPartialReply` / block reply callbacks | not wired | +| `system_event.enqueued` | wrap `enqueueSystemEvent` | not wired | + +OpenCOAT applies **weak modulation** here: extra system prompt, queue/task *policy suggestions* in submit results (host must apply), timeouts, tool visibility — not direct Map mutation. + +### 5.4 Tier C — native hook or OpenCOAT-internal + +**Needs OpenClaw PR (middleware at call site):** + +```text +tool.before_execute # if stricter than plugin before_tool_call (args rewrite mid-flight) +queue.before_enqueue # sync veto at enqueueFollowupRun (bridge poll is too late) +reply_run.phase.* # per-phase hooks on ReplyOperation +memory.before_read / before_write # unified memory middleware (compaction hooks are partial) +response.before_final # unified verifier before channel delivery (message_sending is partial) +response.before_delivery +plan_step.before_execute / decision.before_select +``` + +**OpenCOAT-internal (not OpenClaw hooks):** parse host payload → COPR / prompt tree → child joinpoints: + +```text +token.* span.* prompt.section.* user_message#msg:N runtime_prompt.* +``` + +Requires `messages[]` / `sections[]` on submit (bridge sends `messages[]` on `before_prompt_build`; JoinpointDiscovery expands). + +### 5.5 Observation vs strong control + +```text +Observation (DCN, audit, meta-review): + plan / approval / patch / command_output / compaction events + queue depth diff, task registry diff, reply_run lifecycle approx + +Strong control (host must apply advice): + before_prompt_build → prependSystemContext + before_tool_call → block / params + message_sending → cancel + subagent_spawning → error status + +Upstream “neurosurgery” (recommended order): + 1. tool.before_execute middleware (if plugin hook insufficient) + 2. response.before_final verifier hook + 3. memory.before_write middleware (beyond compaction) +``` + +### 5.6 MVP integration waves + +| Wave | Joinpoints | Mechanism | +| --- | --- | --- | +| **Shipped (bridge)** | §4.1 MVP rows marked “yes” | plugin hooks + `runtime-observers.ts` | +| **Next (observe)** | `command.output`, `patch.*`, streaming deltas | extend `onAgentEvent` mapping in bridge | +| **Next (upstream)** | sync `queue.before_enqueue`, `reply_run.phase.*`, `response.before_final` | OpenClaw plugin hooks at call sites | +| **OpenCOAT-only** | `span.*`, `token.*`, message children | discovery on prompt payload | + +Design catalog lists **17 MVP names**; bridge **strong loop** today is smaller: input → prompt fold → tool guard → optional outbound cancel → task/subagent edges, plus observe-only queue/run/task/event stream for DCN. + +--- + +## 6. Joinpoint map (tree) ```text OpenCOAT Joinpoint (v0.1) From 7b18c56d22e6932b2ec6891f186f8568c89743e1 Mon Sep 17 00:00:00 2001 From: moss Date: Tue, 19 May 2026 16:17:25 +0700 Subject: [PATCH 2/2] docs: use catalog names command.output_stream and patch.summary_created Address Codex PR #75 review: next-wave bridge mapping must match Level 6 joinpoint names so pointcuts match the catalog. Co-authored-by: Cursor --- docs/design/opencoat-openclaw-joinpoint-model-v0.1.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md b/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md index a00f47b..35dbbf0 100644 --- a/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md +++ b/docs/design/opencoat-openclaw-joinpoint-model-v0.1.md @@ -429,7 +429,8 @@ C. Not direct — needs OpenClaw middleware/hook PR, or is OpenCOAT-internal | Agent event stream | `stream: compaction` start/end | memory JPs | observer | observe | | Agent event stream | `stream: lifecycle` start | `reply_run.before_begin` | observer | observe | | Agent event stream | `stream: tool` / `item` / `assistant` after start | `reply_run.phase.running` | observer | observe | -| Agent event stream | `stream: command_output`, `patch` | (catalog TBD) | not wired | observe (future) | +| Agent event stream | `stream: command_output` | `command.output_stream` | not wired | observe (future) | +| Agent event stream | `stream: patch` | `patch.summary_created` | not wired | observe (future) | | Task API | `runtime.tasks.runs.bindSession().list()` | `task.*` | poll diff | observe | | Task hooks | `subagent_*` | `task.after_create`, `task.before_terminal` | yes | observe / spawn veto | | Input | `message_received`, `inbound_claim`, `before_dispatch` | `input.received` | yes | observe / extract | @@ -497,7 +498,7 @@ Upstream “neurosurgery” (recommended order): | Wave | Joinpoints | Mechanism | | --- | --- | --- | | **Shipped (bridge)** | §4.1 MVP rows marked “yes” | plugin hooks + `runtime-observers.ts` | -| **Next (observe)** | `command.output`, `patch.*`, streaming deltas | extend `onAgentEvent` mapping in bridge | +| **Next (observe)** | `command.output_stream`, `patch.summary_created`, streaming deltas | extend `onAgentEvent` mapping in bridge (use catalog names, not `command.output`) | | **Next (upstream)** | sync `queue.before_enqueue`, `reply_run.phase.*`, `response.before_final` | OpenClaw plugin hooks at call sites | | **OpenCOAT-only** | `span.*`, `token.*`, message children | discovery on prompt payload | @@ -541,7 +542,7 @@ OpenCOAT Joinpoint (v0.1) --- -## 6. Wire shape (reference) +## 7. Wire shape (reference) v0.1 extends `JoinpointEvent` with domain metadata; `name` remains the pointcut key (flat or dotted).