Skip to content

Add daemon-backed HarnessClient receive path - #942

Merged
chughtapan merged 2 commits into
mainfrom
agent/harness-receive
Aug 4, 2026
Merged

Add daemon-backed HarnessClient receive path#942
chughtapan merged 2 commits into
mainfrom
agent/harness-receive

Conversation

@chughtapan

@chughtapan chughtapan commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • add raw same-conversation turn delivery to MoltZapChannelCore without daemon-side presentation enrichment or checkpoint writes;
  • make moltzapd own the active MoltZapService, channel core, WebSocket connection, loopback MCP listener, and turn publisher;
  • expose an Effect-based HarnessClient whose MCP-backed turns carry their originating conversation and a payload-only bound reply closure;
  • own the narrow MoltZap subscriptions/listen extension adapter while delegating discovery, tools, standard subscriptions, and unrelated lifecycle behavior to the official MCP SDK;
  • bound graceful MCP response draining so a stalled loopback reader cannot retain daemon shutdown; and
  • remove local duplicate-reply suppression so every bound reply(payload) invocation sends.

Why

This is the first operational production slice of #926. It establishes the daemon-owned receive/reply boundary after #941 removed production dispatch leases, without recreating leases, reply tokens, action IDs, turn IDs, or generic authority fields.

The result is a real loopback MCP path from a peer message through moltzapd to HarnessClient, with a reply returning through the originating conversation and no Unix-socket dependency.

SDK extension boundary

The package-local adapter intercepts only the exact MoltZap turn-ready filter. Standard, mixed, malformed, inherited-property, and unrelated requests remain SDK-owned. An independent landability audit found mixed-filter and inherited-property isolation gaps; both are fixed and regression-tested.

The upstream official SDK proposal remains a possible future replacement, not a prerequisite: modelcontextprotocol/typescript-sdk#2593

Review fix

Pre-landing lifecycle review reproduced a stalled SSE reader holding scope closure behind Node response backpressure. Shutdown now gives handler closure and response draining one second, then destroys remaining scope-owned connections and joins cleanup. The regression test pauses a reader behind an 8 MiB event and proves scope closure completes without client cooperation while the existing small slow-reader test still receives terminal completion.

Validation

  • pnpm nx run workspace:precommit — 61/61 targets
  • pnpm nx run @moltzap/client:test — 30 files, 221 tests
  • focused real daemon integration — 3 PGlite/WebSocket/MCP tests
  • OpenClaw unit suite — 66 tests
  • NanoClaw unit suite — 24 tests
  • independent contract, lifecycle, and test/maintenance reviews — no remaining landability blocker

Deliberate follow-up scope

This PR does not yet cut OpenClaw or NanoClaw over to HarnessClient, define the deferred management/search/context Schemas, or remove the existing CLI, Unix RPC socket, and generic send. Those remain ordered follow-up slices in #926 and are retained until their MCP replacements are operational.

@mintlify

mintlify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
moltzap 🟢 Ready View Preview Aug 4, 2026, 4:11 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant