Quick Start: 5 Minutes
Get Matimo up and running in 5 minutes. Available in TypeScript and Python.
Python SDK
Section titled “Python SDK”Path D: Python Quick Start
Section titled “Path D: Python Quick Start”Install:
pip install matimo# or with uvuv add matimoUse pre-built tools immediately:
pip install matimo matimo-slack matimo-githubimport asynciofrom matimo import Matimo
async def main(): # Load all installed provider packages automatically matimo = await Matimo.init(auto_discover=True)
# Execute a Slack tool result = await matimo.execute('slack_send_channel_message', { 'channel': '#general', 'text': 'Hello from Matimo!', }) print('Message sent!', result)
asyncio.run(main())Tool Naming
You’ll notice Matimo tools use bothkebab-case(e.g.,slack-send-message) andsnake_case(e.g.,slack_send_channel_message).
Both work identically, legacy tools use kebab-case, newer tools use snake_case.
Recommended for new tools:snake_casefollowing{provider}_{action}(e.g.,notion_create_page).
Build your own Python tool (5 min):
Most tools are a single YAML file that describes an HTTP call, no code. This one calls the public JSONPlaceholder test API.
1. Create tools/get_user/definition.yaml:
name: get_userdescription: Look up a user by id on the JSONPlaceholder test APIversion: '1.0.0'
parameters: id: type: number required: true description: User id (1-10)
execution: type: http method: GET url: 'https://jsonplaceholder.typicode.com/users/{id}'
output_schema: type: object properties: name: type: string email: type: string2. Create main.py:
import asynciofrom matimo import Matimo
async def main(): matimo = await Matimo.init('./tools', log_level='warn') print(f"Loaded {len(matimo.list_tools())} tools")
user = await matimo.execute('get_user', {'id': 1}) print('', user['name'], '-', user['email'])
asyncio.run(main())3. Run it:
python main.py# Loaded 1 tools# Leanne Graham - Sincere@april.bizA Python HTTP tool returns the parsed response body.
Python next steps:
- SDK Patterns (Python): factory, decorator, LangChain
- LangChain Integration
- Examples →
TypeScript SDK
Section titled “TypeScript SDK”Choose Your Path
Section titled “Choose Your Path”Not sure where to start? Pick one:
Path A: Use Pre-Built Tools (Fastest: 2 mins)
Section titled “Path A: Use Pre-Built Tools (Fastest: 2 mins)”You want to execute existing tools (Slack, Gmail, GitHub, etc.) without building your own.
Install:
npm install matimo @matimo/slack @matimo/gmailUse immediately:
import { MatimoInstance } from 'matimo';
const matimo = await MatimoInstance.init({ autoDiscover: true });
// Execute a Slack toolconst result = await matimo.execute('slack-send-message', { channel: '#general', text: 'Hello from Matimo!',});
console.log('Message sent!', result);Tool Naming
Matimo supports bothkebab-caseandsnake_casetool names. Legacy tools (Gmail, GitHub, older Slack) usekebab-case(e.g.,slack-send-message), while newer tools usesnake_case(e.g.,bruno_run_request,matimo_create_tool).
Recommended: Usesnake_casefor new tools following{provider}_{action}.
Great for: Using existing integrations in your app See All Available Tools →
Path B: Build Your Own Tool (Educational: 5 mins)
Section titled “Path B: Build Your Own Tool (Educational: 5 mins)”You want to understand how to create and execute custom tools.
Continue below to create your first tool →
Great for: Learning how Matimo works Build Your First Tool →
Path C: Integrate with LangChain (Advanced: 10 mins)
Section titled “Path C: Integrate with LangChain (Advanced: 10 mins)”You want to use Matimo tools with an AI agent (LangChain, CrewAI, etc.).
Great for: Building intelligent agents Examples →
1. Installation (1 min)
Section titled “1. Installation (1 min)”npm install matimo# or with pnpmpnpm add matimo2. Create Your First Script (3 min)
Section titled “2. Create Your First Script (3 min)”Create a file demo.ts:
import { MatimoInstance } from 'matimo';
async function main() { // Initialize Matimo with your tools const matimo = await MatimoInstance.init('./tools');
// List available tools const tools = matimo.listTools(); console.log(`Loaded ${tools.length} tools`);
// Execute a tool const result = (await matimo.execute('get_user', { id: 1 })) as { data: { name: string; email: string }; };
console.log('', result.data.name, '-', result.data.email);}
main().catch(console.error);3. Create Your First Tool (1 min)
Section titled “3. Create Your First Tool (1 min)”Create tools/get_user/definition.yaml, an HTTP tool, Matimo’s default kind, which needs no code:
name: get_userdescription: Look up a user by id on the JSONPlaceholder test APIversion: '1.0.0'
parameters: id: type: number required: true description: User id (1-10)
execution: type: http method: GET url: 'https://jsonplaceholder.typicode.com/users/{id}'
output_schema: type: object properties: name: type: string email: type: string4. Run It (< 1 min)
Section titled “4. Run It (< 1 min)”# Compile TypeScriptnpx tsc demo.ts
# Run the scriptnode demo.js
# Output:# Loaded 1 tools# Leanne Graham - Sincere@april.bizA TypeScript HTTP tool returns { success, data, statusCode, headers }, with the response body in data.
What Just Happened?
Section titled “What Just Happened?”- MatimoInstance.init(‘./tools’): Loaded every
definition.yamlunder./tools - matimo.listTools(): Listed discovered tools
- matimo.execute(‘get_user’, { id: 1 }): The policy engine classified the call (a GET is low risk, so it runs without asking), Matimo filled
{id}into the URL, made the request and returned the result
The MATIMO_APPROVAL_SECRET warning
Section titled “The MATIMO_APPROVAL_SECRET warning”On a first run both SDKs log No MATIMO_APPROVAL_SECRET set. It is a warning, not an error. Matimo signs approvals with that secret, and without one it makes a temporary secret for the process, so approvals do not survive a restart. For local experiments you can ignore it. Before you rely on approvals, set a long random value (export MATIMO_APPROVAL_SECRET=...). It is required when NODE_ENV or MATIMO_ENV is production.
Tools that ask first
Section titled “Tools that ask first”In 0.2.0 some calls wait for a person: tools whose YAML says requires_approval: true, HTTP DELETE tools, and type: command tools (unless they say requires_approval: false). Give the instance a reviewer, or those calls are refused:
const matimo = await MatimoInstance.init({ toolPaths: ['./tools'], onApproval: async (request) => confirmWithUser(request.toolName, request.params),});async def on_approval(request) -> bool: return await confirm_with_user(request.tool_name, request.params)
matimo = await Matimo.init("./tools", on_approval=on_approval)See Approval System.
Next Steps
Section titled “Next Steps”Choose Your Pattern
Section titled “Choose Your Pattern”- Factory Pattern (you just used this), Best for simple scripts and backends
- Decorator Pattern: Best for class-based code
- LangChain: Best for AI agents with automatic tool selection
See SDK Usage Patterns for details.
Add More Tools
Section titled “Add More Tools”Create more YAML files in tools/:
tools/├── get_user/│ └── definition.yaml # Done├── my-api/│ └── definition.yaml # Create more└── slack/ └── definition.yamlEach tool is just a YAML file, no code needed!
Use Provider Tools
Section titled “Use Provider Tools”Install pre-built tools from npm:
pnpm add @matimo/slack @matimo/gmailThen load them alongside your custom tools:
const matimo = await MatimoInstance.init({ toolPaths: [ './tools', // Your custom tools './node_modules/@matimo/slack/tools', // Pre-built tools './node_modules/@matimo/gmail/tools', ],});In Python, install the provider packages from PyPI and let auto-discovery find them, with your own folder alongside:
pip install matimo-slack matimo-gmailmatimo = await Matimo.init("./tools", auto_discover=True)Further Reading
Section titled “Further Reading”- API Reference: Full SDK methods and types
- Tool Specification: Write production tools
- SDK Usage Patterns: Factory, Decorator, LangChain patterns
- Architecture Overview: How Matimo works internally
- Framework Integrations: LangChain integration examples
Common Tasks
Section titled “Common Tasks”Each task is shown in TypeScript, then Python.
List All Loaded Tools
Section titled “List All Loaded Tools”const tools = matimo.listTools();tools.forEach((tool) => { console.log(`${tool.name} - ${tool.description}`);});for tool in matimo.list_tools(): print(f"{tool.name} - {tool.description}")Get Tool by Name
Section titled “Get Tool by Name”const tool = matimo.getTool('get_user');if (tool) { console.log('Parameters:', tool.parameters);}tool = matimo.get_tool("get_user")if tool: print("Parameters:", tool.parameters)Search Tools
Section titled “Search Tools”const results = matimo.searchTools('user');console.log( 'Found:', results.map((t) => t.name));results = matimo.search_tools("user")print("Found:", [t.name for t in results])Execute with Error Handling
Section titled “Execute with Error Handling”try { const result = await matimo.execute('get_user', { id: 1 }); console.log('Success:', result);} catch (error) { if (error.code === 'TOOL_NOT_FOUND') { console.error('Tool not found:', error.message); } else if (error.code === 'INVALID_PARAMETER') { console.error('Invalid parameters:', error.details); } else if (error.code === 'POLICY_DENIED') { console.error('Refused by policy or by a reviewer:', error.message); } else if (error.code === 'EXECUTION_FAILED') { console.error('Execution failed:', error.details); }}from matimo import MatimoError
try: result = await matimo.execute("get_user", {"id": 1}) print("Success:", result)except MatimoError as error: if error.code == "TOOL_NOT_FOUND": print("Tool not found:", error) elif error.code == "INVALID_PARAMETER": print("Invalid parameters:", error.details) elif error.code == "POLICY_DENIED": print("Refused by policy or by a reviewer:", error) elif error.code == "EXECUTION_FAILED": print("Execution failed:", error.details)Example: Using Slack
Section titled “Example: Using Slack”After installing @matimo/slack:
import { MatimoInstance } from 'matimo';
const matimo = await MatimoInstance.init({ toolPaths: ['./tools', './node_modules/@matimo/slack/tools'],});
// Execute a Slack toolconst result = await matimo.execute('slack-send-message', { channel: '#general', text: 'Hello from Matimo!',});
console.log(result);The same call in Python, after pip install matimo-slack:
matimo = await Matimo.init("./tools", auto_discover=True)
result = await matimo.execute("slack-send-message", { "channel": "#general", "text": "Hello from Matimo!",})print(result)Troubleshooting
Section titled “Troubleshooting”Tools not loading?
# Check that YAML files existls tools/*/definition.yaml
# Validate YAML syntaxpnpm validate-tools # TypeScript: from typescript/ in a clone of the repomake validate-tools # Python: from python/ in a clone of the repoExecution failing?
// Enable detailed error messagestry { const result = await matimo.execute('tool-name', params);} catch (error) { console.error('Full error:', JSON.stringify(error, null, 2));}# Python: print the full error, including its detailstry: result = await matimo.execute("tool-name", params)except MatimoError as error: print(error.code, error, error.details)Type errors?
# Check TypeScript compilationnpx tsc --noEmit