Install
openclaw skills install vennSearch, describe, and execute enterprise tools (Jira, Salesforce, Gmail, Slack, Google Calendar, Google Drive, GitHub, Notion, Box, etc.) via the Venn tool-router REST API. Use when the user asks to: (1) query or search data in enterprise SaaS apps, (2) create, update, or manage records (tickets, emails, calendar events, documents), (3) automate multi-step workflows across connected services, or (4) check what integrations are available. Triggers on phrases like "check my Jira tickets", "search Slack", "create a Salesforce lead", "find emails from X", "sync data between apps", or any reference to connected enterprise tools.
openclaw skills install vennConnect to enterprise SaaS tools through the Venn platform REST API.
This skill is gated on VENN_API_KEY — it won't appear until the key is set.
Get your API key from app.venn.ai
Add it to the OpenClaw .env file:
echo 'VENN_API_KEY=your-api-key-here' >> ~/.openclaw/.env
Restart the gateway (picks up the new env on start):
openclaw gateway restart
Or, for zero-downtime reload without restart:
openclaw secrets reload
Alternatively, use the interactive secrets helper:
openclaw secrets configure --skip-provider-setup
Sandboxed agents: The .env file injects into the host process only. For sandboxed (Docker) sessions, also add VENN_API_KEY to agents.defaults.sandbox.docker.env in openclaw.json, or bake it into your custom sandbox image.
VENN_API_KEY (required) — your Venn API keyVENN_API_URL (optional) — defaults to https://app.venn.ai/api/tooliqAll requests use POST with JSON. Examples below use this shorthand:
# Full form (shown once):
VENN_URL="${VENN_API_URL:-https://app.venn.ai/api/tooliq}"
curl -s -X POST "${VENN_URL}/tools/search" \
-H "Authorization: Bearer ${VENN_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"query": "..."}'
# Shorthand (used throughout):
# POST /tools/search {"query": "..."}
# POST /tools/help
{"action": "list_servers"}
Returns result.servers[] with server_id, name, and connection_status.
Other help actions:
getting_started — onboarding guidanceconnector_help — info on connectors (pass server_id for specific one)auth_helper — OAuth re-auth URL for disconnected server (requires server_id)# POST /tools/search
{"query": "jira search issues", "limit": 10}
Returns result.candidates[] with server_id, tool_name, short_description, and (for top results) full inputSchema.
Additional parameters: offset, min_score (0–1, default 0.3), min_results (default 5), include_skills (default true).
Search strategy — broad first, narrow if needed:
Start with the full task description in natural language (skills match better):
If no skill matches, decompose into one search per platform + action:
For simple single-platform tasks, search directly: "create salesforce lead"
Splitting rules:
If no results, try alternate names:
Choosing from results:
type="skill"), prefer it over assembling toolsinputSchema is the source of truth for parameter names — NEVER guessFor platform-specific query syntax (JQL, SOQL, Gmail search), see references/query-syntax.md.
# POST /tools/describe
{"tools": [{"server_id": "SERVER_ID", "tool_name": "TOOL_NAME"}]}
Supports batch requests. Returns result.results[] with inputSchema, description, and write_operation type.
Copy parameter names verbatim from inputSchema — casing matters
maxResults → use maxResults, NOT max_resultsMatch data types exactly:
"type": "string" → "10", NOT 10"type": "integer" → 10, NOT "10""type": "array" → ["value"], NOT "value""type": "object" → {"key": "value"}, NOT "key=value"Include all required fields. Do not add fields not in the schema.
# POST /tools/execute
{"server_id": "SERVER_ID", "tool_name": "TOOL_NAME", "tool_args": {...}}
Translating user intent into values (infer rather than ask):
userId: "me"This applies to values only — parameter names and types must come from inputSchema.
Data integrity: NEVER fabricate data. Only present what appears in actual responses.
Handling links: For create/edit operations, surface clickable URLs from fields like url, link, href, web_url, permalink, html_url. Present as [Resource Name](url).
Chain multiple tool calls in a Python sandbox:
# POST /tools/execute-workflow
{
"code": "results = call_tool(\"atlassian\", \"searchByJQL\", jql=\"assignee = currentUser() AND status != Done\")\nreturn [{\"key\": i[\"key\"], \"summary\": i[\"fields\"][\"summary\"]} for i in results.get(\"issues\", [])]",
"timeout": 180
}
When to use workflows:
Code rules:
if isinstance(result, dict) and "error" in result: ...nextPageToken/cursorAvailable in sandbox:
call_tool(server_id, tool_name, **kwargs) — sequentialasync_call_tool(server_id, tool_name, **kwargs) — for asyncio.gather()call_skill(skill_id, inputs_dict) / async_call_skill(...) — call skillsasyncio, json, datetime, math, re, collections, itertools, functools, operator, decimal, uuid, base64, hashlibd[k] = d[k] + 1, NOT d[k] += 1Write/delete operations return an audit response instead of executing. To proceed:
Show the operation summary to the user and wait for explicit approval
Get a confirmation token (expires in 60s):
# POST /tools/confirm
{"server_id": "SERVER_ID", "tool_name": "TOOL_NAME"}
Re-send with the token:
# POST /tools/execute
{"server_id": "...", "tool_name": "...", "tool_args": {...}, "confirmed": true, "confirmation_token": "TOKEN"}
Never call confirm without user's typed approval ("yes", "confirm", "proceed").
Skills are pre-built workflow patterns in search results with type: "skill". Prefer skills over assembling individual tools.
Marked executable: true. Run step-by-step:
# POST /tools/execute
{"tool_name": "SKILL_ID", "tool_args": {"step_id": "FIRST_STEP", "inputs": {...}}}
Each step returns outputs and next. If next is not null, read next.reasoning, fill placeholders, make the next call.
For skills without executable: true, describe to get the pattern:
# POST /tools/describe
{"tools": [{"tool_name": "SKILL_NAME"}]}
Returns tools_involved, all_servers_connected, disconnected_servers, and step-by-step content. If all_servers_connected is false, use help(action="auth_helper") first.
If a tool call fails, debug and retry — do not report failure immediately.
| Error | Action |
|---|---|
| Schema/parameter error | Re-read inputSchema, fix names and types, retry |
| 404 / "not found" | Wrong ID or tool; search for correct ID |
| Server not connected / 401 | Call help(action="auth_helper", server_id="...") |
| Empty results | Try fuzzy variations, broader date ranges |
| Same error twice | Try different approach (different tool/parameters) |
| Workflow fails twice | Fall back to sequential execute calls |
Only report failure after at least three different approaches have been tried.
list_servers or search to discover what's connectedinputSchema before executing (from search or describe)session_id and user_intent on calls for tracing (API generates one if omitted)