@christopherlittle51/postclaw 1.3.1 → 1.3.4
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/README.md +76 -690
- package/dashboard/README.md +89 -0
- package/dashboard/public/app.js +1023 -543
- package/dashboard/public/index.html +283 -75
- package/dashboard/public/styles.css +583 -126
- package/dist/dashboard/routes/config.d.ts.map +1 -1
- package/dist/dashboard/routes/config.js +17 -1
- package/dist/dashboard/routes/config.js.map +1 -1
- package/dist/dashboard/routes/graph.d.ts +2 -2
- package/dist/dashboard/routes/graph.d.ts.map +1 -1
- package/dist/dashboard/routes/graph.js +61 -23
- package/dist/dashboard/routes/graph.js.map +1 -1
- package/dist/dashboard/routes/memories.d.ts.map +1 -1
- package/dist/dashboard/routes/memories.js +97 -11
- package/dist/dashboard/routes/memories.js.map +1 -1
- package/dist/dashboard/routes/scripts.d.ts.map +1 -1
- package/dist/dashboard/routes/scripts.js +3 -1
- package/dist/dashboard/routes/scripts.js.map +1 -1
- package/dist/dashboard/routes/workspace.d.ts +4 -3
- package/dist/dashboard/routes/workspace.d.ts.map +1 -1
- package/dist/dashboard/routes/workspace.js +119 -7
- package/dist/dashboard/routes/workspace.js.map +1 -1
- package/dist/dashboard/server.js +1 -1
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +189 -43
- package/dist/index.js.map +1 -1
- package/dist/schemas/validation.d.ts +108 -12
- package/dist/schemas/validation.d.ts.map +1 -1
- package/dist/schemas/validation.js +66 -11
- package/dist/schemas/validation.js.map +1 -1
- package/dist/scripts/bootstrap_persona.d.ts.map +1 -1
- package/dist/scripts/bootstrap_persona.js +3 -3
- package/dist/scripts/bootstrap_persona.js.map +1 -1
- package/dist/scripts/setup-db.d.ts.map +1 -1
- package/dist/scripts/setup-db.js +74 -37
- package/dist/scripts/setup-db.js.map +1 -1
- package/dist/scripts/sleep_cycle.d.ts +1 -0
- package/dist/scripts/sleep_cycle.d.ts.map +1 -1
- package/dist/scripts/sleep_cycle.js +209 -38
- package/dist/scripts/sleep_cycle.js.map +1 -1
- package/dist/services/config.d.ts +1 -0
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +15 -29
- package/dist/services/config.js.map +1 -1
- package/dist/services/db.d.ts +10 -0
- package/dist/services/db.d.ts.map +1 -1
- package/dist/services/db.js +38 -1
- package/dist/services/db.js.map +1 -1
- package/dist/services/llm.d.ts.map +1 -1
- package/dist/services/llm.js +3 -1
- package/dist/services/llm.js.map +1 -1
- package/dist/services/memoryService.d.ts +4 -2
- package/dist/services/memoryService.d.ts.map +1 -1
- package/dist/services/memoryService.js +127 -43
- package/dist/services/memoryService.js.map +1 -1
- package/dist/services/personaService.d.ts +25 -0
- package/dist/services/personaService.d.ts.map +1 -1
- package/dist/services/personaService.js +79 -0
- package/dist/services/personaService.js.map +1 -1
- package/dist/tests/dashboard-schemas.test.js +71 -1
- package/dist/tests/dashboard-schemas.test.js.map +1 -1
- package/openclaw.plugin.json +5 -0
- package/package.json +2 -1
- package/schemas/README.md +64 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# PostClaw — PostgreSQL Memory Plugin
|
|
1
|
+
# PostClaw — The PostgreSQL Vector Memory Plugin
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<img src="https://github.com/user-attachments/assets/2a7798c6-e711-40fa-bcf2-7416180651cc"
|
|
@@ -8,754 +8,140 @@
|
|
|
8
8
|
style="display: block; margin: 0 auto" />
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Overview
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Table of Contents
|
|
16
|
-
|
|
17
|
-
- [Features](#features)
|
|
18
|
-
- [Prerequisites](#prerequisites)
|
|
19
|
-
- [Quick Start](#quick-start)
|
|
20
|
-
- [Installation](#installation)
|
|
21
|
-
- [Database Setup](#database-setup)
|
|
22
|
-
- [Configuration](#configuration)
|
|
23
|
-
- [Plugin Hooks](#plugin-hooks)
|
|
24
|
-
- [Agent Tools](#agent-tools)
|
|
25
|
-
- [CLI Commands](#cli-commands)
|
|
26
|
-
- [Background Services](#background-services)
|
|
27
|
-
- [Database Schema](#database-schema)
|
|
28
|
-
- [Row-Level Security](#row-level-security)
|
|
29
|
-
- [Persona Bootstrap](#persona-bootstrap)
|
|
30
|
-
- [Sleep Cycle](#sleep-cycle)
|
|
31
|
-
- [Testing](#testing)
|
|
32
|
-
- [Troubleshooting](#troubleshooting)
|
|
13
|
+
**PostClaw** is a memory architecture plugin designed specifically for the OpenClaw agent framework. By migrating the default text-based memory system into a PostgreSQL database equipped with `pgvector`, PostClaw gives your AI agent the ability to recall long-term facts and short-term conversations using semantic vector search.
|
|
33
14
|
|
|
34
|
-
|
|
15
|
+
Rather than relying on exact keyword matching ("dog"), PostClaw translates memories into mathematical arrays. This means the agent can find related context conceptually ("pets", "puppies", "vet trips") regardless of the exact phrasing.
|
|
35
16
|
|
|
36
|
-
|
|
17
|
+
### Core Features
|
|
37
18
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
| **Dynamic Persona Injection** | Injects agent-specific persona rules and RAG context into every prompt |
|
|
44
|
-
| **Duplicate Detection** | Identifies and merges near-duplicate memories during background maintenance |
|
|
45
|
-
| **Multi-Agent Isolation** | Row-Level Security (RLS) ensures agents can only read/write their own data |
|
|
46
|
-
| **Autonomous Management** | Agents silently store, update, link, and search memories without user prompts |
|
|
19
|
+
* **Retrieval-Augmented Generation (RAG):** Dynamically injects highly relevant factual memories directly into the agent's context window.
|
|
20
|
+
* **Separation of Concerns:** Distinct tables for short-term transcripts (**Episodic Memory**) versus long-term durable truths (**Semantic Memory**).
|
|
21
|
+
* **The Knowledge Graph:** Explicit connections between related ideas stored in the `entity_edges` table, allowing the agent to pull secondary context automatically.
|
|
22
|
+
* **Automated Maintenance (The Sleep Cycle):** Background scripts that run periodically to deduplicate overlapping facts, consolidate messy conversational logs, and delete stale data—all autonomously via the LLM.
|
|
23
|
+
* **Data Isolation (RLS):** True multi-agent sandboxing using PostgreSQL Row-Level Security. Agent A mathematically cannot read or overwrite Agent B's private memory.
|
|
47
24
|
|
|
48
25
|
---
|
|
49
26
|
|
|
50
|
-
## Prerequisites
|
|
51
|
-
|
|
52
|
-
1. **OpenClaw** — installed and configured
|
|
53
|
-
2. **PostgreSQL** (v14+) — installed and running. Depending on your system, you may need the `postgresql-<version>-pgvector` package installed. The `pgvector` extension is installed automatically by the setup command.
|
|
54
|
-
3. **Node.js** (v18+) and **npm**
|
|
55
|
-
4. **Embedding Provider** — LM Studio, Ollama, or any OpenAI-compatible endpoint serving an embedding model (e.g. `nomic-embed-text-v2-moe`)
|
|
56
|
-
|
|
57
|
-
```json
|
|
58
|
-
"memorySearch": {
|
|
59
|
-
"provider": "openai",
|
|
60
|
-
"remote": {
|
|
61
|
-
"baseUrl": "http://<OPENAI-COMPATIBLE-ENDPOINT>/v1",
|
|
62
|
-
"apiKey": "<API-KEY>"
|
|
63
|
-
},
|
|
64
|
-
"model": "text-embedding-nomic-embed-text-v2-moe"
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
5. **Tools Enabled** - At the least, you need the following permissions setup in your `openclaw.json`. This is a **Breaking Change** introduced in 2026.3.2 of OpenClaw:
|
|
69
|
-
|
|
70
|
-
```json
|
|
71
|
-
"tools": {
|
|
72
|
-
"profile": "messaging",
|
|
73
|
-
"alsoAllow": ["postclaw"] // OR group:plugins if you have other plugins installed.
|
|
74
|
-
},
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Quick Start
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
# PREREQUISITES
|
|
83
|
-
## You must have a password assigned to your postgres user if you are running openclaw from another user.
|
|
84
|
-
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'YOUR_PASSWORD';"
|
|
85
|
-
|
|
86
|
-
## Install pgvector plugin (change xx to your postgres version:
|
|
87
|
-
sudo apt install postgresql-xx-pgvector # Ubuntu/Debian example.
|
|
88
|
-
|
|
89
|
-
# 1. Install the plugin
|
|
90
|
-
openclaw plugins install @christopherlittle51/postclaw # from npm
|
|
91
|
-
# OR from a local path:
|
|
92
|
-
openclaw plugins install /path/to/PostClaw
|
|
93
|
-
|
|
94
|
-
# 2. Set up the database (creates DB, user, schema, everything)
|
|
95
|
-
openclaw postclaw setup --admin-url postgres://<POSTGRES-USERNAME>:<PASSWORD>@[IP ADDRESS/localhost]/postgres
|
|
96
|
-
|
|
97
|
-
# 3. Restart the gateway
|
|
98
|
-
openclaw restart
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Done. PostClaw will automatically:
|
|
102
|
-
|
|
103
|
-
- Connect to the database using the credential it just generated
|
|
104
|
-
- Start injecting RAG context and persona rules into every prompt
|
|
105
|
-
- Begin logging episodic memory after each agent turn
|
|
106
|
-
- Run the sleep cycle in the background every 6 hours
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## Installation
|
|
111
|
-
|
|
112
|
-
### From npm (recommended)
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
openclaw plugins install @christopherlittle51/postclaw
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### From local path
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
# Copy into ~/.openclaw/extensions/postclaw/
|
|
122
|
-
openclaw plugins install /path/to/PostClaw
|
|
123
|
-
|
|
124
|
-
# Or link for development (live edits, no copy)
|
|
125
|
-
openclaw plugins install -l /path/to/PostClaw
|
|
126
|
-
```
|
|
27
|
+
## 🛠 Prerequisites
|
|
127
28
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
git clone <repository-url> PostClaw
|
|
132
|
-
cd PostClaw
|
|
133
|
-
npm install
|
|
134
|
-
npm run build
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Then add to `~/.openclaw/openclaw.json`:
|
|
29
|
+
To use PostClaw, your environment must meet the following infrastructure requirements:
|
|
138
30
|
|
|
31
|
+
1. **OpenClaw (v2026.3.2+):** The host agent framework installed and running.
|
|
32
|
+
2. **PostgreSQL 14+ with pgvector:** A running database server. The `pgvector` and `pgcrypto` extensions are strictly required for mathematical embeddings and UUID generation. *(e.g., `postgresql-16-pgvector`)*.
|
|
33
|
+
3. **Node.js (v18+):** For executing the plugin scripts.
|
|
34
|
+
4. **An Embedding Provider:** A local endpoint (like LM Studio or Ollama) running an embedding model natively (such as `nomic-embed-text-v2-moe`) to convert text into vectors.
|
|
139
35
|
```json
|
|
140
|
-
{
|
|
141
|
-
"plugins": {
|
|
142
|
-
"load": { "paths": ["/absolute/path/to/PostClaw"] },
|
|
143
|
-
"slots": { "memory": "postclaw" },
|
|
144
|
-
"entries": {
|
|
145
|
-
"postclaw": { "enabled": true }
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## Database Setup
|
|
154
|
-
|
|
155
|
-
### Automated Setup
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
openclaw postclaw setup [options]
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
This command:
|
|
162
|
-
|
|
163
|
-
1. Connects to PostgreSQL as a superuser
|
|
164
|
-
2. Creates the `memorydb` database (if it doesn't exist)
|
|
165
|
-
3. Installs the `vector` and `pgcrypto` extensions
|
|
166
|
-
4. Creates the `openclaw` app user with a **random password**
|
|
167
|
-
5. Creates the `system_admin` role with RLS bypass
|
|
168
|
-
6. Builds all tables, triggers, indices, and RLS policies
|
|
169
|
-
7. Auto-updates `~/.openclaw/openclaw.json` with the connection string
|
|
170
|
-
|
|
171
|
-
#### Options
|
|
172
|
-
|
|
173
|
-
| Flag | Default | Description |
|
|
174
|
-
|------|---------|-------------|
|
|
175
|
-
| `--admin-url <url>` | `postgres://localhost/postgres` | Superuser connection string |
|
|
176
|
-
| `--db-name <name>` | `memorydb` | Database name |
|
|
177
|
-
| `--db-user <user>` | `openclaw` | App user name |
|
|
178
|
-
| `--db-password <pass>` | *auto-generated* | App user password |
|
|
179
|
-
| `--skip-config` | `false` | Don't auto-update `openclaw.json` |
|
|
180
|
-
|
|
181
|
-
#### Examples
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
# Local PostgreSQL with default peer auth
|
|
185
|
-
openclaw postclaw setup
|
|
186
|
-
|
|
187
|
-
# Remote / password-protected PostgreSQL
|
|
188
|
-
openclaw postclaw setup --admin-url postgres://postgres:mysecretpass@db.example.com:5432/postgres
|
|
189
|
-
|
|
190
|
-
# Custom database and user names
|
|
191
|
-
openclaw postclaw setup --db-name myagent_memory --db-user myagent --db-password hunter2
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
#### Output
|
|
195
|
-
|
|
196
|
-
```
|
|
197
|
-
🦐 PostClaw Database Setup
|
|
198
|
-
|
|
199
|
-
✅ Connected to Postgres as superuser
|
|
200
|
-
✅ Created database 'memorydb'
|
|
201
|
-
✅ Created user 'openclaw'
|
|
202
|
-
✅ Created role 'system_admin'
|
|
203
|
-
✅ Schema created (6 tables, 14 indices, 18 RLS policies)
|
|
204
|
-
✅ Granted permissions
|
|
205
|
-
|
|
206
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
207
|
-
Database: memorydb
|
|
208
|
-
App User: openclaw
|
|
209
|
-
App Password: kR9x!mQ2vL8nP4wZ
|
|
210
|
-
Admin User: system_admin
|
|
211
|
-
Admin Pass: bN7yT3xK1mR5sW9e
|
|
212
|
-
|
|
213
|
-
Connection: postgres://openclaw:kR9x!mQ2vL8nP4wZ@localhost:5432/memorydb
|
|
214
|
-
|
|
215
|
-
✅ openclaw.json updated with dbUrl
|
|
216
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
217
|
-
|
|
218
|
-
Save these credentials! They won't be shown again.
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
The setup is **fully idempotent** — safe to re-run without errors.
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
## Configuration
|
|
226
|
-
|
|
227
|
-
All configuration lives in `~/.openclaw/openclaw.json`:
|
|
228
|
-
|
|
229
|
-
```json
|
|
230
|
-
{
|
|
231
|
-
"plugins": {
|
|
232
|
-
"slots": {
|
|
233
|
-
"memory": "postclaw"
|
|
234
|
-
},
|
|
235
|
-
"entries": {
|
|
236
|
-
"postclaw": {
|
|
237
|
-
"enabled": true,
|
|
238
|
-
"config": {
|
|
239
|
-
"dbUrl": "postgres://openclaw:PASSWORD@localhost:5432/memorydb",
|
|
240
|
-
"sleepIntervalHours": 6
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
},
|
|
245
|
-
"agents": {
|
|
36
|
+
"agents": {
|
|
246
37
|
"defaults": {
|
|
247
38
|
"memorySearch": {
|
|
248
|
-
"
|
|
39
|
+
"model": "text-embedding-nomic-embed-text-v2-moe",
|
|
249
40
|
"remote": {
|
|
250
|
-
"baseUrl": "http://
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
"model": "text-embedding-nomic-embed-text-v2-moe"
|
|
254
|
-
}
|
|
41
|
+
"baseUrl": "http://localhost:1234/v1" // example for LM Studio
|
|
42
|
+
}
|
|
43
|
+
},
|
|
255
44
|
}
|
|
256
|
-
}
|
|
257
45
|
}
|
|
258
46
|
```
|
|
259
47
|
|
|
260
|
-
### Config Properties
|
|
261
|
-
|
|
262
|
-
| Key | Type | Default | Description |
|
|
263
|
-
|-----|------|---------|-------------|
|
|
264
|
-
| `dbUrl` | `string` | — | PostgreSQL connection string (**required**) |
|
|
265
|
-
| `adminDbUrl` | `string` | — | Superuser connection (only used by `postclaw setup`) |
|
|
266
|
-
| `sleepIntervalHours` | `number` | `6` | Hours between background sleep cycles. Set to `0` to disable. |
|
|
267
|
-
|
|
268
|
-
The `POSTCLAW_DB_URL` environment variable is also supported as a fallback for `dbUrl`.
|
|
269
|
-
|
|
270
48
|
---
|
|
271
49
|
|
|
272
|
-
##
|
|
273
|
-
|
|
274
|
-
PostClaw registers three hooks with the OpenClaw lifecycle:
|
|
275
|
-
|
|
276
|
-
### 1. `message_received` (void)
|
|
277
|
-
|
|
278
|
-
**When:** Every inbound message before agent processing begins.
|
|
279
|
-
|
|
280
|
-
**What it does:** Caches the raw message text so the next `before_prompt_build` has the real user text (not the system-modified version).
|
|
281
|
-
|
|
282
|
-
### 2. `before_prompt_build` (modifying)
|
|
50
|
+
## 🚀 Quick Start Guide
|
|
283
51
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
**What it does:**
|
|
287
|
-
|
|
288
|
-
1. **Prunes the system prompt** — strips OpenClaw's default bloat (Tooling rules, Documentation, Project Context markdown)
|
|
289
|
-
2. **Injects memory architecture rules** — teaches the agent how to use its memory tools
|
|
290
|
-
3. **Fetches persona context** — pulls `agent_persona` rules from Postgres (core rules always, situational rules ranked by embedding similarity)
|
|
291
|
-
4. **Runs RAG search** — performs a vector similarity search on `memory_semantic` + traverses `entity_edges` for linked memories
|
|
292
|
-
5. **Loads dynamic tools** — fetches tool schemas from `context_environment` ranked by embedding similarity
|
|
293
|
-
6. **Injects everything** — returns the modified system prompt and prepended RAG context
|
|
294
|
-
|
|
295
|
-
**Returns:** `{ systemPrompt, prependContext, tools }`
|
|
296
|
-
|
|
297
|
-
### 3. `agent_end` (void)
|
|
298
|
-
|
|
299
|
-
**When:** After the agent completes a turn (response generated).
|
|
300
|
-
|
|
301
|
-
**What it does:**
|
|
302
|
-
|
|
303
|
-
1. **Logs user prompt** as an episodic memory event (with embedding)
|
|
304
|
-
2. **Logs each tool call** the agent made as a separate episodic event
|
|
305
|
-
3. Skips heartbeat/cron runs to avoid noise
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## Agent Tools
|
|
310
|
-
|
|
311
|
-
PostClaw registers 5 native tools that the agent can invoke autonomously:
|
|
312
|
-
|
|
313
|
-
### `memory_search`
|
|
314
|
-
|
|
315
|
-
Search the semantic memory database by natural language query.
|
|
316
|
-
|
|
317
|
-
```
|
|
318
|
-
memory_search({ query: "user's preferred programming language" })
|
|
319
|
-
→ { results: "[ID: abc...] (92.3%) - The user prefers TypeScript..." }
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
| Parameter | Type | Required | Description |
|
|
323
|
-
|-----------|------|----------|-------------|
|
|
324
|
-
| `query` | `string` | ✅ | Natural language search query |
|
|
325
|
-
| `max_results` | `number` | — | Max results to return (default: 5) |
|
|
326
|
-
|
|
327
|
-
### `memory_store`
|
|
328
|
-
|
|
329
|
-
Store a new semantic memory fact with embedding.
|
|
330
|
-
|
|
331
|
-
```
|
|
332
|
-
memory_store({
|
|
333
|
-
content: "The user's server runs Ubuntu 22.04 on a Hetzner VPS",
|
|
334
|
-
scope: "private",
|
|
335
|
-
category: "infrastructure",
|
|
336
|
-
tier: "permanent",
|
|
337
|
-
confidence: 0.95
|
|
338
|
-
})
|
|
339
|
-
→ { id: "550e8400-...", status: "stored" }
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
| Parameter | Type | Required | Description |
|
|
343
|
-
|-----------|------|----------|-------------|
|
|
344
|
-
| `content` | `string` | ✅ | The fact to store |
|
|
345
|
-
| `scope` | `"private" \| "shared" \| "global"` | — | Visibility (default: `private`) |
|
|
346
|
-
| `category` | `string` | — | Semantic category label |
|
|
347
|
-
| `volatility` | `"low" \| "medium" \| "high"` | — | How likely to change |
|
|
348
|
-
| `tier` | `"volatile" \| "session" \| "daily" \| "stable" \| "permanent"` | — | Retention tier |
|
|
349
|
-
| `confidence` | `number` | — | 0.0–1.0 confidence score |
|
|
350
|
-
| `metadata` | `object` | — | Arbitrary JSON metadata |
|
|
351
|
-
|
|
352
|
-
### `memory_update`
|
|
353
|
-
|
|
354
|
-
Supersede an existing memory with a corrected fact. Archives the old memory and links the new one.
|
|
355
|
-
|
|
356
|
-
```
|
|
357
|
-
memory_update({
|
|
358
|
-
old_memory_id: "550e8400-...",
|
|
359
|
-
new_fact: "The user's server now runs Ubuntu 24.04",
|
|
360
|
-
tier: "permanent"
|
|
361
|
-
})
|
|
362
|
-
→ { newId: "7c9e6679-...", status: "updated" }
|
|
363
|
-
```
|
|
52
|
+
Assuming you have PostgreSQL installed and an OpenClaw environment ready, follow these steps to bootstrap your agent's new memory:
|
|
364
53
|
|
|
365
|
-
|
|
366
|
-
|-----------|------|----------|-------------|
|
|
367
|
-
| `old_memory_id` | `string` | ✅ | UUID of the memory to supersede |
|
|
368
|
-
| `new_fact` | `string` | ✅ | The corrected/updated content |
|
|
369
|
-
| All `memory_store` options | — | — | Same options available |
|
|
54
|
+
### 1. Install the Plugin
|
|
370
55
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
Create a directed edge in the knowledge graph between two memories.
|
|
374
|
-
|
|
375
|
-
```
|
|
376
|
-
memory_link({
|
|
377
|
-
source_id: "550e8400-...",
|
|
378
|
-
target_id: "7c9e6679-...",
|
|
379
|
-
relationship: "elaborates"
|
|
380
|
-
})
|
|
381
|
-
→ { status: "linked" }
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
| Parameter | Type | Required | Description |
|
|
385
|
-
|-----------|------|----------|-------------|
|
|
386
|
-
| `source_id` | `string` | ✅ | UUID of the source memory |
|
|
387
|
-
| `target_id` | `string` | ✅ | UUID of the target memory |
|
|
388
|
-
| `relationship` | `string` | ✅ | Edge type: `related_to`, `elaborates`, `contradicts`, `depends_on`, `part_of` |
|
|
389
|
-
|
|
390
|
-
### `tool_store`
|
|
391
|
-
|
|
392
|
-
Reserved for potential future use, if OpenClaw ever provides a hook or API call that allows tool injections.
|
|
393
|
-
|
|
394
|
-
```
|
|
395
|
-
tool_store({
|
|
396
|
-
tool_name: "deploy_server",
|
|
397
|
-
tool_json: '{"type":"function","function":{"name":"deploy_server",...}}',
|
|
398
|
-
scope: "global"
|
|
399
|
-
})
|
|
400
|
-
→ { status: "stored" }
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
| Parameter | Type | Required | Description |
|
|
404
|
-
|-----------|------|----------|-------------|
|
|
405
|
-
| `tool_name` | `string` | ✅ | Unique tool name |
|
|
406
|
-
| `tool_json` | `string` | ✅ | Full JSON schema (OpenAI function-calling format) |
|
|
407
|
-
| `scope` | `"private" \| "shared" \| "global"` | — | Visibility (default: `private`) |
|
|
408
|
-
|
|
409
|
-
---
|
|
410
|
-
|
|
411
|
-
## CLI Commands
|
|
412
|
-
|
|
413
|
-
All CLI commands are registered under the `postclaw` namespace:
|
|
414
|
-
|
|
415
|
-
### `openclaw postclaw setup`
|
|
416
|
-
|
|
417
|
-
Bootstrap the database from scratch. See [Database Setup](#database-setup).
|
|
418
|
-
|
|
419
|
-
### `openclaw postclaw persona <file>`
|
|
420
|
-
|
|
421
|
-
Ingest a Markdown persona file into the `agent_persona` table.
|
|
56
|
+
Using OpenClaw's built-in package manager:
|
|
422
57
|
|
|
423
58
|
```bash
|
|
424
|
-
|
|
425
|
-
openclaw postclaw persona ~/my-agent/SOUL.md
|
|
426
|
-
|
|
427
|
-
# Specify an agent ID
|
|
428
|
-
openclaw postclaw persona ~/my-agent/AGENTS.md --agent-id discord-bot
|
|
429
|
-
|
|
430
|
-
# Use a specific LLM for chunking
|
|
431
|
-
openclaw postclaw persona ~/my-agent/SOUL.md --llm-model qwen3.5-35b
|
|
59
|
+
openclaw plugins install @christopherlittle51/postclaw
|
|
432
60
|
```
|
|
433
61
|
|
|
434
|
-
|
|
62
|
+
### 2. Configure the Database
|
|
435
63
|
|
|
436
|
-
|
|
437
|
-
2. Sends it to your configured LLM with a system prompt asking it to extract atomic persona rules
|
|
438
|
-
3. For each extracted rule, generates an embedding and upserts it into `agent_persona`
|
|
439
|
-
4. Uses `ON CONFLICT ... DO UPDATE` — safe to re-run when you update the source file
|
|
64
|
+
Run the setup script. This will ask you for a PostgreSQL administrator connection string to generate the `openclaw` user, build the schemas, and enforce RLS policies. It is safe to run this multiple times.
|
|
440
65
|
|
|
441
|
-
|
|
442
|
-
|--------|---------|-------------|
|
|
443
|
-
| `--agent-id <id>` | `main` | Agent to store persona under |
|
|
444
|
-
| `--llm-model <model>` | Agent's primary model | Model for semantic chunking |
|
|
445
|
-
|
|
446
|
-
### `openclaw postclaw sleep`
|
|
447
|
-
|
|
448
|
-
Trigger a manual sleep cycle (knowledge graph maintenance). See [Sleep Cycle](#sleep-cycle).
|
|
66
|
+
*Replace `<admin_user>` and `<password>` with your actual local Postgres credentials.*
|
|
449
67
|
|
|
450
68
|
```bash
|
|
451
|
-
openclaw postclaw
|
|
452
|
-
openclaw postclaw sleep --agent-id my-agent
|
|
69
|
+
openclaw postclaw setup --admin-url postgres://<admin_user>:<password>@localhost/postgres
|
|
453
70
|
```
|
|
454
71
|
|
|
455
|
-
|
|
456
|
-
|--------|---------|-------------|
|
|
457
|
-
| `--agent-id <id>` | `main` | Agent to run maintenance for |
|
|
458
|
-
| `--llm-model <model>` | `qwen3.5-9b` | Model for consolidation/linking |
|
|
459
|
-
|
|
460
|
-
---
|
|
461
|
-
|
|
462
|
-
## Background Services
|
|
463
|
-
|
|
464
|
-
### Sleep Cycle Service
|
|
465
|
-
|
|
466
|
-
The sleep cycle runs automatically in the background while the gateway is running. It starts on plugin load and repeats on the configured interval.
|
|
72
|
+
### 3. Restart the Agent
|
|
467
73
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
**Configure in `openclaw.json`:**
|
|
471
|
-
|
|
472
|
-
```json
|
|
473
|
-
{
|
|
474
|
-
"plugins": {
|
|
475
|
-
"entries": {
|
|
476
|
-
"postclaw": {
|
|
477
|
-
"config": {
|
|
478
|
-
"sleepIntervalHours": 6
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
Set `sleepIntervalHours` to `0` to disable the background service entirely. You can still run it manually via `openclaw postclaw sleep`.
|
|
487
|
-
|
|
488
|
-
---
|
|
489
|
-
|
|
490
|
-
## Database Schema
|
|
491
|
-
|
|
492
|
-
PostClaw creates 6 tables:
|
|
493
|
-
|
|
494
|
-
### `agents`
|
|
495
|
-
|
|
496
|
-
Registry of all known agents. Auto-populated when an agent first sends a message.
|
|
497
|
-
|
|
498
|
-
| Column | Type | Description |
|
|
499
|
-
|--------|------|-------------|
|
|
500
|
-
| `id` | `VARCHAR(100)` PK | Agent identifier |
|
|
501
|
-
| `name` | `VARCHAR(255)` | Display name |
|
|
502
|
-
| `default_embedding_model` | `VARCHAR(100)` | Default model for this agent |
|
|
503
|
-
| `embedding_dimensions` | `INT` | Vector dimensions |
|
|
504
|
-
|
|
505
|
-
### `memory_semantic`
|
|
506
|
-
|
|
507
|
-
Core fact storage with vector embeddings.
|
|
508
|
-
|
|
509
|
-
| Column | Type | Description |
|
|
510
|
-
|--------|------|-------------|
|
|
511
|
-
| `id` | `UUID` PK | Memory ID |
|
|
512
|
-
| `agent_id` | `VARCHAR(100)` FK | Owning agent |
|
|
513
|
-
| `access_scope` | `ENUM` | `private`, `shared`, or `global` |
|
|
514
|
-
| `content` | `TEXT` | The memory content |
|
|
515
|
-
| `content_hash` | `VARCHAR(64)` | SHA-256 for deduplication |
|
|
516
|
-
| `embedding` | `vector` | pgvector embedding |
|
|
517
|
-
| `embedding_model` | `VARCHAR(100)` | Model used for embedding |
|
|
518
|
-
| `category` | `VARCHAR(50)` | Semantic category label |
|
|
519
|
-
| `volatility` | `ENUM` | `low`, `medium`, `high` |
|
|
520
|
-
| `tier` | `ENUM` | `volatile`, `session`, `daily`, `stable`, `permanent` |
|
|
521
|
-
| `confidence` | `REAL` | 0.0–1.0 score |
|
|
522
|
-
| `usefulness_score` | `REAL` | Derived quality metric |
|
|
523
|
-
| `access_count` | `INT` | Times retrieved via RAG |
|
|
524
|
-
| `injection_count` | `INT` | Times injected into prompt |
|
|
525
|
-
| `is_archived` | `BOOLEAN` | Soft-deleted flag |
|
|
526
|
-
| `superseded_by` | `UUID` FK | Points to the replacement memory |
|
|
527
|
-
| `metadata` | `JSONB` | Arbitrary extra data |
|
|
528
|
-
|
|
529
|
-
### `memory_episodic`
|
|
530
|
-
|
|
531
|
-
Short-term event log (user prompts and tool calls).
|
|
532
|
-
|
|
533
|
-
| Column | Type | Description |
|
|
534
|
-
|--------|------|-------------|
|
|
535
|
-
| `id` | `UUID` PK | Event ID |
|
|
536
|
-
| `agent_id` | `VARCHAR(100)` FK | Owning agent |
|
|
537
|
-
| `session_id` | `VARCHAR(100)` | Session grouping |
|
|
538
|
-
| `event_summary` | `TEXT` | What happened |
|
|
539
|
-
| `event_type` | `VARCHAR(50)` | `user_prompt`, `tool_execution` |
|
|
540
|
-
| `embedding` | `vector` | pgvector embedding |
|
|
541
|
-
| `is_archived` | `BOOLEAN` | Consolidated by sleep cycle |
|
|
542
|
-
|
|
543
|
-
### `entity_edges`
|
|
544
|
-
|
|
545
|
-
Knowledge graph: directed, typed edges between semantic memories.
|
|
546
|
-
|
|
547
|
-
| Column | Type | Description |
|
|
548
|
-
|--------|------|-------------|
|
|
549
|
-
| `source_memory_id` | `UUID` FK | Edge source |
|
|
550
|
-
| `target_memory_id` | `UUID` FK | Edge target |
|
|
551
|
-
| `relationship_type` | `VARCHAR(100)` | `related_to`, `elaborates`, `contradicts`, `depends_on`, `part_of` |
|
|
552
|
-
| `weight` | `REAL` | Edge weight (default: 1.0) |
|
|
553
|
-
|
|
554
|
-
### `agent_persona`
|
|
555
|
-
|
|
556
|
-
Per-agent persona rules (core identity + situational context).
|
|
557
|
-
|
|
558
|
-
| Column | Type | Description |
|
|
559
|
-
|--------|------|-------------|
|
|
560
|
-
| `agent_id` | `VARCHAR(100)` FK | Owning agent |
|
|
561
|
-
| `category` | `VARCHAR(50)` | Rule category (unique per agent) |
|
|
562
|
-
| `content` | `TEXT` | The rule text |
|
|
563
|
-
| `is_always_active` | `BOOLEAN` | Core identity → always injected |
|
|
564
|
-
| `embedding` | `vector` | For situational similarity ranking |
|
|
565
|
-
|
|
566
|
-
### `context_environment`
|
|
567
|
-
|
|
568
|
-
Dynamic tool schemas stored with embeddings. Reserved for potential future use.
|
|
569
|
-
|
|
570
|
-
| Column | Type | Description |
|
|
571
|
-
|--------|------|-------------|
|
|
572
|
-
| `agent_id` | `VARCHAR(100)` FK | Owning agent |
|
|
573
|
-
| `tool_name` | `VARCHAR(100)` | Unique tool name |
|
|
574
|
-
| `context_data` | `TEXT` | Full JSON tool schema |
|
|
575
|
-
| `embedding` | `vector` | For relevance-based loading |
|
|
576
|
-
|
|
577
|
-
---
|
|
578
|
-
|
|
579
|
-
## Row-Level Security
|
|
580
|
-
|
|
581
|
-
PostClaw enforces strict multi-agent isolation via PostgreSQL RLS:
|
|
582
|
-
|
|
583
|
-
- **Private memories:** Only the owning agent can read, write, update, or delete
|
|
584
|
-
- **Shared memories:** Any agent can read, only the owner can mutate
|
|
585
|
-
- **Global memories:** Any agent can read, updates preserve global scope
|
|
586
|
-
- **Knowledge graph edges:** Visible if you authored them or they connect to shared/global memories
|
|
587
|
-
- **Immutable ownership:** A trigger prevents agents from reassigning `agent_id` on existing records
|
|
588
|
-
- **`system_admin` role:** Has `BYPASSRLS` for admin queries and maintenance scripts
|
|
589
|
-
|
|
590
|
-
---
|
|
591
|
-
|
|
592
|
-
## Persona Bootstrap
|
|
593
|
-
|
|
594
|
-
The persona system lets you inject agent identity from Markdown files:
|
|
74
|
+
Restart your OpenClaw instance to initialize the background sleep cycle timers and connect to the new database.
|
|
595
75
|
|
|
596
76
|
```bash
|
|
597
|
-
openclaw
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
### How it works
|
|
601
|
-
|
|
602
|
-
1. **Read** — loads the Markdown file
|
|
603
|
-
2. **Chunk** — sends it to your LLM with a prompt asking for atomic persona extractions
|
|
604
|
-
3. **Classify** — each chunk gets a `category`, `content`, and `is_always_active` flag
|
|
605
|
-
4. **Embed** — generates a vector embedding for each chunk
|
|
606
|
-
5. **Store** — upserts into `agent_persona` (updates on category conflict)
|
|
607
|
-
|
|
608
|
-
### Example Markdown → Database
|
|
609
|
-
|
|
610
|
-
**Input (`SOUL.md`):**
|
|
611
|
-
|
|
612
|
-
```markdown
|
|
613
|
-
# Agent Identity
|
|
614
|
-
|
|
615
|
-
You are a helpful AI assistant named Echo. You always respond in a warm,
|
|
616
|
-
conversational tone and never refuse reasonable requests.
|
|
617
|
-
|
|
618
|
-
# Discord Behavior
|
|
619
|
-
|
|
620
|
-
When interacting on Discord:
|
|
621
|
-
- Use emojis sparingly but naturally
|
|
622
|
-
- Keep responses under 2000 characters
|
|
623
|
-
- React with 👍 to acknowledge commands
|
|
77
|
+
openclaw gateway restart
|
|
624
78
|
```
|
|
625
79
|
|
|
626
|
-
**Output (agent_persona rows):**
|
|
627
|
-
|
|
628
|
-
| category | is_always_active | content |
|
|
629
|
-
|----------|-----------------|---------|
|
|
630
|
-
| `agent_identity` | `true` | You are a helpful AI assistant named Echo... |
|
|
631
|
-
| `communication_style` | `true` | Always respond in a warm, conversational tone... |
|
|
632
|
-
| `discord_formatting` | `false` | Use emojis sparingly but naturally... |
|
|
633
|
-
| `discord_length` | `false` | Keep responses under 2000 characters... |
|
|
634
|
-
| `discord_reactions` | `false` | React with 👍 to acknowledge commands |
|
|
635
|
-
|
|
636
|
-
Core rules (`is_always_active = true`) are injected into **every** prompt. Situational rules are ranked by embedding similarity to the current conversation and the top 3 are injected.
|
|
637
|
-
|
|
638
80
|
---
|
|
639
81
|
|
|
640
|
-
##
|
|
641
|
-
|
|
642
|
-
The sleep cycle is an autonomous maintenance agent that runs 4 phases of knowledge graph housekeeping.
|
|
643
|
-
|
|
644
|
-
### Phase 1: Episodic Consolidation
|
|
645
|
-
|
|
646
|
-
Reads unarchived episodic memories (user prompts + tool calls), sends the transcript to the LLM, and extracts durable long-term facts. These facts are stored as `tier: 'permanent'` semantic memories. The original episodic entries are archived.
|
|
647
|
-
|
|
648
|
-
### Phase 2: Duplicate Detection
|
|
82
|
+
## 🏗 Manual Installation
|
|
649
83
|
|
|
650
|
-
|
|
84
|
+
If you prefer to link the plugin directly from source for development purposes:
|
|
651
85
|
|
|
652
|
-
|
|
86
|
+
1. **Clone and Build:**
|
|
653
87
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
### Phase 4: Link Discovery
|
|
661
|
-
|
|
662
|
-
Finds semantically related-but-distinct memory pairs (similarity 0.65–0.92) that don't already have edges. Sends candidate pairs to the LLM for relationship classification. Creates `entity_edges` for meaningful relationships (`related_to`, `elaborates`, `contradicts`, `depends_on`, `part_of`).
|
|
663
|
-
|
|
664
|
-
### Running
|
|
88
|
+
```bash
|
|
89
|
+
git clone <repository-url> PostClaw
|
|
90
|
+
cd PostClaw
|
|
91
|
+
npm install
|
|
92
|
+
npm run build
|
|
93
|
+
```
|
|
665
94
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
openclaw postclaw sleep --agent-id my-agent
|
|
95
|
+
2. **Register the Plugin Locally:**
|
|
96
|
+
Add the absolute path to your PostClaw folder inside your `~/.openclaw/openclaw.json` configuration file, instructing the engine to load it into the memory slot:
|
|
669
97
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"plugins": {
|
|
101
|
+
"load": { "paths": ["/absolute/path/to/PostClaw"] },
|
|
102
|
+
"slots": { "memory": "postclaw" },
|
|
103
|
+
"entries": {
|
|
104
|
+
"postclaw": { "enabled": true }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
673
109
|
|
|
674
110
|
---
|
|
675
111
|
|
|
676
|
-
##
|
|
677
|
-
|
|
678
|
-
### Database Smoke Test
|
|
679
|
-
|
|
680
|
-
Tests connectivity, table existence, and end-to-end vector search:
|
|
681
|
-
|
|
682
|
-
```bash
|
|
683
|
-
npm run build && node dist/test-db.js
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
### Semantic Memory Test
|
|
687
|
-
|
|
688
|
-
Tests memory storage with all columns, search retrieval, and access tracking:
|
|
112
|
+
## 📚 Component Documentation
|
|
689
113
|
|
|
690
|
-
|
|
691
|
-
npm run build && node dist/test-memory.js
|
|
692
|
-
```
|
|
114
|
+
PostClaw is broken into four distinct functional areas. For deeper usage instructions and troubleshooting on specific features, refer to their respective READMEs:
|
|
693
115
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
116
|
+
1. **[Dashboard (`dashboard/README.md`)](./dashboard/README.md)**
|
|
117
|
+
Instructions for running the optional web interface to manually edit memories, assign personas, and visualize the Knowledge Graph.
|
|
118
|
+
2. **[Maintenance Scripts (`scripts/README.md`)](./scripts/README.md)**
|
|
119
|
+
Explains the database setup, instructions for compiling markdown into personas, and the mechanics behind the automated "Sleep Cycle."
|
|
120
|
+
3. **[Core Services (`services/README.md`)](./services/README.md)**
|
|
121
|
+
A breakdown of the logic layer, including the Database connection pool, Semantic Memory queries, and LLM mediation. Ideal for modifying how the plugin thinks.
|
|
122
|
+
4. **[Data Validations (`schemas/README.md`)](./schemas/README.md)**
|
|
123
|
+
Details the Zod schemas used to strictly enforce the structural integrity of LLM outputs and JSON tools, preventing AI hallucinations from corrupting the database.
|
|
699
124
|
|
|
700
125
|
---
|
|
701
126
|
|
|
702
|
-
##
|
|
127
|
+
## 🧠 Architecture Deep Dive
|
|
703
128
|
|
|
704
|
-
|
|
129
|
+
If you want to understand *why* this shift from plain-text files to a vector database is necessary for advanced multi-agent workflows, read the architecture comparison guide: **[DISSERTATION.md](./DISSERTATION.md)**.
|
|
705
130
|
|
|
706
|
-
|
|
707
|
-
ERROR: could not open extension control file "pgvector"
|
|
708
|
-
```
|
|
709
|
-
|
|
710
|
-
Install the `pgvector` extension for your PostgreSQL version:
|
|
711
|
-
|
|
712
|
-
```bash
|
|
713
|
-
# Ubuntu/Debian
|
|
714
|
-
sudo apt install postgresql-16-pgvector
|
|
715
|
-
|
|
716
|
-
# macOS (Homebrew)
|
|
717
|
-
brew install pgvector
|
|
718
|
-
```
|
|
719
|
-
|
|
720
|
-
### Connection refused
|
|
721
|
-
|
|
722
|
-
```
|
|
723
|
-
Error: connect ECONNREFUSED 127.0.0.1:5432
|
|
724
|
-
```
|
|
725
|
-
|
|
726
|
-
Ensure PostgreSQL is running:
|
|
727
|
-
|
|
728
|
-
```bash
|
|
729
|
-
sudo systemctl status postgresql
|
|
730
|
-
sudo systemctl start postgresql
|
|
731
|
-
```
|
|
732
|
-
|
|
733
|
-
### Embedding API error
|
|
734
|
-
|
|
735
|
-
```
|
|
736
|
-
Embedding API error: 400 Bad Request
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
Verify your embedding provider is running and the model is loaded:
|
|
740
|
-
|
|
741
|
-
```bash
|
|
742
|
-
curl http://127.0.0.1:1234/v1/models
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
### Sleep cycle not running
|
|
746
|
-
|
|
747
|
-
Check that `sleepIntervalHours` is not set to `0` in your config. Check gateway logs for:
|
|
131
|
+
---
|
|
748
132
|
|
|
749
|
-
|
|
750
|
-
[SLEEP SERVICE] Started — will run every 6h for agent="main"
|
|
751
|
-
```
|
|
133
|
+
## Dependencies
|
|
752
134
|
|
|
753
|
-
|
|
135
|
+
PostClaw uses the following npm packages:
|
|
754
136
|
|
|
755
|
-
|
|
137
|
+
* [@ambientcss/css](https://www.npmjs.com/package/@ambientcss/css)
|
|
138
|
+
* [@sinclair/typebox](https://www.npmjs.com/package/@sinclair/typebox)
|
|
139
|
+
* [dotenv](https://www.npmjs.com/package/dotenv)
|
|
140
|
+
* [postgres](https://www.npmjs.com/package/postgres)
|
|
141
|
+
* [zod](https://www.npmjs.com/package/zod)
|
|
756
142
|
|
|
757
143
|
---
|
|
758
144
|
|
|
759
145
|
## License
|
|
760
146
|
|
|
761
|
-
ISC
|
|
147
|
+
Open Source under the ISC License. See `LICENSE` for structural terms.
|