Skip to content

feat: add Moltis hook provider - #25

Open
GTanger wants to merge 7 commits into
speakeasy-api:mainfrom
GTanger:feat/moltis-provider
Open

feat: add Moltis hook provider#25
GTanger wants to merge 7 commits into
speakeasy-api:mainfrom
GTanger:feat/moltis-provider

Conversation

@GTanger

@GTanger GTanger commented Sep 2, 2026

Copy link
Copy Markdown

Summary

  • add ProviderMoltis, native process-per-event decoding, shape detection, and typed views for all 17 HookPayload variants
  • render native TOML-frontmatter HOOK.md packs for user/project installs; group tool.post and tool.error into one AfterToolCall subscription
  • preserve Moltis semantics instead of treating its OpenClaw importer as wire compatibility
  • consume Moltis' native tool_call_id when present and retain the synthesized-ID fallback for unpatched releases
  • correlate outbound lifecycle pairs by session, content, and event order, and require complete pre/post ID pairing for every observed tool call
  • add provenance-stamped fixtures, capability/quirk coverage, and an opt-in isolated real-Gateway E2E

Native semantics covered

  • exit 0 with empty stdout: no opinion
  • exit 1 with stderr: block with reason
  • {"action":"modify","data":...}: tool-argument rewrite
  • MessageReceived context: append to the only mutable native field, content
  • AfterToolCall.success=false: normalize as tool.error
  • MessageSending and MessageSent: retain as Moltis-native extension events; AgentEnd maps to the portable stop event

The quirk registry records the stock 20260902.01-20260902.02 gaps: no native tool-call correlation ID and missing production dispatch for some declared lifecycle payloads. It also records native fail-open behavior on hook crashes/timeouts. moltis-org/moltis#1257 supplies the host-side lifecycle and identity changes while this adapter remains backward-compatible.

Ground truth

The codec and fixtures are qualified against the official Moltis 20260902.01 tag, commit 77b0d0ac52744aa4d59cbfe83db23cb7a6283ccf:

Live compatibility was then verified against a portable 20260902.02 build carrying moltis-org/moltis#1257, including its review fix that suppresses MessageSent when persistence or known-channel delivery fails.

Verification

  • go mod tidy -diff
  • go build ./...
  • go vet ./...
  • golangci-lint v2.7.2 run — 0 issues
  • go test -race ./... — PASS
  • go test ./... -run 'Moltis' -count=1 — PASS
  • AGENTHOOKS_E2E=1 AGENTHOOKS_MOLTIS_BASE_URL=http://127.0.0.1:11434/v1 AGENTHOOKS_MOLTIS_MODEL=Q4-ColdFusion-27B go test ./e2e -run '^TestMoltisEventsAndDecisions$' -count=1 -v — PASS in 118.04s on the current head
  • AGENTHOOKS_E2E=1 go test ./e2e -run '^TestCodexPortableHandler$' -count=1 -v — PASS in 16.38s

The Moltis E2E starts an isolated localhost Gateway with temporary config/data/project roots and uses the same provider-free recorder used by the Codex E2E. It proves:

  • prompt context reaches the final model response
  • every native BeforeToolCall and AfterToolCall has a non-empty, bidirectionally matched stable ID
  • a correlated MessageSending precedes MessageSent for the same session and content
  • AgentEnd is observed as the portable stop event
  • a direct /sh denial prevents the marker command from executing
  • model-issued tool denial prevents execution
  • updated tool input replaces the command that actually runs

The test does not modify the live Moltis configuration or Gateway.

@GTanger
GTanger requested a review from a team as a code owner September 2, 2026 12:56
@GTanger
GTanger force-pushed the feat/moltis-provider branch from 6b52980 to 5d076f3 Compare September 2, 2026 13:01

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread provider/moltis/moltis.go
Comment thread install/render_moltis.go
Comment thread codec_moltis.go Outdated
Comment thread codec_moltis.go Outdated
Comment thread provider/moltis/moltis_test.go
Comment thread codec_moltis_test.go Outdated
Comment thread DESIGN.md

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 31 files (changes from recent commits).

Confidence score: 5/5

  • agenthookstest/fixtures/moltis/README.md documents Moltis 20260902.01 at commit 77b0d0ac..., while the PR description cites 610e9fba...; this creates a minor reproducibility and release-traceability ambiguity—confirm the correct commit and make the references consistent.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="agenthookstest/fixtures/moltis/README.md">

<violation number="1" location="agenthookstest/fixtures/moltis/README.md:4">
P3: The README pins these fixtures to Moltis 20260902.01 at commit 77b0d0ac..., but the PR description cites a different commit (610e9fba...) for the same release. A tagged release points to exactly one commit, so the two references contradict each other. Reconcile them to a single verified hash so a reader re-qualifying against the pinned commit lands on the intended revision.</violation>
</file>

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.

Fix all with cubic | Re-trigger cubic

