venn-cli 0.1.0__tar.gz

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.
@@ -0,0 +1,25 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ unit-tests:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+
21
+ - name: Install dependencies
22
+ run: pip install -e ".[dev]"
23
+
24
+ - name: Run unit tests
25
+ run: pytest -m "not integration" -v
@@ -0,0 +1,30 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: read
10
+ id-token: write
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ environment: pypi
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.13"
22
+
23
+ - name: Install build tools
24
+ run: pip install build
25
+
26
+ - name: Build package
27
+ run: python -m build
28
+
29
+ - name: Publish to PyPI
30
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ *.egg
8
+ .env
venn_cli-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Moda Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.4
2
+ Name: venn-cli
3
+ Version: 0.1.0
4
+ Summary: CLI for the Venn ToolIQ API
5
+ Project-URL: Homepage, https://github.com/moda-labs/venn-cli
6
+ Project-URL: Repository, https://github.com/moda-labs/venn-cli
7
+ Project-URL: Issues, https://github.com/moda-labs/venn-cli/issues
8
+ Author-email: Moda Labs <zach@modalabs.ai>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: click>=8.1
22
+ Requires-Dist: httpx>=0.27
23
+ Requires-Dist: python-dotenv>=1.0
24
+ Requires-Dist: rich>=13.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Requires-Dist: respx>=0.22; extra == 'dev'
venn_cli-0.1.0/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1 @@
1
+ {"openapi":"3.1.0","info":{"title":"ToolIQ REST API","description":"REST API for tool discovery, search, and execution","version":"1.0.0"},"paths":{"/tools/list":{"get":{"summary":"Api List All Tools","description":"List all tools for a server with metadata. Requires one of: slug, directory_id, or instance_id. Returns server name, version, and tool metadata.","operationId":"api_list_all_tools_tools_list_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"directory_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Server directory UUID","title":"Directory Id"},"description":"Server directory UUID"},{"name":"instance_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Server instance UUID","title":"Instance Id"},"description":"Server instance UUID"},{"name":"slug","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Toolset slug (e.g., 'salesforce', 'gmail')","title":"Slug"},"description":"Toolset slug (e.g., 'salesforce', 'gmail')"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListToolsSuccessResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Server not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tools/search":{"post":{"summary":"Api Search Tools","description":"Search for tools across connected MCP servers using semantic similarity. Returns ranked results with scores, supports pagination and filtering.","operationId":"api_search_tools_tools_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchToolsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchToolsSuccessResponse"}}}},"400":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/tools/describe":{"post":{"summary":"Api Describe Tools","description":"Get detailed schema information for one or more tools including inputSchema, description, and write operation metadata.","operationId":"api_describe_tools_tools_describe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DescribeToolsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DescribeToolsSuccessResponse"}}}},"400":{"description":"Invalid request or tool not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tool not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/tools/execute":{"post":{"summary":"Api Execute Tool","description":"Execute a specific tool on a connected MCP server. Supports audit operations with confirmation tokens.","operationId":"api_execute_tool_tools_execute_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteToolRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteToolSuccessResponse"}}}},"400":{"description":"Invalid request or execution failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Server not connected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/tools/execute-workflow":{"post":{"summary":"Api Execute Code","description":"Execute Python code in a sandboxed environment for programmatic tool calling with access to async_call_tool() and async_call_skill() (call sites must `await`).","operationId":"api_execute_code_tools_execute_workflow_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteCodeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteCodeSuccessResponse"}}}},"400":{"description":"Invalid request or code execution failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"408":{"description":"Code execution timeout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/tools/help":{"post":{"summary":"Api Help","description":"Get help information, server status, and authentication URLs. Supports actions: getting_started, connector_help, auth_helper, list_servers.","operationId":"api_help_tools_help_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelpRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HelpSuccessResponse"}}}},"400":{"description":"Invalid action or request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/tools/confirm":{"post":{"summary":"Api Confirm Write Operation","description":"Get a confirmation token for executing write operations.\n\nRequest body: {} (no parameters required)\n\nAuthentication:\n Requires Bearer token in Authorization header","operationId":"api_confirm_write_operation_tools_confirm_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmWriteOperationSuccessResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/skills":{"post":{"summary":"Api Upsert Skill","description":"Create or update an executable skill. Writes the YAML to disk and reloads the index.\n\nThis endpoint is intended for local development use (e.g., from the create-skill CLI command).\nDeployed environments must opt in explicitly with TOOL_ROUTER_SKILL_UPSERT_ENABLED.","operationId":"api_upsert_skill_skills_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSkillRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Endpoint disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"Invalid skill YAML","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/toolset/{toolset_key}/history":{"get":{"summary":"Api List Catalog History","description":"Catalog (YAML) history for a 1st-party toolset, newest first.","operationId":"api_list_catalog_history_toolset__toolset_key__history_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"toolset_key","in":"path","required":true,"schema":{"type":"string","title":"Toolset Key"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"before_version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Before Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogHistorySuccessResponse"}}}},"404":{"description":"Toolset has no catalog history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"History unavailable — DB temporarily unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/server/{directory_id}/history":{"get":{"summary":"Api List Server History","description":"Per-server-instance history, newest first. Works for any connected\nserver including 3rd-party — caller must supply `directory_id`.","operationId":"api_list_server_history_server__directory_id__history_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"directory_id","in":"path","required":true,"schema":{"type":"string","title":"Directory Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"before_version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Before Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerHistorySuccessResponse"}}}},"404":{"description":"No history for this directory_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"History unavailable — DB temporarily unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"CatalogHistoryData":{"properties":{"toolset_key":{"type":"string","title":"Toolset Key"},"revisions":{"items":{"$ref":"#/components/schemas/RevisionSummary"},"type":"array","title":"Revisions"}},"type":"object","required":["toolset_key","revisions"],"title":"CatalogHistoryData","description":"Data returned by /toolset/{toolset_key}/history endpoint."},"CatalogHistorySuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"$ref":"#/components/schemas/CatalogHistoryData"}},"type":"object","required":["result"],"title":"CatalogHistorySuccessResponse","description":"Success response for /toolset/{toolset_key}/history."},"ConfirmWriteOperationData":{"properties":{"confirmation_token":{"type":"string","title":"Confirmation Token"},"expires_in_seconds":{"type":"integer","title":"Expires In Seconds"},"usage":{"type":"string","title":"Usage"},"important":{"type":"string","title":"Important"}},"type":"object","required":["confirmation_token","expires_in_seconds","usage","important"],"title":"ConfirmWriteOperationData","description":"Data returned by confirm_write_operation endpoint."},"ConfirmWriteOperationSuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"$ref":"#/components/schemas/ConfirmWriteOperationData"}},"type":"object","required":["result"],"title":"ConfirmWriteOperationSuccessResponse","description":"Success response for /tools/confirm endpoint."},"DescribeToolsData":{"properties":{"results":{"items":{"$ref":"#/components/schemas/ToolDetailsData"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"DescribeToolsData","description":"Data returned by describe_tools endpoint."},"DescribeToolsRequest":{"properties":{"tools":{"items":{"$ref":"#/components/schemas/ToolIdentifier"},"type":"array","title":"Tools","description":"List of tool identifiers"},"refresh":{"type":"boolean","title":"Refresh","description":"Bypass cache","default":false}},"type":"object","required":["tools"],"title":"DescribeToolsRequest"},"DescribeToolsSuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"$ref":"#/components/schemas/DescribeToolsData"}},"type":"object","required":["result"],"title":"DescribeToolsSuccessResponse","description":"Success response for /tools/describe endpoint."},"ErrorResponse":{"properties":{"success":{"type":"boolean","const":false,"title":"Success","default":false},"version":{"type":"string","title":"Version"},"error":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"}],"title":"Error","description":"Error message or structured error details"}},"type":"object","required":["error"],"title":"ErrorResponse","description":"Response model for error responses."},"ExecuteCodeData":{"properties":{"result":{"title":"Result"}},"type":"object","required":["result"],"title":"ExecuteCodeData","description":"Data returned by execute_code endpoint."},"ExecuteCodeRequest":{"properties":{"code":{"type":"string","title":"Code","description":"Python code to execute"},"timeout":{"type":"integer","maximum":360.0,"minimum":1.0,"title":"Timeout","description":"Maximum execution time in seconds","default":180},"confirmed":{"type":"boolean","title":"Confirmed","description":"For write operations, set to True after user approval","default":false},"confirmation_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Confirmation Token","description":"Required when confirmed=True"}},"type":"object","required":["code"],"title":"ExecuteCodeRequest"},"ExecuteCodeSuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"$ref":"#/components/schemas/ExecuteCodeData"}},"type":"object","required":["result"],"title":"ExecuteCodeSuccessResponse","description":"Success response for /tools/execute-code endpoint."},"ExecuteToolRequest":{"properties":{"server_id":{"type":"string","title":"Server Id","description":"Server identifier"},"tool_name":{"type":"string","title":"Tool Name","description":"Tool name"},"tool_args":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Tool Args","description":"Tool arguments"},"refresh":{"type":"boolean","title":"Refresh","description":"Bypass cache","default":false},"confirmed":{"type":"boolean","title":"Confirmed","description":"For write operations, set to True after user approval","default":false},"confirmation_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Confirmation Token","description":"Required when confirmed=True"}},"type":"object","required":["server_id","tool_name"],"title":"ExecuteToolRequest"},"ExecuteToolSuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"title":"Result"}},"type":"object","required":["result"],"title":"ExecuteToolSuccessResponse","description":"Success response for /tools/execute endpoint."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HelpRequest":{"properties":{"action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action","description":"Help action: getting_started, connector_help, auth_helper, list_servers"},"server_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Server Id","description":"Server identifier (required for auth_helper)"},"refresh":{"type":"boolean","title":"Refresh","description":"Bypass cache","default":false}},"type":"object","title":"HelpRequest"},"HelpSuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{"additionalProperties":true,"type":"object"},"type":"array"}],"title":"Result"}},"type":"object","required":["result"],"title":"HelpSuccessResponse","description":"Success response for /tools/help endpoint."},"ListToolsData":{"properties":{"name":{"type":"string","title":"Name"},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug"},"toolset_version":{"type":"string","title":"Toolset Version"},"tools":{"items":{"$ref":"#/components/schemas/ToolMetadata"},"type":"array","title":"Tools"},"instance_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instance Id"},"directory_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Directory Id"}},"type":"object","required":["name","slug","toolset_version","tools","instance_id","directory_id"],"title":"ListToolsData","description":"Data returned by list_tools endpoint."},"ListToolsSuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"$ref":"#/components/schemas/ListToolsData"}},"type":"object","required":["result"],"title":"ListToolsSuccessResponse","description":"Success response for /tools/list endpoint."},"RevisionSummary":{"properties":{"version":{"type":"integer","title":"Version"},"transaction_id":{"type":"string","title":"Transaction Id"},"issued_at":{"type":"string","format":"date-time","title":"Issued At"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"summary":{"additionalProperties":{"type":"integer"},"type":"object","title":"Summary"}},"type":"object","required":["version","transaction_id","issued_at","summary"],"title":"RevisionSummary","description":"A single revision in a toolset's or server's history.\n\n`version` is a 0-indexed counter scoped to the slice (toolset_key OR\ndirectory_id; v0 = oldest revision in that slice). `transaction_id` is\nthe underlying global Continuum transaction id, exposed for debugging."},"SearchToolsData":{"properties":{"candidates":{"items":{"anyOf":[{"$ref":"#/components/schemas/ToolCandidate"},{"$ref":"#/components/schemas/SkillCandidate"}]},"type":"array","title":"Candidates"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["candidates","total","limit","offset"],"title":"SearchToolsData","description":"Data returned by search_tools endpoint.\n\nReturns a unified list of tools and skills ranked by relevance.\nEach candidate has a 'type' field to distinguish between tools and skills."},"SearchToolsRequest":{"properties":{"query":{"type":"string","title":"Query","description":"Search query text"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","description":"Maximum number of results","default":10},"offset":{"type":"integer","minimum":0.0,"title":"Offset","description":"Number of results to skip","default":0},"min_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Score","description":"Minimum similarity score threshold","default":0.3},"min_results":{"type":"integer","minimum":0.0,"title":"Min Results","description":"Minimum results to return even if below threshold","default":5},"refresh":{"type":"boolean","title":"Refresh","description":"Bypass cache to get updated servers","default":false}},"type":"object","required":["query"],"title":"SearchToolsRequest"},"SearchToolsSuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"$ref":"#/components/schemas/SearchToolsData"}},"type":"object","required":["result"],"title":"SearchToolsSuccessResponse","description":"Success response for /tools/search endpoint."},"ServerHistoryData":{"properties":{"directory_id":{"type":"string","title":"Directory Id"},"revisions":{"items":{"$ref":"#/components/schemas/RevisionSummary"},"type":"array","title":"Revisions"}},"type":"object","required":["directory_id","revisions"],"title":"ServerHistoryData","description":"Data returned by /server/{directory_id}/history endpoint."},"ServerHistorySuccessResponse":{"properties":{"success":{"type":"boolean","const":true,"title":"Success","default":true},"version":{"type":"string","title":"Version"},"result":{"$ref":"#/components/schemas/ServerHistoryData"}},"type":"object","required":["result"],"title":"ServerHistorySuccessResponse","description":"Success response for /server/{directory_id}/history."},"SkillCandidate":{"properties":{"type":{"type":"string","const":"skill","title":"Type","default":"skill"},"rank":{"type":"integer","title":"Rank"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"}},"type":"object","required":["rank","name","description"],"title":"SkillCandidate","description":"Lightweight skill summary in search results.\n\nReturns minimal information to save context tokens.\nUse describe_skill tool to retrieve full pattern content."},"ToolCandidate":{"properties":{"type":{"type":"string","const":"tool","title":"Type","default":"tool"},"rank":{"type":"integer","title":"Rank"},"server_id":{"type":"string","title":"Server Id"},"server_name":{"type":"string","title":"Server Name"},"tool_name":{"type":"string","title":"Tool Name"},"short_description":{"type":"string","title":"Short Description"},"server_connected":{"type":"boolean","title":"Server Connected"},"annotations":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Annotations"}},"type":"object","required":["rank","server_id","server_name","tool_name","short_description","server_connected"],"title":"ToolCandidate","description":"Individual tool in search results."},"ToolDetailsData":{"properties":{"server_id":{"type":"string","title":"Server Id"},"server_name":{"type":"string","title":"Server Name"},"tool_name":{"type":"string","title":"Tool Name"},"description":{"type":"string","title":"Description"},"extended_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extended Description"},"inputSchema":{"additionalProperties":true,"type":"object","title":"Inputschema"},"outputSchema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Outputschema"},"write_operation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Write Operation"},"preview_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview Template"},"annotations":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Annotations"}},"type":"object","required":["server_id","server_name","tool_name","description","inputSchema"],"title":"ToolDetailsData","description":"Detailed schema information for a single tool."},"ToolIdentifier":{"properties":{"server_id":{"type":"string","title":"Server Id","description":"Server identifier"},"tool_name":{"type":"string","title":"Tool Name","description":"Tool name"}},"type":"object","required":["server_id","tool_name"],"title":"ToolIdentifier"},"ToolMetadata":{"properties":{"tool_name":{"type":"string","title":"Tool Name"},"readable_name":{"type":"string","title":"Readable Name"},"short_description":{"type":"string","title":"Short Description"},"crud_operation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crud Operation"},"status":{"type":"string","title":"Status"},"risk_level":{"type":"integer","title":"Risk Level"},"audit":{"type":"boolean","title":"Audit"},"paywalled":{"type":"boolean","title":"Paywalled"}},"type":"object","required":["tool_name","readable_name","short_description","crud_operation","status","risk_level","audit","paywalled"],"title":"ToolMetadata","description":"Metadata for a single tool in a toolset."},"UpsertSkillRequest":{"properties":{"content":{"type":"string","title":"Content","description":"Full YAML content of the skill file"}},"type":"object","required":["content"],"title":"UpsertSkillRequest","description":"Request body for POST /skills — create or update an executable skill."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"JWT Bearer token from Barndoor platform","scheme":"bearer"}}},"servers":[{"url":"/tooliq/api","description":"ToolIQ REST API"}]}
@@ -0,0 +1,52 @@
1
+ [project]
2
+ name = "venn-cli"
3
+ version = "0.1.0"
4
+ description = "CLI for the Venn ToolIQ API"
5
+ requires-python = ">=3.11"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "Moda Labs", email = "zach@modalabs.ai" },
9
+ ]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Environment :: Console",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Software Development",
20
+ ]
21
+ dependencies = [
22
+ "click>=8.1",
23
+ "httpx>=0.27",
24
+ "rich>=13.0",
25
+ "python-dotenv>=1.0",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/moda-labs/venn-cli"
30
+ Repository = "https://github.com/moda-labs/venn-cli"
31
+ Issues = "https://github.com/moda-labs/venn-cli/issues"
32
+
33
+ [project.scripts]
34
+ venn = "venn_cli.cli:main"
35
+
36
+ [project.optional-dependencies]
37
+ dev = [
38
+ "pytest>=8.0",
39
+ "respx>=0.22",
40
+ ]
41
+
42
+ [build-system]
43
+ requires = ["hatchling"]
44
+ build-backend = "hatchling.build"
45
+
46
+ [tool.pytest.ini_options]
47
+ markers = [
48
+ "integration: hits the live Venn API (requires VENN_API_KEY)",
49
+ ]
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["src/venn_cli"]
File without changes
@@ -0,0 +1,265 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import click
9
+ from dotenv import load_dotenv
10
+
11
+ from venn_cli.client import VennClient
12
+ from venn_cli import output
13
+
14
+
15
+ def _load_env() -> None:
16
+ for p in [Path.cwd() / ".env", Path(__file__).resolve().parents[2] / ".env"]:
17
+ if p.exists():
18
+ load_dotenv(p)
19
+ return
20
+ load_dotenv()
21
+
22
+
23
+ def _client(ctx: click.Context) -> VennClient:
24
+ return ctx.obj["client"]
25
+
26
+
27
+ @click.group()
28
+ @click.option("--api-key", envvar="VENN_API_KEY", help="Venn API key (or set VENN_API_KEY)")
29
+ @click.option("--base-url", envvar="VENN_BASE_URL", default=None, help="Override API base URL")
30
+ @click.option("--raw", is_flag=True, help="Output raw JSON instead of formatted tables")
31
+ @click.version_option(package_name="venn-cli")
32
+ @click.pass_context
33
+ def main(ctx: click.Context, api_key: str | None, base_url: str | None, raw: bool) -> None:
34
+ """Venn ToolIQ CLI — discover, inspect, and execute tools."""
35
+ _load_env()
36
+ api_key = api_key or os.environ.get("VENN_API_KEY")
37
+ if not api_key:
38
+ click.echo("Error: VENN_API_KEY not set. Pass --api-key or add it to .env", err=True)
39
+ raise SystemExit(1)
40
+ kwargs = {"api_key": api_key}
41
+ if base_url:
42
+ kwargs["base_url"] = base_url
43
+ ctx.ensure_object(dict)
44
+ ctx.obj["client"] = VennClient(**kwargs)
45
+ ctx.obj["raw"] = raw
46
+
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # venn tools
50
+ # ---------------------------------------------------------------------------
51
+
52
+ @main.group()
53
+ def tools():
54
+ """Discover, inspect, and execute tools."""
55
+
56
+
57
+ @tools.command("list")
58
+ @click.option("--slug", "-s", help="Toolset slug (e.g. 'salesforce', 'gmail')")
59
+ @click.option("--directory-id", "-d", help="Server directory UUID")
60
+ @click.option("--instance-id", "-i", help="Server instance UUID")
61
+ @click.pass_context
62
+ def tools_list(ctx, slug, directory_id, instance_id):
63
+ """List tools for a server."""
64
+ if not any([slug, directory_id, instance_id]):
65
+ click.echo("Provide at least one of: --slug, --directory-id, --instance-id", err=True)
66
+ raise SystemExit(1)
67
+ data = _client(ctx).list_tools(slug=slug, directory_id=directory_id, instance_id=instance_id)
68
+ if ctx.obj["raw"]:
69
+ output.print_json(data)
70
+ else:
71
+ output.print_tool_list(data.get("result", {}))
72
+
73
+
74
+ @tools.command("search")
75
+ @click.argument("query")
76
+ @click.option("--limit", "-n", default=10, type=int, help="Max results")
77
+ @click.option("--offset", default=0, type=int, help="Skip N results")
78
+ @click.option("--min-score", default=0.3, type=float, help="Minimum similarity score")
79
+ @click.option("--refresh", is_flag=True, help="Bypass cache")
80
+ @click.pass_context
81
+ def tools_search(ctx, query, limit, offset, min_score, refresh):
82
+ """Search tools by natural language query."""
83
+ data = _client(ctx).search_tools(query, limit=limit, offset=offset, min_score=min_score, refresh=refresh)
84
+ if ctx.obj["raw"]:
85
+ output.print_json(data)
86
+ else:
87
+ output.print_search_results(data.get("result", {}))
88
+
89
+
90
+ @tools.command("describe")
91
+ @click.option("--server-id", "-s", required=True, help="Server identifier")
92
+ @click.option("--tool-name", "-t", required=True, multiple=True, help="Tool name (repeatable)")
93
+ @click.option("--refresh", is_flag=True, help="Bypass cache")
94
+ @click.pass_context
95
+ def tools_describe(ctx, server_id, tool_name, refresh):
96
+ """Get detailed schema for one or more tools."""
97
+ tools_list = [{"server_id": server_id, "tool_name": t} for t in tool_name]
98
+ data = _client(ctx).describe_tools(tools_list, refresh=refresh)
99
+ if ctx.obj["raw"]:
100
+ output.print_json(data)
101
+ else:
102
+ output.print_tool_details(data.get("result", {}).get("results", []))
103
+
104
+
105
+ @tools.command("execute")
106
+ @click.option("--server-id", "-s", required=True, help="Server identifier")
107
+ @click.option("--tool-name", "-t", required=True, help="Tool name")
108
+ @click.option("--args", "-a", "tool_args", default=None, help="Tool arguments as JSON string")
109
+ @click.option("--confirm", "do_confirm", is_flag=True, help="Auto-obtain confirmation token for write ops")
110
+ @click.pass_context
111
+ def tools_execute(ctx, server_id, tool_name, tool_args, do_confirm):
112
+ """Execute a tool."""
113
+ client = _client(ctx)
114
+ parsed_args = json.loads(tool_args) if tool_args else None
115
+
116
+ confirmation_token = None
117
+ if do_confirm:
118
+ confirm_data = client.confirm_write()
119
+ confirmation_token = confirm_data.get("result", {}).get("confirmation_token")
120
+
121
+ data = client.execute_tool(
122
+ server_id=server_id,
123
+ tool_name=tool_name,
124
+ tool_args=parsed_args,
125
+ confirmed=do_confirm,
126
+ confirmation_token=confirmation_token,
127
+ )
128
+ if ctx.obj["raw"]:
129
+ output.print_json(data)
130
+ else:
131
+ output.print_execute_result(data)
132
+
133
+
134
+ @tools.command("confirm")
135
+ @click.pass_context
136
+ def tools_confirm(ctx):
137
+ """Get a confirmation token for write operations."""
138
+ data = _client(ctx).confirm_write()
139
+ if ctx.obj["raw"]:
140
+ output.print_json(data)
141
+ else:
142
+ output.print_confirm(data.get("result", {}))
143
+
144
+
145
+ # ---------------------------------------------------------------------------
146
+ # venn workflow
147
+ # ---------------------------------------------------------------------------
148
+
149
+ @main.group()
150
+ def workflow():
151
+ """Execute code in a sandboxed environment."""
152
+
153
+
154
+ @workflow.command("run")
155
+ @click.option("--code", "-c", help="Python code to execute")
156
+ @click.option("--file", "-f", "code_file", type=click.Path(exists=True), help="Read code from file")
157
+ @click.option("--timeout", default=180, type=int, help="Max execution time in seconds")
158
+ @click.option("--confirm", "do_confirm", is_flag=True, help="Obtain confirmation for write ops")
159
+ @click.pass_context
160
+ def workflow_run(ctx, code, code_file, timeout, do_confirm):
161
+ """Execute Python code in the Venn sandbox."""
162
+ if code_file:
163
+ code = Path(code_file).read_text()
164
+ if not code:
165
+ click.echo("Provide --code or --file", err=True)
166
+ raise SystemExit(1)
167
+
168
+ client = _client(ctx)
169
+ confirmation_token = None
170
+ if do_confirm:
171
+ confirm_data = client.confirm_write()
172
+ confirmation_token = confirm_data.get("result", {}).get("confirmation_token")
173
+
174
+ data = client.execute_workflow(
175
+ code=code,
176
+ timeout=timeout,
177
+ confirmed=do_confirm,
178
+ confirmation_token=confirmation_token,
179
+ )
180
+ if ctx.obj["raw"]:
181
+ output.print_json(data)
182
+ else:
183
+ output.print_execute_result(data)
184
+
185
+
186
+ # ---------------------------------------------------------------------------
187
+ # venn help
188
+ # ---------------------------------------------------------------------------
189
+
190
+ @main.command("help")
191
+ @click.argument("action", required=False, type=click.Choice(
192
+ ["getting_started", "connector_help", "auth_helper", "list_servers"],
193
+ case_sensitive=False,
194
+ ))
195
+ @click.option("--server-id", "-s", help="Server ID (required for auth_helper)")
196
+ @click.option("--refresh", is_flag=True, help="Bypass cache")
197
+ @click.pass_context
198
+ def help_cmd(ctx, action, server_id, refresh):
199
+ """Get help, server status, or auth URLs."""
200
+ data = _client(ctx).help(action=action, server_id=server_id, refresh=refresh)
201
+ if ctx.obj["raw"]:
202
+ output.print_json(data)
203
+ else:
204
+ output.print_help_result(data.get("result"))
205
+
206
+
207
+ # ---------------------------------------------------------------------------
208
+ # venn skills
209
+ # ---------------------------------------------------------------------------
210
+
211
+ @main.group()
212
+ def skills():
213
+ """Manage executable skills."""
214
+
215
+
216
+ @skills.command("upsert")
217
+ @click.option("--file", "-f", "skill_file", required=True, type=click.Path(exists=True), help="Skill YAML file")
218
+ @click.pass_context
219
+ def skills_upsert(ctx, skill_file):
220
+ """Create or update a skill from a YAML file."""
221
+ content = Path(skill_file).read_text()
222
+ data = _client(ctx).upsert_skill(content)
223
+ if ctx.obj["raw"]:
224
+ output.print_json(data)
225
+ else:
226
+ output.console.print("[green]Skill upserted successfully.[/green]")
227
+ if data.get("result"):
228
+ output.print_json(data["result"])
229
+
230
+
231
+ # ---------------------------------------------------------------------------
232
+ # venn history
233
+ # ---------------------------------------------------------------------------
234
+
235
+ @main.group()
236
+ def history():
237
+ """View catalog and server revision history."""
238
+
239
+
240
+ @history.command("toolset")
241
+ @click.argument("toolset_key")
242
+ @click.option("--limit", "-n", default=50, type=int, help="Max revisions")
243
+ @click.option("--before", "before_version", default=None, type=int, help="Only show versions before this")
244
+ @click.pass_context
245
+ def history_toolset(ctx, toolset_key, limit, before_version):
246
+ """Show revision history for a toolset."""
247
+ data = _client(ctx).toolset_history(toolset_key, limit=limit, before_version=before_version)
248
+ if ctx.obj["raw"]:
249
+ output.print_json(data)
250
+ else:
251
+ output.print_history(data.get("result", {}))
252
+
253
+
254
+ @history.command("server")
255
+ @click.argument("directory_id")
256
+ @click.option("--limit", "-n", default=50, type=int, help="Max revisions")
257
+ @click.option("--before", "before_version", default=None, type=int, help="Only show versions before this")
258
+ @click.pass_context
259
+ def history_server(ctx, directory_id, limit, before_version):
260
+ """Show revision history for a server instance."""
261
+ data = _client(ctx).server_history(directory_id, limit=limit, before_version=before_version)
262
+ if ctx.obj["raw"]:
263
+ output.print_json(data)
264
+ else:
265
+ output.print_history(data.get("result", {}))