Skip to content

manifest: declare contracts.tools, bump to 1.2.0#35

Merged
pallaoro merged 4 commits into
mainfrom
fix-contracts-tools-manifest
May 19, 2026
Merged

manifest: declare contracts.tools, bump to 1.2.0#35
pallaoro merged 4 commits into
mainfrom
fix-contracts-tools-manifest

Conversation

@pallaoro
Copy link
Copy Markdown
Member

@pallaoro pallaoro commented May 19, 2026

Summary

Restores flow_run/flow_create/etc. as native OpenClaw tools on hosts running ≥ 2026.4.26, and replaces the legacy boolean approval gate with a configurable one. Four compounding issues addressed:

1. Manifest missing contracts.tools (OpenClaw 2026.5.2)

"enforce contracts.tools as the manifest ownership contract for plugin tool registration, rejecting undeclared runtime tool names"

Adds all 11 runtime tools: flow_create, flow_delete, flow_restore_from_bin, flow_run, flow_resume, flow_send_event, flow_status, flow_list, flow_read, flow_publish, flow_edit.

2. dist/index.js had no plugin default export

OpenClaw's loader resolves through package.json.main. Previously src/index.ts exported only the library surface, so dist/index.js had no default.register → gateway logged [plugins] clawflow missing register/activate export. src/index.ts now re-exports default from ./plugin/index.js so dist/index.js exposes both plugin entry + public library symbols.

3. registerHook missing required name (OpenClaw 2026.4.26)

"fail plugin registration when loader-owned acceptance gates reject missing hook names"

The plugin called api.registerHook("before_tool_call", handler) without opts. The current SDK signature requires { name }. Now passes { name: "clawflow-flow-run-approval", description: ... }.

4. Approval gate hardcoded + inflexible

Previously: prompted unconditionally on every flow_run with a boolean requireApproval: true + plain prompt string. Incompatible with hook-driven, unattended automation (e.g. inbound-email workflows whose session has no interactive channel).

Adds approval to PluginConfig (and configSchema):

approval?: {
  enabled?: boolean;              // default true
  skipSessionPatterns?: string[]; // substrings against ctx.sessionKey
  timeoutMs?: number;             // default 5 min
  timeoutBehavior?: "allow" | "deny"; // default "deny"
}

Hosts running unattended workflows (e.g. Clawnify with "skipSessionPatterns": ["email"]) bypass the gate for those sessions. Standalone clawflow users keep the safe default.

Also modernizes the hook event handling:

  • Reads event.toolName (with event.tool fallback for older runtimes).
  • Reads event.context.sessionKey per current OpenClaw event shape.
  • Returns the rich requireApproval: { title, description, severity, timeoutMs, timeoutBehavior } object the gateway and dashboard render natively.

Also

  • Bumps version 0.2.2 / 1.1.01.2.0 (sync openclaw.plugin.json with package.json).
  • Bumps compat.pluginApi / minGatewayVersion to >=2026.5.2, build.openclawVersion to 2026.5.12.
  • Drops the unreferenced duplicate manifest at src/plugin/openclaw.plugin.json.

Test plan

  • npm run build + npm run lint pass
  • node -e "import('./dist/index.js').then(m => …)"default.register: function
  • Termit canary deploy: gateway log clean, plugin loads, [clawflow] flow server listening on :3335
  • Agent CLI test: openclaw agent --agent main --message "is flow_run available?"YES
  • Termit inbound-email end-to-end: PDF order email → flow ran successfully (confirmed by user)
  • Approval skip on email sessions configured via plugins.entries.clawflow.config.approval.skipSessionPatterns = ["email"]

pallaoro added 4 commits May 19, 2026 11:59
OpenClaw 2026.5.2 began enforcing `contracts.tools` as the manifest
ownership contract for plugin tool registration: any runtime
`registerTool()` call whose name isn't declared in the manifest is
rejected, so the gateway reports `toolNames: []` and tools like
`flow_run` are invisible to agents.

Declares all 11 tools registered in src/plugin/index.ts:
flow_create, flow_delete, flow_restore_from_bin, flow_run, flow_resume,
flow_send_event, flow_status, flow_list, flow_read, flow_publish,
flow_edit.

Also:
- Bumps compat.pluginApi / minGatewayVersion to >=2026.5.2 (the
  release that enforced the contract) and build.openclawVersion to
  2026.5.12.
- Syncs openclaw.plugin.json version (was stale at 0.2.2) with
  package.json (now both 1.2.0).
- Drops the unreferenced duplicate manifest at src/plugin/openclaw.plugin.json.
OpenClaw's plugin loader uses `package.json.main` (./dist/index.js) as
the entry point, so dist/index.js must expose `default.register` for
the plugin to register tools.

Before this change, src/index.ts contained only library re-exports
(FlowRunner, validateFlow, etc.) — compiled dist/index.js had no
`default` export at all, and the gateway logged
`[plugins] clawflow missing register/activate export`.

After: dist/index.js exports BOTH the plugin default (id + register)
AND the public library surface, so OpenClaw can register the 11 flow
tools while standalone consumers can still `import { FlowRunner }`.
OpenClaw 2026.4.26 began requiring an explicit hook name in the third
argument of `api.registerHook()`. Without it the loader rejects the
plugin entirely with:

    plugin load failed: clawflow: Error: hook registration missing name

This prevents the plugin's register() from completing, so none of the
11 flow_* tools end up registered either.

Passes { name: "clawflow-flow-run-approval" } as the opts argument
and updates the local PluginApi typing to match the current SDK shape
(events: string|string[], opts.name required).
The approval hook previously prompted unconditionally on every flow_run
and returned a boolean `requireApproval: true` with a plain prompt string
— inflexible and incompatible with hook-driven, unattended automation
(e.g. inbound-email workflows whose session has no interactive channel
to surface the prompt in).

Adds `approval` to PluginConfig with four knobs, all backward-compatible
(the default behavior is still "ask on every run"):

  approval:
    enabled: boolean              # default true; false disables entirely
    skipSessionPatterns: string[] # substrings; if any appears in
                                  # ctx.sessionKey the gate is skipped
                                  # (e.g. ["email"] for inbound-email
                                  # automation: session keys look like
                                  # `agent:main:main:email:<id>`)
    timeoutMs: number             # default 300000 (5 min)
    timeoutBehavior: "allow"|"deny"  # default "deny"

Also modernizes the hook:
- Reads `event.toolName` (keeps `event.tool` fallback for older runtimes).
- Reads `event.context.sessionKey` per current OpenClaw event shape.
- Returns the rich `requireApproval: { title, description, severity,
  timeoutMs, timeoutBehavior }` object the gateway and dashboard render
  natively, instead of the legacy boolean+prompt pair.

Hosts that want unattended automation (e.g. Clawnify) can configure
`plugins.entries.clawflow.config.approval.skipSessionPatterns = ["email"]`.
Standalone users keep the safe default.
@pallaoro pallaoro merged commit ab29f74 into main May 19, 2026
1 check passed
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