Comment thread install/render_moltis_test.go Outdated
Comment thread e2e/moltis_test.go Outdated
# Moltis fixture provenance

These payloads target **Moltis 20260902.01** at the official tag commit
[`77b0d0ac52744aa4d59cbfe83db23cb7a6283ccf`](https://github.com/moltis-org/moltis/commit/77b0d0ac52744aa4d59cbfe83db23cb7a6283ccf).

@cubic-dev-ai cubic-dev-ai Bot Sep 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The README pins these fixtures to Moltis 20260902.01 at commit 77b0d0ac..., but the PR description cites a different commit (610e9fba...) for the same release. A tagged release points to exactly one commit, so the two references contradict each other. Reconcile them to a single verified hash so a reader re-qualifying against the pinned commit lands on the intended revision.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At agenthookstest/fixtures/moltis/README.md, line 4:

<comment>The README pins these fixtures to Moltis 20260902.01 at commit 77b0d0ac..., but the PR description cites a different commit (610e9fba...) for the same release. A tagged release points to exactly one commit, so the two references contradict each other. Reconcile them to a single verified hash so a reader re-qualifying against the pinned commit lands on the intended revision.</comment>

<file context>
@@ -0,0 +1,34 @@
+# Moltis fixture provenance
+
+These payloads target **Moltis 20260902.01** at the official tag commit
+[`77b0d0ac52744aa4d59cbfe83db23cb7a6283ccf`](https://github.com/moltis-org/moltis/commit/77b0d0ac52744aa4d59cbfe83db23cb7a6283ccf).
+The complete 17-variant wire schema comes from the public `HookPayload` enum in
+`crates/common/src/hooks.rs`; Moltis does not version the hook protocol
</file context>
Fix with cubic

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reconciled the PR description and fixture provenance on the verified official tag commit 77b0d0ac52744aa4d59cbfe83db23cb7a6283ccf. The newer f640c9b7 reference is used only for the separately documented 20260902.02 release audit, not as the 20260902.01 fixture source.

@GTanger

GTanger commented Sep 2, 2026

Copy link
Copy Markdown
Author

Addressed all valid Cubic findings in 4caa8f1 and added the shared Codex/Moltis consumer E2E in 1a822fd:

  • match-all now dominates scoped matchers when Moltis specs share a native event
  • prompt context appends to the middleware-mutated typed prompt
  • unavailable AfterToolCall arguments keep RawInput == nil
  • nested ChannelBinding unknown fields are retained
  • all 17 Moltis typed views now have fixture coverage and tool-event assertions are panic-safe
  • Moltis history polling now treats transient GraphQL failures as retryable
  • the shell-quoting assertion is OS-aware
  • DESIGN.md includes Moltis in the provider list
  • fixture README and PR both pin official tag commit 77b0d0ac52744aa4d59cbfe83db23cb7a6283ccf

Current verification: go test -race ./... -count=1 passes, golangci-lint reports 0 issues, isolated Moltis E2E passes in 117.79s, and the same provider-free recorder/context/natural prompt passes the real Codex E2E in 16.38s.

Preserve Moltis tool_call_id values in normalized events and typed provider views while retaining synthesized fallback identities for released payloads.

Extend the live conformance test to require AgentEnd, stable pre/post correlation, and direct shell denial against the lifecycle implementation proposed in moltis-org/moltis#1257.

Document the official-release gap and the forward-compatible patched wire.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 8 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread provider/moltis/moltis_test.go
Comment thread e2e/moltis_test.go
Install native MessageSending and MessageSent observers in the real Moltis E2E harness. Assert that outbound content is non-empty, unchanged across the two events, and emitted in pre-send then post-send order.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Confidence score: 4/5

  • In e2e/moltis_test.go, requireMoltisMessageLifecycle compares the final MessageSending and MessageSent contents even though the fixtures show these are distinct payloads; valid lifecycles could therefore fail end-to-end tests. Align the assertion with the intended lifecycle semantics.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="e2e/moltis_test.go">

<violation number="1" location="e2e/moltis_test.go:415">
P2: requireMoltisMessageLifecycle asserts the last MessageSending content equals the last MessageSent content, but Moltis models these as distinct payloads (the PR's own fixtures show "message entering the model" vs "message delivered"), and in a real multi-iteration session the last MessageSending is an input message while the last MessageSent is the assistant output. Track each pair by session/message instead, or assert that a Sending has a corresponding Sent with matching content rather than comparing the last occurrences globally.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread e2e/moltis_test.go Outdated
Match MessageSending to a later MessageSent by session key and content instead of comparing whichever two lifecycle events happened to be last. This keeps the process-level acceptance test robust when unrelated turns add more events.
Require every observed BeforeToolCall and AfterToolCall ID to have a counterpart instead of accepting the first matching pair.

Rename the typed-view test to describe forward-compatible decoding without implying that unpatched Moltis releases already emit stable IDs.
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