https://github.com/calebwin/pgclaw
A "Clawdbot" in every row with 400 lines of Postgres SQL
https://github.com/calebwin/pgclaw
Last synced: 3 months ago
JSON representation
A "Clawdbot" in every row with 400 lines of Postgres SQL
- Host: GitHub
- URL: https://github.com/calebwin/pgclaw
- Owner: calebwin
- License: mit
- Created: 2026-02-12T17:30:08.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-02-12T17:32:22.000Z (5 months ago)
- Last Synced: 2026-02-27T20:55:15.778Z (4 months ago)
- Language: Rust
- Size: 50.8 KB
- Stars: 206
- Watchers: 1
- Forks: 11
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# pgclaw
> "What if I had an AI assistant in every row of my Postgres table?"
I asked myself this a few weeks back and pgclaw is what I came up with: an open-source Postgres extension that introduces a `claw` data type to instantiate an AI agent - either a simple LLM or an "OpenClaw" agent - as a Postgres column.
With pgclaw, store your AI agents with the rest of your data. Supports:
* Simple LLM agents and more stateful "OpenClaw" agents
* Any LLM provider via [rig](https://docs.rig.rs): Anthropic, OpenAI, Ollama, Gemini, Groq, Together, DeepSeek, Mistral, Perplexity, Cohere, xAI, OpenRouter, and more
* A "Claude Code" in each row via [claude-agent-sdk](https://crates.io/crates/claude-agent-sdk): agents that can read/write files, run code, and use tools
* [ACID](https://en.wikipedia.org/wiki/ACID) compliance, point-in-time recovery, JOINs, and all of the other [great features](https://www.postgresql.org/about/) of Postgres
* any language with a Postgres client
## Quick Start
**Prerequisites:** Rust toolchain and PostgreSQL 17 dev headers.
```bash
cargo install cargo-pgrx
cargo pgrx init --pg17 download
git clone https://github.com/calebwin/pgclaw.git
cd pgclaw
cargo pgrx install
```
Then in `postgresql.conf`:
```
shared_preload_libraries = 'pgclaw'
pgclaw.api_key = 'sk-ant-...'
pgclaw.database = 'mydb'
```
### Try it
```sql
CREATE EXTENSION pgclaw;
CREATE TABLE tickets (
id serial PRIMARY KEY,
title text,
body text,
priority text,
agent claw DEFAULT claw('Set priority to low/medium/high/critical based on urgency.')
);
SELECT claw_watch('tickets');
INSERT INTO tickets (title, body) VALUES ('Login broken', '500 error on login page');
-- ~1-2s later: priority = 'critical'
```
## The `claw` Data Type
A `claw` value binds an LLM agent to a row. Two modes:
**Inline** — just a prompt:
```sql
claw('Summarize this ticket in one sentence.')
claw('Classify sentiment.', model => 'claude-sonnet')
```
**Agent reference** — points to a reusable agent definition in `claw.agents`:
```sql
claw(agent => 'ticket-triage')
claw(agent => 'ticket-triage', model => 'claude-opus')
```
## Stateful Agents
Define reusable agents with identity, instructions, and memory:
```sql
INSERT INTO claw.agents (id, soul, instructions, memory) VALUES (
'ticket-triage',
'You are a meticulous support ticket classifier.',
'Read the ticket. Set priority (low/medium/high/critical) and summary.
If unsure, set medium and explain in summary.',
'{"patterns": []}'
);
CREATE TABLE tickets (
id serial PRIMARY KEY,
title text,
body text,
priority text,
summary text,
agent claw DEFAULT claw(agent => 'ticket-triage')
);
SELECT claw_watch('tickets');
```
The agent can update its own memory by including `{"__memory": {...}}` in its response.
## Agents with Workspaces (Claude Code)
Agents with a `workspace` field get their own filesystem directory and run via Claude Code:
```sql
INSERT INTO claw.agents (id, soul, instructions, workspace) VALUES (
'engineer',
'You are a senior engineer. You write clean, tested code.',
'Implement the change. Run tests. Update status to pass/fail.',
'auto'
);
CREATE TABLE tasks (
id serial PRIMARY KEY, task text, status text DEFAULT 'pending', diff text,
agent claw DEFAULT claw(agent => 'engineer')
);
SELECT claw_watch('tasks');
```
Requires [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) (`npm install -g @anthropic-ai/claude-code`). Workspace paths: `'auto'` uses `{pgclaw.workspace_dir}/{agent}/{table}/{pk}/`, or use a custom template like `'/data/{agent}/{table}/{pk}'`.
## Channels, Sessions, Heartbeats
```sql
INSERT INTO claw.agents (id, soul, instructions) VALUES (
'support-bot', 'You are the support bot for Acme Inc.', 'Help users with orders.'
);
INSERT INTO claw.bindings (channel, agent_id) VALUES ('telegram', 'support-bot');
INSERT INTO claw.heartbeats (agent_id, every) VALUES ('support-bot', '30 minutes');
SELECT claw.route('telegram', '*', 'user123', NULL, 'My order is late');
-- Pick up responses from claw.outbox
```
## Configuration
```
# Required
pgclaw.api_key = 'sk-ant-...' # API key for your provider
pgclaw.database = 'mydb' # Database for the background worker
# Optional
pgclaw.api_provider = 'anthropic' # see supported providers below
pgclaw.api_url = '' # override API endpoint
pgclaw.default_model = 'claude-sonnet-4-5-20250929' # default model for inline claw values
pgclaw.enabled = true # enable/disable processing
pgclaw.workspace_dir = '/tmp/pgclaw/workspaces' # base dir for Claude Code workspaces
```
**Supported providers:** `anthropic` (default), `openai`, `ollama`, `gemini`, `groq`, `together`, `deepseek`, `perplexity`, `cohere`, `mistral`, `moonshot`, `openrouter`, `xai`, `hyperbolic`, `mira`, `galadriel`
```
# OpenAI
pgclaw.api_provider = 'openai'
pgclaw.api_key = 'sk-...'
pgclaw.default_model = 'gpt-4o'
# Ollama (local, no API key needed)
pgclaw.api_provider = 'ollama'
pgclaw.default_model = 'llama3.1'
# OpenAI-compatible (vLLM, LM Studio, etc.)
pgclaw.api_provider = 'openai'
pgclaw.api_url = 'http://localhost:8000/v1'
```
## How It Works
1. You add a `claw` column to a table and call `claw_watch()`
2. On INSERT/UPDATE, a Postgres trigger enqueues the row to `claw.queue`
3. A Postgres background worker polls the queue:
- **LLM agents** (no workspace): builds prompt from agent config + row data, calls LLM via [rig](https://docs.rig.rs)
- **Claude Code agents** (with workspace): creates a workspace directory with `SOUL.md`, `AGENTS.md`, `context.json`, spawns Claude Code via [claude-agent-sdk](https://crates.io/crates/claude-agent-sdk)
4. The response is parsed for column updates (JSON `{"column": "value"}`) and applied back to the row
5. Conversation history is preserved in `claw.history` for multi-turn interactions
## License
MIT of course!