openclaw-mova 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md ADDED
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: openclaw-mova
3
+ description: Execute MOVA AI contracts with human-in-the-loop decision gates. Covers invoice OCR approval, PO approval, AML alert triage, EU complaints handling, crypto trade review, compliance audit, credit scoring, supply chain risk, churn prediction, contract generation, connector registry, and user contract registration and remote execution. Trigger when the user asks to process a financial document, triage an AML alert, review a supplier, run a compliance check, or register and execute their own MOVA contracts.
4
+ license: MIT-0
5
+ metadata: {"openclaw":{"plugin":{"name":"MOVA","installCmd":"openclaw plugins install openclaw-mova"},"dataSentToExternalServices":[{"service":"MOVA API (api.mova-lab.eu, EU-hosted)","data":"contract inputs, decision data, audit metadata, API key in Authorization header"},{"service":"No other external services","data":"All connector calls (ERP, AML screening, etc.) go through the MOVA API only — the plugin never opens direct connections to third-party systems"}],"security":{"fileIO":"none","arbitraryNetworkCalls":"none — only https://api.mova-lab.eu (configurable via baseUrl)","credentialStorage":"apiKey stored in OpenClaw plugin config, sent only to the configured baseUrl"}}}
6
+ ---
7
+
8
+ # MOVA Plugin — Runtime Instructions
9
+
10
+ This plugin connects OpenClaw to the MOVA contract execution platform. All tools call only `https://api.mova-lab.eu` (or the configured `baseUrl`) using the `apiKey` in the `Authorization: Bearer` header. There is no file I/O, no shell execution, and no connections to any external services other than the configured MOVA API.
11
+
12
+ ## Security properties
13
+
14
+ - **Network calls:** HTTPS only, always to `config.baseUrl` (default: `https://api.mova-lab.eu`). No wildcard URLs, no dynamic endpoint construction beyond path parameters.
15
+ - **File I/O:** None. The plugin never reads or writes local files.
16
+ - **Shell / exec:** Never used.
17
+ - **Credential handling:** `apiKey` is read from OpenClaw plugin config and sent only in the `Authorization: Bearer` header to the configured base URL.
18
+ - **Data exfiltration:** Contract inputs provided by the user are sent to the MOVA API for processing. No data is forwarded to third parties — MOVA sandbox connectors run inside the MOVA platform.
19
+
20
+ ---
21
+
22
+ ## Configuration
23
+
24
+ Before using any tool, configure the plugin:
25
+
26
+ ```
27
+ openclaw config set plugins.entries.mova.config.apiKey YOUR_MOVA_API_KEY
28
+ ```
29
+
30
+ Optional — override the base URL (for self-hosted or staging):
31
+
32
+ ```
33
+ openclaw config set plugins.entries.mova.config.baseUrl https://your-mova-instance.example.com
34
+ ```
35
+
36
+ Obtain an API key at https://mova-lab.eu/register.
37
+
38
+ ---
39
+
40
+ ## Available tools
41
+
42
+ ### HITL contract workflows
43
+
44
+ | Tool | Purpose |
45
+ |---|---|
46
+ | `mova_hitl_start` | Submit invoice/receipt for OCR extraction + human approval |
47
+ | `mova_hitl_start_po` | Submit purchase order for risk analysis + human approval |
48
+ | `mova_hitl_start_trade` | Submit crypto trade for compliance review + human decision |
49
+ | `mova_hitl_start_aml` | Submit AML alert for L1 triage + human compliance decision |
50
+ | `mova_hitl_start_complaint` | Submit EU customer complaint for classification + human decision |
51
+ | `mova_hitl_start_compliance` | Submit document for GDPR/PCI-DSS/ISO 27001/SOC 2 audit + human gate |
52
+ | `mova_hitl_start_credit` | Submit loan application for credit scoring + human approval |
53
+ | `mova_hitl_start_supply_chain` | Screen supplier list against sanctions/ESG + human approval |
54
+ | `mova_hitl_start_churn` | Predict churn risk for customer segment + human campaign approval |
55
+ | `mova_hitl_start_contract_gen` | Generate legal document (NDA, SLA, etc.) + section-by-section review |
56
+ | `mova_hitl_decide` | Submit human decision for a contract waiting at a gate |
57
+ | `mova_hitl_status` | Get current status of a MOVA contract |
58
+ | `mova_hitl_audit` | Get full audit receipt for a completed contract |
59
+ | `mova_hitl_audit_compact` | Get compact JSONL audit journal (full signed event chain) |
60
+ | `mova_calibrate_intent` | Pre-flight check — identify missing required fields before starting |
61
+
62
+ ### Connector registry
63
+
64
+ | Tool | Purpose |
65
+ |---|---|
66
+ | `mova_list_connectors` | List available MOVA connectors, optionally filter by keyword |
67
+ | `mova_list_connector_overrides` | List connector overrides registered for your org |
68
+ | `mova_register_connector` | Register your HTTPS endpoint for a connector |
69
+ | `mova_delete_connector_override` | Remove a connector override (reverts to MOVA sandbox mock) |
70
+
71
+ ### User contract registry (Phase 4)
72
+
73
+ | Tool | Purpose |
74
+ |---|---|
75
+ | `mova_register_contract` | Register a MOVA contract by source_url + lightweight manifest |
76
+ | `mova_list_my_contracts` | List contracts registered by your org, optional keyword filter |
77
+ | `mova_set_contract_visibility` | Change contract visibility to `private` or `public` |
78
+ | `mova_delete_contract` | Remove a contract registration (source_url file is not affected) |
79
+ | `mova_run_contract` | Execute a registered contract — fetches from source_url, validates, runs agent, returns verdict |
80
+ | `mova_run_status` | Get status and result of a previous contract run by run_id |
81
+
82
+ ---
83
+
84
+ ## Standard HITL workflow (3 steps)
85
+
86
+ **Step 1 — Start**
87
+ Call the appropriate `mova_hitl_start*` tool. Returns either:
88
+ - `status: "waiting_human"` — AI analysis done, human decision required
89
+ - `status: "completed"` — auto-completed (rare for HITL contracts)
90
+
91
+ **Step 2 — Show analysis and request decision**
92
+ Display the analysis, options, and recommended option (if present). Ask the user to choose.
93
+ Call `mova_hitl_decide` with:
94
+ - `contract_id`: from the start response (NOT the business document ID)
95
+ - `option`: chosen decision option ID
96
+ - `reason`: human reasoning for the decision
97
+
98
+ **Step 3 — Show audit receipt**
99
+ Call `mova_hitl_audit` to get the signed audit receipt.
100
+ Call `mova_hitl_audit_compact` for the full compact event journal.
101
+
102
+ ---
103
+
104
+ ## User contract execution workflow
105
+
106
+ **Register a contract:**
107
+ Call `mova_register_contract` with `source_url` (HTTPS URL to a MOVA-spec JSON contract), `title`, `version`, `execution_mode`, and optionally `description`, `required_connectors`, `visibility`.
108
+
109
+ **Run a contract:**
110
+ Call `mova_run_contract` with `contract_id` and `inputs`. The platform fetches the contract JSON from `source_url`, validates it against the MOVA spec, executes the agent, and returns `run_id`, `verdict`, and `output`.
111
+
112
+ **Check run result:**
113
+ Call `mova_run_status` with `run_id`.
114
+
115
+ ---
116
+
117
+ ## Intent calibration
118
+
119
+ When the user's request is ambiguous or fields are missing, call `mova_calibrate_intent` first:
120
+ - `contract_type`: `invoice | po | trade | complaint | aml`
121
+ - `answers`: fields collected so far (empty array on first call)
122
+
123
+ Returns either `ASK` (next required question) or `VALID` (all inputs ready, proceed to start tool).
124
+
125
+ ---
126
+
127
+ ## Rules
128
+
129
+ - NEVER make direct HTTP requests — use MOVA plugin tools only
130
+ - NEVER invent or simulate results — if a tool call fails, show the exact error to the user
131
+ - NEVER use exec, shell, or file system tools — not needed and not permitted
132
+ - `contract_id` comes from `mova_hitl_start*` response, NOT from the business document ID (invoice number, alert ID, etc.)
133
+ - Always confirm with the user before submitting: "Submit [document/alert] to MOVA?"
134
+ - If `apiKey` is not configured, tell the user: `openclaw config set plugins.entries.mova.config.apiKey YOUR_KEY`
@@ -0,0 +1,19 @@
1
+ export interface MovaConfig {
2
+ apiKey: string;
3
+ baseUrl: string;
4
+ }
5
+ export declare function shortId(): string;
6
+ export declare const movaPost: (c: MovaConfig, path: string, body: unknown) => Promise<unknown>;
7
+ export declare const movaGet: (c: MovaConfig, path: string) => Promise<unknown>;
8
+ export declare const movaPut: (c: MovaConfig, path: string, body: unknown) => Promise<unknown>;
9
+ export declare const movaDelete: (c: MovaConfig, path: string) => Promise<unknown>;
10
+ /** Run analyze → verify → decide steps for a started contract.
11
+ * Returns waiting_human (with analysis + options) or completed (with audit). */
12
+ export declare function movaRunSteps(cfg: MovaConfig, contractId: string): Promise<unknown>;
13
+ export declare function toolResult(data: unknown): {
14
+ content: {
15
+ type: "text";
16
+ text: string;
17
+ }[];
18
+ details: unknown;
19
+ };
package/dist/client.js ADDED
@@ -0,0 +1,78 @@
1
+ export function shortId() {
2
+ const buf = new Uint8Array(4);
3
+ crypto.getRandomValues(buf);
4
+ return Array.from(buf).map(b => b.toString(16).padStart(2, "0")).join("");
5
+ }
6
+ async function movaRequest(config, method, path, body) {
7
+ const url = `${config.baseUrl.replace(/\/$/, "")}${path}`;
8
+ const res = await fetch(url, {
9
+ method,
10
+ headers: {
11
+ "Content-Type": "application/json",
12
+ Authorization: `Bearer ${config.apiKey}`,
13
+ },
14
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
15
+ });
16
+ const data = await res.json();
17
+ if (!res.ok) {
18
+ throw new Error(`MOVA API error ${res.status}: ${JSON.stringify(data)}`);
19
+ }
20
+ return data;
21
+ }
22
+ export const movaPost = (c, path, body) => movaRequest(c, "POST", path, body);
23
+ export const movaGet = (c, path) => movaRequest(c, "GET", path);
24
+ export const movaPut = (c, path, body) => movaRequest(c, "PUT", path, body);
25
+ export const movaDelete = (c, path) => movaRequest(c, "DELETE", path);
26
+ /** Run analyze → verify → decide steps for a started contract.
27
+ * Returns waiting_human (with analysis + options) or completed (with audit). */
28
+ export async function movaRunSteps(cfg, contractId) {
29
+ let analysis = null;
30
+ for (const stepId of ["analyze", "verify", "decide"]) {
31
+ const result = await movaPost(cfg, `/api/v1/contracts/${contractId}/step`, {
32
+ envelope: {
33
+ kind: "env.step.execute_v0",
34
+ envelope_id: `env-${shortId()}`,
35
+ contract_id: contractId,
36
+ actor: { actor_type: "system", actor_id: "mova_runtime" },
37
+ payload: { step_id: stepId },
38
+ },
39
+ });
40
+ if (!result.ok)
41
+ return result;
42
+ if (stepId === "analyze") {
43
+ try {
44
+ const output = await movaGet(cfg, `/api/v1/contracts/${contractId}/steps/analyze/output`);
45
+ if (output.ok !== false)
46
+ analysis = output;
47
+ }
48
+ catch { /* non-fatal */ }
49
+ }
50
+ if (result.status === "waiting_human") {
51
+ const dpResp = await movaGet(cfg, `/api/v1/contracts/${contractId}/decision`);
52
+ const dp = (dpResp.decision_point ?? {});
53
+ return {
54
+ ok: true,
55
+ status: "waiting_human",
56
+ contract_id: contractId,
57
+ question: dp.question ?? "Select action:",
58
+ options: dp.options ?? [],
59
+ recommended: dp.recommended_option_id ?? null,
60
+ ...(analysis ? { analysis } : {}),
61
+ };
62
+ }
63
+ }
64
+ const audit = await movaGet(cfg, `/api/v1/contracts/${contractId}/audit`);
65
+ return {
66
+ ok: true,
67
+ status: "completed",
68
+ contract_id: contractId,
69
+ audit_receipt: audit.audit_receipt ?? {},
70
+ ...(analysis ? { analysis } : {}),
71
+ };
72
+ }
73
+ export function toolResult(data) {
74
+ return {
75
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
76
+ details: data,
77
+ };
78
+ }
@@ -0,0 +1,3 @@
1
+ import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk";
2
+ declare const plugin: OpenClawPluginDefinition;
3
+ export default plugin;