matimo-postgres 0.1.3__tar.gz → 0.2.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.
@@ -58,7 +58,6 @@ temp/
58
58
 
59
59
  # Personal scratch notes / working docs — not part of the shipped repo
60
60
  .local-notes/
61
- typescript/examples/mcp/matimo-tools/.matimo-approvals.json
62
61
  typescript/examples/mcp/matimo-tools/fetch-weather/definition.yaml
63
62
  typescript/examples/mcp/matimo-tools/npm_downloads/definition.yaml
64
63
  typescript/examples/mcp/matimo-tools/skills/ecosystem-health/SKILL.md
@@ -68,3 +67,6 @@ typescript/packages/cli/.matimo/certs/server.crt
68
67
  typescript/packages/cli/.matimo/certs/server.key
69
68
  typescript/examples/mcp/.matimo/certs/server.crt
70
69
  typescript/examples/mcp/.matimo/certs/server.key
70
+
71
+ # HITL approval manifests are per-machine state (HMAC-signed approvals); never commit one
72
+ **/.matimo-approvals.json
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ROAIQ TECHNOLOGIES PRIVATE LIMITED
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.
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matimo-postgres
3
- Version: 0.1.3
3
+ Version: 0.2.0
4
4
  Summary: Matimo provider — PostgreSQL tools (query, insert, update, delete, execute SQL)
5
5
  License: MIT
6
+ License-File: LICENSE
6
7
  Keywords: agents,ai,matimo,postgres,tools
7
8
  Classifier: Development Status :: 4 - Beta
8
9
  Classifier: Intended Audience :: Developers
@@ -10,7 +11,7 @@ Classifier: License :: OSI Approved :: MIT License
10
11
  Classifier: Programming Language :: Python :: 3.11
11
12
  Requires-Python: >=3.11
12
13
  Requires-Dist: asyncpg>=0.29
13
- Requires-Dist: matimo-core<0.2.0,>=0.1.0
14
+ Requires-Dist: matimo-core<0.3.0,>=0.2.0
14
15
  Description-Content-Type: text/markdown
15
16
 
16
17
  # matimo-postgres
