Reference implementation of Lineage-Aware Memory Governance (IEEE Access, DOI 10.1109/ACCESS.2026.3730363) on PostgreSQL + pgvector
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Documented (README)
git clone https://github.com/sangaraju1988/amu-pgvectorTools overview
# amu-pgvector
[](https://doi.org/10.5281/zenodo.23025849)
Reference implementation of **Lineage-Aware Memory Governance**
(Sangaraju & Vissa, *IEEE Access*, [10.1109/ACCESS.2026.3730363](https://doi.org/10.1109/ACCESS.2026.3730363))
on PostgreSQL + [pgvector](https://github.com/pgvector/pgvector).
## The problem
Say Finance computes `avg(income)` for a customer segment and caches the
result so the next agent that asks the same question doesn't have to
recompute it. Later, a Marketing agent asks a semantically similar
question -- "what's the average customer income by segment?" -- and a
naive shared memory, gated only on the metric's name or content tags,
serves back Finance's cached result. Marketing was never permitted to see
`income`. The result itself doesn't *look* like income -- it's a number --
but it was **derived from** a column Marketing isn't permitted to touch,
and nothing about matching on metric name or content catches that. That's
the leak this project closes: gating reuse on *how a result was derived*,
not on what it looks like.
## 60-second quickstart
```bash
git clone https://github.com/sangaraju1988/amu-pgvector.git
cd amu-pgvector
docker compose up -d
psql -h localhost -p 5433 -U amu_owner -d amu_dev -f sql/amu_pgvector.sql
# password: amu_owner_password
```
```bash
uv sync --all-packages --all-extras # or: pip install amu-pgvector
```
```python
from amu_pgvector import AMUStore
from amu_pgvector.embeddings import fake_embedder
DSN = "postgresql://amu_owner:amu_owner_password@localhost:5433/amu_dev"
embed = fake_embedder(dim=1536) # swap for a real embedding model in production
admin = AMUStore(DSN)
admin.register_sensitive_column("income")
admin.grant_department_permission("Finance", "income")
admin.create_agent_role("finance_agent", "Finance", "finance_pw")
admin.create_agent_role("marketing_agent", "Marketing", "marketing_pw")
admin.record(
"SELECT avg(income) FROM customers",
{"avg": 82000},
metric_name="avg_income",
description="average customer income",
owner_department="Finance",
embed_fn=embed,
)
finance_dsn = "postgresql://finance_agent:finance_pw@localhost:5433/amu_dev"
marketing_dsn = "postgresql://marketing_agent:marketing_pw@localhost:5433/amu_dev"
AMUStore(finance_dsn).search("average customer income", k=5, embed_fn=embed)
# -> [SearchResult(metric_name='avg_income', ...)]
AMUStore(marketing_dsn).search("average customer income", k=5, embed_fn=embed)
# -> [] -- Marketing was never granted `income`, so Postgres itself
# never returns the row, regardless of how the query is asked.
```
Every line above was run against this exact repo before being written
here (see `docs/design.md` for what a from-scratch install actually looks
like). `amu_owner`/`amu_owner_password` is the docker-compose default --
change it for anything beyond local development.
## How the gate works
`amu.memory_units` is a normal Postgres table with `FORCE ROW LEVEL
SECURITY` enabled. Every write goes through a trigger that extracts the
lineage of the SQL that actually produced the cached result (via
[amu-governance](https://github.com/sangaraju1988/amu-governance)'s
`sql_lineage` module -- not self-reported by the agent), closes it over any
registered materialized-view/derived-table edges, and computes S(a): the
set of sensitive columns that lineage actually touches. A `SELECT` policy
enforces `S(a) ⊆ P(d)` -- the row is visible only if every column in S(a)
is in the requesting role's permitted set P(d) -- for every query against
the table, from every client: raw SQL, `amu.search()`, the Python client,
the LangChain integration, and the MCP server all go through the same
policy, because it's the table's policy, not any one client's filter.
```mermaid
sequenceDiagram
participant Writer as amu_writer role<br/>(trusted interception layer)
participant PG as Postgres: amu.memory_units<br/>(FORCE ROW LEVEL SECURITY)
participant Trigger as BEFORE INSERT trigger
participant Finance as finance_agent role
participant Marketing as marketing_agent role
Writer->>PG: INSERT ... lineage = {"steps":[{"table":"customers","columns_used":["income"]}]}
PG->>Trigger: compute lineage_columns, S(a), lineage_status
Trigger-->>PG: sensitive_columns = {income}, resolved
Finance->>PG: SELECT ... (session_user = finance_agent)
PG->>PG: S(a)={income} subset P(Finance)={income,...}? yes
PG-->>Finance: row returned
Marketing->>PG: SELECT ... (session_user = marketing_agent)
PG->>PG: S(a)={income} subset P(Marketing)={...}? no
PG-->>Marketing: row not returned
```
See [`docs/design.md`](docs/design.md) for how every paper concept maps to
a specific SQL object, and [`docs/sql-reference.md`](docs/sql-reference.md)
for an exhaustive reference of every table, function, role and policy.
## Security model and limits
**Protected:** cross-department leakage of a cached result's derivation
columns (the core guarantee, enforced by RLS); silent metric-definition
conflicts (`amu.check_conflict()`); a column reclassified as sensitive
*after* AMUs already exist (a trigger recomputes affected rows, no
rewrite needed); lineage closure that silently truncates a long or cyclic
derivation chain (fails closed -- marks the AMU unresolved and invisible,
rather than serving a partially-traced result).
**Explicitly out of scope:** a writer that lies about lineage (the SQL
gate trusts `amu_writer`'s input by design); inference by combining
several individually-permitted AMUs; Postgres superusers, who always
bypass RLS; timing side channels; a "convenience mode" identity option
(off by default) that's only as safe as the boundary between trusted
application code and agent-influenced code on a pooled connection.
Full writeup: [`docs/threat-model.md`](docs/threat-model.md).
## Benchmarks
Every number below is quoted directly from
[`results/SUMMARY.md`](results/SUMMARY.md), generated by
`benchmarks/generate_summary.py` from committed `results/<name>/<timestamp>/`
runs (git SHA, Postgres/pgvector versions, hardware, seed and parameters
in each run's `manifest.json`). Re-run the benchmark scripts yourself to
reproduce or challenge these; nothing here is estimated.
**Leak rate** (2000 requests over 600 synthetic AMUs, Finance/Marketing/Support):
| Condition | Served | Cross-department leaks | Leak rate |
|---|---|---|---|
| Naive (content-gated, no lineage check) | 2000 | 1010 | 50.5% |
| amu-pgvector (RLS-gated) | 990 | 0 | 0.0% |
**Latency** (p50/p95 at k=10; RLS and `hnsw.iterative_scan` each on/off,
same role/queries/data per row):
| n | RLS | iterative_scan | p50 (ms) | p95 (ms) |
|---|---|---|---|---|
| 10,000 | on | on (`amu.search()` default) | 66.8 | 70.2 |
| 10,000 | on | off | 81.9 | 88.2 |
| 10,000 | off | on | 19.5 | 21.8 |
| 10,000 | off | off | 49.2 | 52.3 |
| 100,000 | on | on (`amu.search()` default) | 712.9 | 851.2 |
| 100,000 | on | off | 43.4 | 65.7 |
| 100,000 | off | on | 376.8 | 418.5 |
| 100,000 | off | off | 46.6 | 70.9 |
Read honestly: `hnsw.iterative_scan=relaxed_order` (what `amu.search()`
uses by default, so that filtered results still hit k even when most rows
are hidden) costs real latency at scale -- roughly 16x slower than
iterative-off at 100k rows in this run. That's the price of the recall
guarantee below; if your visible fraction is consistently high, you may
prefer to query without it. 1M-row scale was not attempted: the 100k HNSW
index build alone took about 7 minutes on the machine this was run on
(Docker Desktop on macOS, sharing the host with unrelated workloads) --
recorded honestly rather than extrapolated.
**Filtered recall** (recall@10 of gated HNSW search vs. exact brute-force
over the same role's actually-visible rows, n=20,000):
| Visible fraction | recall@10 (mean) | recall@10 (min) |
|---|---|---|
| 50% | 100.0% | 100.0% |
| 10% | 100.0% | 100.0% |
| 1% | 100.0% | 100.0% |
## Integrations
- **Plain SQL** -- `sql/amu_pgvector.sql` is the artifact that matters most:
idempotent, installs on a managed Postgres as a normal database owner
(no superuser), no C extensions beyond `vector`. Works identically on
Supabase and Neon (see `submissions/supabase-neon-guide.md` for a
from-scratch tutorial covering both).
- **LangChain** -- `langchain-amu` provides `AMUVectorStore` and
`AMURetriever`. Every read runs under the store's own Postgres role, so
RLS gates LangChain the same way it gates raw SQL. See
`packages/langchain-amu/`.
- **MCP** -- `pip install amu-pgvector[mcp]` adds an `amu-pgvector-mcp`
console script exposing `amu_search`, `amu_record` and
`amu_check_conflict` as tools, gated the same way. See
`packages/amu-pgvector/src/amu_pgvector/mcp_server.py`.
## Citation
```bibtex
@article{sangaraju2026lineage,
title = {Lineage-Aware Memory Governance: A Derivation-Gated Framework
for Privacy-Preserving Column-Level Access Control in
Enterprise AI Agents},
author = {Sangaraju, Venkata and Vissa, Sudhir},
journal = {IEEE Access},
year = {2026},
doi = {10.1109/ACCESS.2026.3730363}
}
```
See [`CITATION.cff`](CITATION.cff) to also cite this software directly.
## License
MIT. See [`LICENSE`](LICENSE).
## Related
- Paper: Sangaraju & Vissa, *IEEE Access*, DOI [10.1109/ACCESS.2026.3730363](https://doi.org/10.1109/ACCESS.2026.3730363)
- Reference library: [amu-governance](https://github.com/sangaraju1988/amu-governance) ([PyPI](https://pypi.org/project/amu-governance/))
- [`docs/design.md`](docs/design.md) -- paper concepts mapped to SQL objects, plus every real gotcha found while building this
- [`docs/threat-model.md`](docs/threat-model.md) -- what's protected, what's not
- [`docs/sql-reference.md`](docs/sql-reference.md) -- every table, function, role and policy
What people ask about amu-pgvector
What is sangaraju1988/amu-pgvector?
+
sangaraju1988/amu-pgvector is tools for the Claude AI ecosystem. Reference implementation of Lineage-Aware Memory Governance (IEEE Access, DOI 10.1109/ACCESS.2026.3730363) on PostgreSQL + pgvector It has 0 GitHub stars and its last recorded update is dated 2026-09-29.
How do I install amu-pgvector?
+
You can install amu-pgvector by cloning the repository (https://github.com/sangaraju1988/amu-pgvector) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is sangaraju1988/amu-pgvector safe to use?
+
Our security agent has analyzed sangaraju1988/amu-pgvector and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains sangaraju1988/amu-pgvector?
+
sangaraju1988/amu-pgvector is maintained by sangaraju1988. The last recorded GitHub activity is dated 2026-09-29, with 0 open issues.
Are there alternatives to amu-pgvector?
+
Yes. On ClaudeWave you can browse similar tools at /categories/tools, sorted by popularity or recent activity.
Deploy amu-pgvector to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/sangaraju1988-amu-pgvector)<a href="https://claudewave.com/repo/sangaraju1988-amu-pgvector"><img src="https://claudewave.com/api/badge/sangaraju1988-amu-pgvector" alt="Featured on ClaudeWave: sangaraju1988/amu-pgvector" width="320" height="64" /></a>More Tools
A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls.
An AI skill that provides design intelligence for building professional UI/UX across multiple platforms.
🪨 why use many token when few token do trick. Viral skill + proxy for coding agents that cuts 65% of tokens by talking like a caveman.
CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies
The fastest, litest AI Gateway. Rust core with Python SDK. Call 100+ LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [Bedrock, Azure, OpenAI, Anthropic, OpenAI, VertexAI, vLLM, Nvidia NIM]
Use Claude Code, Codex, VSCode, Pi, and OpenCode (and 6 other harnesses) for free (1.3B+ free tokens) from your terminal, app, IDE, or phone, and now from the browser with native browser sessions (multi-harness + multi-model) like OpenClaw (voice supported + ToS friendly)