@@ -18,7 +19,7 @@ Description-Content-Type: text/markdown
18
19
  > PostgreSQL tools for [Matimo](https://matimo.dev) - execute SQL queries safely with policy-gated approval.
19
20
 
20
21
  [![PyPI](https://img.shields.io/pypi/v/matimo-postgres)](https://pypi.org/project/matimo-postgres/)
21
- [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://matimo.dev/docs)
22
+ [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://docs.matimo.dev)
22
23
 
23
24
  ---
24
25
 
@@ -38,7 +39,7 @@ pip install matimo matimo-postgres
38
39
 
39
40
  The tool does not set `requires_approval` itself - if you want destructive operations
40
41
  (INSERT, UPDATE, DELETE, DROP) to require human approval, gate them yourself via a
41
- [policy file](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE) or a custom
42
+ [policy file](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE) or a custom
42
43
  `PolicyEngine`.
43
44
 
44
45
  ---
@@ -64,23 +65,27 @@ asyncio.run(main())
64
65
 
65
66
  ### With Interactive Approval (Recommended for Writes)
66
67
 
67
- If you've configured a policy that quarantines this tool for HITL review, provide an
68
- `on_hitl` callback:
68
+ A query whose `sql` contains a destructive keyword (`DELETE`, `DROP`, `UPDATE`, `INSERT`, `ALTER`, `CREATE`, ...) needs approval. Provide an `on_approval` callback; without one the query is refused:
69
69
 
70
70
  ```python
71
- async def ask_user(request) -> dict:
71
+ from matimo import ApprovalRequest
72
+
73
+
74
+ async def ask_user(request: ApprovalRequest) -> bool:
72
75
  print(f"\nSQL requires approval:\n{request.params.get('sql')}")
73
- answer = input("Run this query? [y/n]: ").strip()
74
- return {'approved': answer == 'y', 'reason': 'user reviewed'}
76
+ return input("Run this query? [y/n]: ").strip() == "y"
75
77
 
76
- matimo = await Matimo.init(get_tools_path(), on_hitl=ask_user)
77
78
 
78
- # This will prompt before executing, if quarantined by your policy
79
+ matimo = await Matimo.init(get_tools_path(), on_approval=ask_user)
80
+
81
+ # Prompts before executing
79
82
  await matimo.execute('postgres-execute-sql', {
80
83
  'sql': 'DELETE FROM sessions WHERE expired_at < NOW()',
81
84
  })
82
85
  ```
83
86
 
87
+ The keyword match is a substring of the upper-cased query, so a `SELECT created_at ...` also asks (it contains `CREATE`).
88
+
84
89
  ---
85
90
 
86
91
  ## Authentication
@@ -102,14 +107,14 @@ export MATIMO_POSTGRES_PASSWORD="mypassword"
102
107
  - All SQL queries go through Matimo's **content validator** - SSRF and injection patterns are detected
103
108
  - The tool itself does not require approval - use a policy file if you want writes gated
104
109
  - Use a **read-only database user** for agent workloads when possible
105
- - Consider a [policy file](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE) to restrict allowed SQL patterns
110
+ - Consider a [policy file](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE) to restrict allowed SQL patterns
106
111
 
107
112
  ---
108
113
 
109
114
  ## Documentation
110
115
 
111
- - [Approval System](https://matimo.dev/docs/api-reference/APPROVAL-SYSTEM)
112
- - [Policy & Lifecycle](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE)
116
+ - [Approval System](https://docs.matimo.dev/api-reference/APPROVAL-SYSTEM)
117
+ - [Policy & Lifecycle](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE)
113
118
  - [Python Examples](https://github.com/tallclub/matimo/tree/main/python/examples/langchain/postgres)
114
119
 
115
120
  ---
@@ -3,7 +3,7 @@
3
3
  > PostgreSQL tools for [Matimo](https://matimo.dev) - execute SQL queries safely with policy-gated approval.
4
4
 
5
5
  [![PyPI](https://img.shields.io/pypi/v/matimo-postgres)](https://pypi.org/project/matimo-postgres/)
6
- [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://matimo.dev/docs)
6
+ [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://docs.matimo.dev)
7
7
 
8
8
  ---
9
9
 
@@ -23,7 +23,7 @@ pip install matimo matimo-postgres
23
23
 
24
24
  The tool does not set `requires_approval` itself - if you want destructive operations
25
25
  (INSERT, UPDATE, DELETE, DROP) to require human approval, gate them yourself via a
26
- [policy file](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE) or a custom
26
+ [policy file](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE) or a custom
27
27
  `PolicyEngine`.
28
28
 
29
29
  ---
@@ -49,23 +49,27 @@ asyncio.run(main())
49
49
 
50
50
  ### With Interactive Approval (Recommended for Writes)
51
51
 
52
- If you've configured a policy that quarantines this tool for HITL review, provide an
53
- `on_hitl` callback:
52
+ A query whose `sql` contains a destructive keyword (`DELETE`, `DROP`, `UPDATE`, `INSERT`, `ALTER`, `CREATE`, ...) needs approval. Provide an `on_approval` callback; without one the query is refused:
54
53
 
55
54
  ```python
56
- async def ask_user(request) -> dict:
55
+ from matimo import ApprovalRequest
56
+
57
+
58
+ async def ask_user(request: ApprovalRequest) -> bool:
57
59
  print(f"\nSQL requires approval:\n{request.params.get('sql')}")
58
- answer = input("Run this query? [y/n]: ").strip()
59
- return {'approved': answer == 'y', 'reason': 'user reviewed'}
60
+ return input("Run this query? [y/n]: ").strip() == "y"
60
61
 
61
- matimo = await Matimo.init(get_tools_path(), on_hitl=ask_user)
62
62
 
63
- # This will prompt before executing, if quarantined by your policy
63
+ matimo = await Matimo.init(get_tools_path(), on_approval=ask_user)
64
+
65
+ # Prompts before executing
64
66
  await matimo.execute('postgres-execute-sql', {
65
67
  'sql': 'DELETE FROM sessions WHERE expired_at < NOW()',
66
68
  })
67
69
  ```
68
70
 
71
+ The keyword match is a substring of the upper-cased query, so a `SELECT created_at ...` also asks (it contains `CREATE`).
72
+
69
73
  ---
70
74
 
71
75
  ## Authentication
@@ -87,14 +91,14 @@ export MATIMO_POSTGRES_PASSWORD="mypassword"
87
91
  - All SQL queries go through Matimo's **content validator** - SSRF and injection patterns are detected
88
92
  - The tool itself does not require approval - use a policy file if you want writes gated
89
93
  - Use a **read-only database user** for agent workloads when possible
90
- - Consider a [policy file](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE) to restrict allowed SQL patterns
94
+ - Consider a [policy file](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE) to restrict allowed SQL patterns
91
95
 
92
96
  ---
93
97
 
94
98
  ## Documentation
95
99
 
96
- - [Approval System](https://matimo.dev/docs/api-reference/APPROVAL-SYSTEM)
97
- - [Policy & Lifecycle](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE)
100
+ - [Approval System](https://docs.matimo.dev/api-reference/APPROVAL-SYSTEM)
101
+ - [Policy & Lifecycle](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE)
98
102
  - [Python Examples](https://github.com/tallclub/matimo/tree/main/python/examples/langchain/postgres)
99
103
 
100
104
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "matimo-postgres"
7
- version = "0.1.3"
7
+ version = "0.2.0"
8
8
  description = "Matimo provider — PostgreSQL tools (query, insert, update, delete, execute SQL)"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -17,7 +17,7 @@ classifiers = [
17
17
  "Programming Language :: Python :: 3.11",
18
18
  ]
19
19
  dependencies = [
20
- "matimo-core>=0.1.0,<0.2.0",
20
+ "matimo-core>=0.2.0,<0.3.0",
21
21
  "asyncpg>=0.29",
22
22
  ]
23
23
 
@@ -0,0 +1,293 @@
1
+ ---
2
+ name: postgres
3
+ description: "Complete guide to all PostgreSQL tools — parameterized queries, schema navigation, data retrieval, and safe database interaction patterns."
4
+ version: "1.0.0"
5
+ license: "MIT"
6
+ metadata:
7
+ category: "Database"
8
+ difficulty: "intermediate"
9
+ apply-to: "postgres-execute-sql"
10
+ tags: "postgres,sql,database,queries"
11
+ ---
12
+
13
+ # PostgreSQL
14
+
15
+ This skill teaches you how to **safely execute SQL queries** against a PostgreSQL database using Matimo tools, with emphasis on parameterized queries, schema awareness, and safe patterns.
16
+
17
+ ## Tools You Will Use
18
+
19
+ | Tool | Purpose |
20
+ |------|---------|
21
+ | `postgres-execute-sql` | Execute any SQL statement against a connected Postgres database |
22
+
23
+ ---
24
+
25
+ ## Executing a Query
26
+
27
+ Use `postgres-execute-sql` to run SQL statements. The tool supports parameterized queries for safety.
28
+
29
+ ### Parameters
30
+
31
+ | Parameter | Type | Description |
32
+ |-----------|------|-------------|
33
+ | `sql` | string | SQL statement to execute. Use `$1`, `$2`, etc. for parameterized values |
34
+ | `params` | array | Optional array of parameter values (matched by position to `$1`, `$2`, etc.) |
35
+ | `schema` | string | Optional schema name for table qualification |
36
+
37
+ ### Critical: Always Use Parameterized Queries
38
+
39
+ **NEVER** interpolate user-provided values directly into SQL strings. Always use `$1`, `$2` placeholders.
40
+
41
+ ```json
42
+ // ✅ SAFE — parameterized
43
+ {
44
+ "sql": "SELECT * FROM users WHERE email = $1",
45
+ "params": ["user@example.com"]
46
+ }
47
+
48
+ // ❌ DANGEROUS — SQL injection risk
49
+ {
50
+ "sql": "SELECT * FROM users WHERE email = 'user@example.com'"
51
+ }
52
+ ```
53
+
54
+ This prevents SQL injection attacks regardless of the input content.
55
+
56
+ ---
57
+
58
+ ## Read Operations
59
+
60
+ ### Select with Parameters
61
+
62
+ ```json
63
+ {
64
+ "sql": "SELECT id, name, email FROM users WHERE id = $1",
65
+ "params": [42]
66
+ }
67
+ ```
68
+
69
+ ### Select with Multiple Conditions
70
+
71
+ ```json
72
+ {
73
+ "sql": "SELECT * FROM orders WHERE status = $1 AND created_at > $2",
74
+ "params": ["pending", "2025-01-01"]
75
+ }
76
+ ```
77
+
78
+ ### Count Records
79
+
80
+ ```json
81
+ {
82
+ "sql": "SELECT count(*) as total FROM users WHERE active = $1",
83
+ "params": [true]
84
+ }
85
+ ```
86
+
87
+ ### Pagination Pattern
88
+
89
+ ```json
90
+ {
91
+ "sql": "SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT $1 OFFSET $2",
92
+ "params": [20, 0]
93
+ }
94
+ ```
95
+
96
+ Increment the offset by the limit for each page: `0`, `20`, `40`, `60`...
97
+
98
+ ### Join Queries
99
+
100
+ ```json
101
+ {
102
+ "sql": "SELECT u.name, o.total, o.status FROM users u JOIN orders o ON u.id = o.user_id WHERE o.status = $1 ORDER BY o.created_at DESC LIMIT $2",
103
+ "params": ["completed", 10]
104
+ }
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Schema Discovery
110
+
111
+ ### List All Tables
112
+
113
+ ```json
114
+ {
115
+ "sql": "SELECT table_name FROM information_schema.tables WHERE table_schema = $1 ORDER BY table_name",
116
+ "params": ["public"]
117
+ }
118
+ ```
119
+
120
+ ### Describe a Table
121
+
122
+ ```json
123
+ {
124
+ "sql": "SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name = $1 AND table_schema = $2 ORDER BY ordinal_position",
125
+ "params": ["users", "public"]
126
+ }
127
+ ```
128
+
129
+ ### List Indexes
130
+
131
+ ```json
132
+ {
133
+ "sql": "SELECT indexname, indexdef FROM pg_indexes WHERE tablename = $1",
134
+ "params": ["users"]
135
+ }
136
+ ```
137
+
138
+ ### Using Schema Parameter
139
+
140
+ When working with non-default schemas, use the `schema` parameter:
141
+
142
+ ```json
143
+ {
144
+ "sql": "SELECT * FROM customers LIMIT 10",
145
+ "schema": "sales"
146
+ }
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Write Operations
152
+
153
+ ### Insert a Row
154
+
155
+ ```json
156
+ {
157
+ "sql": "INSERT INTO users (name, email, role) VALUES ($1, $2, $3) RETURNING id",
158
+ "params": ["Alice Smith", "alice@example.com", "admin"]
159
+ }
160
+ ```
161
+
162
+ Use `RETURNING` to get the inserted row's ID without a second query.
163
+
164
+ ### Update Rows
165
+
166
+ ```json
167
+ {
168
+ "sql": "UPDATE users SET email = $1, updated_at = NOW() WHERE id = $2 RETURNING id, email",
169
+ "params": ["newemail@example.com", 42]
170
+ }
171
+ ```
172
+
173
+ ### Delete Rows
174
+
175
+ ```json
176
+ {
177
+ "sql": "DELETE FROM sessions WHERE expires_at < NOW() RETURNING id",
178
+ "params": []
179
+ }
180
+ ```
181
+
182
+ ### Upsert (Insert or Update)
183
+
184
+ ```json
185
+ {
186
+ "sql": "INSERT INTO settings (key, value) VALUES ($1, $2) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value RETURNING key, value",
187
+ "params": ["theme", "dark"]
188
+ }
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Understanding the Response
194
+
195
+ Every query returns:
196
+
197
+ ```json
198
+ {
199
+ "rows": [
200
+ { "id": 1, "name": "Alice", "email": "alice@example.com" },
201
+ { "id": 2, "name": "Bob", "email": "bob@example.com" }
202
+ ],
203
+ "rowCount": 2
204
+ }
205
+ ```
206
+
207
+ - **`rows`**: Array of result objects (empty for non-SELECT statements)
208
+ - **`rowCount`**: Number of rows affected (for INSERT/UPDATE/DELETE) or returned (for SELECT)
209
+
210
+ ---
211
+
212
+ ## Common Workflows
213
+
214
+ ### Workflow: Data Exploration
215
+
216
+ 1. **List tables:** Query `information_schema.tables` to see what's available
217
+ 2. **Describe schema:** Query `information_schema.columns` for table structure
218
+ 3. **Sample data:** `SELECT * FROM {table} LIMIT 10` to understand content
219
+ 4. **Targeted queries:** Build specific queries based on discovered schema
220
+
221
+ ### Workflow: Reporting
222
+
223
+ 1. **Aggregate data:** Use `GROUP BY`, `COUNT`, `SUM`, `AVG`
224
+ 2. **Date ranges:** Filter with parameterized date values
225
+ 3. **Multiple queries:** Chain queries to build multi-dimensional reports
226
+
227
+ ```json
228
+ {
229
+ "sql": "SELECT status, count(*) as count, sum(total) as revenue FROM orders WHERE created_at >= $1 GROUP BY status ORDER BY count DESC",
230
+ "params": ["2025-01-01"]
231
+ }
232
+ ```
233
+
234
+ ### Workflow: Safe Bulk Operations
235
+
236
+ Always use transactions for multi-step writes:
237
+
238
+ ```json
239
+ {
240
+ "sql": "BEGIN; UPDATE accounts SET balance = balance - $1 WHERE id = $2; UPDATE accounts SET balance = balance + $1 WHERE id = $3; COMMIT;",
241
+ "params": [100.00, 1, 2]
242
+ }
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Best Practices
248
+
249
+ 1. **Always parameterize.** Every dynamic value should use `$1`, `$2`, etc. — no exceptions.
250
+ 2. **Use LIMIT.** Always add `LIMIT` to SELECT queries to prevent fetching millions of rows.
251
+ 3. **Use RETURNING.** On INSERT/UPDATE/DELETE, use `RETURNING` to avoid a second SELECT.
252
+ 4. **Check rowCount.** Verify the expected number of rows were affected before proceeding.
253
+ 5. **Use specific columns.** Avoid `SELECT *` in production — name the columns you need.
254
+ 6. **Schema-qualify tables.** Use the `schema` parameter or `schema.table` syntax for clarity.
255
+ 7. **Timeout awareness.** Queries timeout after 30 seconds — optimize or paginate large queries.
256
+
257
+ ---
258
+
259
+ ## Error Handling
260
+
261
+ | Error | Cause | Resolution |
262
+ |-------|-------|------------|
263
+ | `ECONNREFUSED` | Database not reachable | Check `MATIMO_POSTGRES_URL` or host/port env vars |
264
+ | `password authentication failed` | Bad credentials | Verify `MATIMO_POSTGRES_PASSWORD` env var |
265
+ | `relation "X" does not exist` | Table not found | Check table name and schema |
266
+ | `column "X" does not exist` | Wrong column name | Query `information_schema.columns` to verify |
267
+ | `syntax error at or near` | Invalid SQL | Check query syntax — use a SQL validator |
268
+ | `query timeout` | Query too slow | Add indexes, use LIMIT, or optimize the query |
269
+
270
+ ---
271
+
272
+ ## Authentication
273
+
274
+ PostgreSQL connection supports two modes:
275
+
276
+ ### Option 1: Connection String (Recommended)
277
+
278
+ Set `MATIMO_POSTGRES_URL`:
279
+ ```
280
+ postgresql://user:password@host:5432/dbname?sslmode=require
281
+ ```
282
+
283
+ ### Option 2: Separate Environment Variables
284
+
285
+ | Env Var | Description |
286
+ |---------|-------------|
287
+ | `MATIMO_POSTGRES_HOST` | Database hostname |
288
+ | `MATIMO_POSTGRES_PORT` | Port (default: 5432) |
289
+ | `MATIMO_POSTGRES_USER` | Username |
290
+ | `MATIMO_POSTGRES_PASSWORD` | Password |
291
+ | `MATIMO_POSTGRES_DB` | Database name |
292
+
293
+ **Never log or expose connection credentials.**
@@ -1,5 +1,6 @@
1
1
  name: postgres-execute-sql
2
2
  version: '1.0.0'
3
+ risk: high
3
4
  description: Execute arbitrary SQL against a Postgres database. Supports both connection string and explicit env var configuration.
4
5
 
5
6
  parameters: