@polymorphism-tech/morph-spec 10.0.0 → 10.1.1
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/CLAUDE.md +2 -0
- package/README.md +2 -2
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +28 -36
- package/docs/QUICKSTART.md +31 -191
- package/framework/CLAUDE.md +2 -2
- package/framework/MORPH.md +2 -2
- package/framework/commands/morph-preflight.md +3 -3
- package/framework/docs/CLI.md +1 -1
- package/framework/hooks/shared/next-step.js +2 -2
- package/framework/mcp/registry.json +4 -4
- package/framework/rules/ai-agents-standards.md +1 -1
- package/framework/rules/data-standards.md +1 -1
- package/framework/rules/hangfire-standards.md +1 -1
- package/framework/rules/neon-auth-standards.md +1 -1
- package/framework/rules/neon-standards.md +3 -3
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +4 -3
- package/framework/skills/core/morph-plan/SKILL.md +19 -13
- package/framework/skills/core/morph-plan/references/critique.md +11 -8
- package/framework/skills/core/morph-plan/references/interview.md +18 -6
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +20 -24
- package/framework/standards/STANDARDS.meta.json +12 -19
- package/framework/standards/ai-agents/rag-custom-pgvector.md +1 -0
- package/framework/standards/architecture/stack-baseline.md +26 -3
- package/framework/standards/backend/database/postgresql/database.md +22 -1
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +33 -1
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +2 -1
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +10 -9
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +2 -2
- package/framework/standards/infrastructure/neon/neon-pgvector.md +62 -20
- package/framework/standards/infrastructure/neon/neon-platform.md +61 -0
- package/framework/standards/infrastructure/neon/neon-setup.md +14 -13
- package/framework/standards/integration/mcp/mcp-tools.md +20 -20
- package/framework/templates/docs/plan.md +4 -1
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +1 -1
- package/package.json +1 -1
- package/src/commands/state/auto-approval.js +1 -1
- package/src/commands/state/create.js +1 -1
- package/src/commands/state/gate-check.js +2 -2
- package/src/lib/detectors/index.js +1 -1
- package/src/lib/installers/memory-installer.js +1 -1
- package/src/lib/plan/checks.js +8 -1
- package/framework/standards/infrastructure/neon/neon-pgrag.md +0 -243
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
# Neon pgrag Standard
|
|
2
|
-
|
|
3
|
-
> **Scope:** neon
|
|
4
|
-
> **Layer:** 2 (on keyword)
|
|
5
|
-
> **Keywords:** pgrag, rag, chunking, embedding, reranking, retrieval
|
|
6
|
-
> **Load When:** pgrag or in-database RAG keywords detected
|
|
7
|
-
|
|
8
|
-
**Verified against:** Neon pgrag (`rag` extension family — experimental, see Core Rules). Last-verified: 2026-05-20.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
Stack: Neon Serverless Postgres
|
|
13
|
-
|
|
14
|
-
## Core Rules
|
|
15
|
-
|
|
16
|
-
- pgrag is EXPERIMENTAL -- API may change between Neon releases
|
|
17
|
-
- ALWAYS enable unstable extensions before installing: `SET neon.allow_unstable_extensions='true'`
|
|
18
|
-
- Use pgrag for simple, self-contained RAG pipelines (PDF ingestion, chunking, search)
|
|
19
|
-
- Use application-level custom RAG (a typed MAF tool over pgvector — see standard ai-agents-rag-custom-pgvector) for complex workflows requiring custom logic, multi-model orchestration, or .NET integration
|
|
20
|
-
- NEVER use pgrag local embeddings (384 dims) when your application uses a different embedding model -- dimension mismatch breaks search
|
|
21
|
-
|
|
22
|
-
## Install pgrag
|
|
23
|
-
|
|
24
|
-
```sql
|
|
25
|
-
-- Enable unstable extensions (required)
|
|
26
|
-
SET neon.allow_unstable_extensions='true';
|
|
27
|
-
|
|
28
|
-
-- Core extension
|
|
29
|
-
CREATE EXTENSION IF NOT EXISTS rag CASCADE;
|
|
30
|
-
|
|
31
|
-
-- Local embedding model (bge-small-en-v1.5, 384 dimensions, 33M params)
|
|
32
|
-
CREATE EXTENSION IF NOT EXISTS rag_bge_small_en_v15 CASCADE;
|
|
33
|
-
|
|
34
|
-
-- Local reranker (jina-reranker-v1-tiny-en, 33M params)
|
|
35
|
-
CREATE EXTENSION IF NOT EXISTS rag_jina_reranker_v1_tiny_en CASCADE;
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Text Extraction
|
|
39
|
-
|
|
40
|
-
Extract text from binary documents directly in SQL:
|
|
41
|
-
|
|
42
|
-
```sql
|
|
43
|
-
-- Extract text from PDF
|
|
44
|
-
SELECT rag.text_from_pdf(pg_read_binary_file('/path/to/document.pdf'));
|
|
45
|
-
|
|
46
|
-
-- Extract text from DOCX
|
|
47
|
-
SELECT rag.text_from_docx(pg_read_binary_file('/path/to/document.docx'));
|
|
48
|
-
|
|
49
|
-
-- Convert HTML to Markdown
|
|
50
|
-
SELECT rag.markdown_from_html('<h1>Title</h1><p>Content here</p>');
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### From a Documents Table
|
|
54
|
-
|
|
55
|
-
```sql
|
|
56
|
-
CREATE TABLE raw_documents (
|
|
57
|
-
id SERIAL PRIMARY KEY,
|
|
58
|
-
filename TEXT NOT NULL,
|
|
59
|
-
content BYTEA NOT NULL,
|
|
60
|
-
extracted_text TEXT
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
-- Extract text on insert
|
|
64
|
-
UPDATE raw_documents
|
|
65
|
-
SET extracted_text = rag.text_from_pdf(content)
|
|
66
|
-
WHERE filename LIKE '%.pdf' AND extracted_text IS NULL;
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Chunking Strategies
|
|
70
|
-
|
|
71
|
-
### Character-Based Chunking
|
|
72
|
-
|
|
73
|
-
Splits text by character count with overlap for context continuity:
|
|
74
|
-
|
|
75
|
-
```sql
|
|
76
|
-
-- Split into chunks of 1000 chars with 200 char overlap
|
|
77
|
-
SELECT unnest(
|
|
78
|
-
rag.chunks_by_character_count(
|
|
79
|
-
'Your long document text here...',
|
|
80
|
-
1000, -- max_chars per chunk
|
|
81
|
-
200 -- overlap chars
|
|
82
|
-
)
|
|
83
|
-
);
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Token-Based Chunking
|
|
87
|
-
|
|
88
|
-
Uses the bge-small-en-v1.5 tokenizer for model-aware splitting:
|
|
89
|
-
|
|
90
|
-
```sql
|
|
91
|
-
-- Split into chunks of 512 tokens with 50 token overlap
|
|
92
|
-
SELECT unnest(
|
|
93
|
-
rag_bge_small_en_v15.chunks_by_token_count(
|
|
94
|
-
'Your long document text here...',
|
|
95
|
-
512, -- max_tokens per chunk
|
|
96
|
-
50 -- overlap tokens
|
|
97
|
-
)
|
|
98
|
-
);
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Embedding Generation
|
|
102
|
-
|
|
103
|
-
### Local Embeddings (bge-small-en-v1.5)
|
|
104
|
-
|
|
105
|
-
Zero-cost, runs on the database server. Produces 384-dimension vectors:
|
|
106
|
-
|
|
107
|
-
```sql
|
|
108
|
-
-- Embedding for a document passage (includes "passage:" prefix internally)
|
|
109
|
-
SELECT rag_bge_small_en_v15.embedding_for_passage('Neon is a serverless Postgres platform');
|
|
110
|
-
|
|
111
|
-
-- Embedding for a search query (includes "query:" prefix internally)
|
|
112
|
-
SELECT rag_bge_small_en_v15.embedding_for_query('What is Neon?');
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### OpenAI Embeddings (text-embedding-3-small)
|
|
116
|
-
|
|
117
|
-
Remote API call, produces 1536-dimension vectors:
|
|
118
|
-
|
|
119
|
-
```sql
|
|
120
|
-
-- Set API key (per session)
|
|
121
|
-
SET neon.ai_api_key = 'sk-...';
|
|
122
|
-
|
|
123
|
-
-- Generate embedding via OpenAI
|
|
124
|
-
SELECT rag.openai_text_embedding_3_small('Neon is a serverless Postgres platform');
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## Full RAG Pipeline Example
|
|
128
|
-
|
|
129
|
-
```sql
|
|
130
|
-
-- 1. Create chunks table
|
|
131
|
-
CREATE TABLE chunks (
|
|
132
|
-
id SERIAL PRIMARY KEY,
|
|
133
|
-
document_id INT REFERENCES raw_documents(id),
|
|
134
|
-
chunk_text TEXT NOT NULL,
|
|
135
|
-
embedding vector(384)
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
-- 2. Chunk and embed a document
|
|
139
|
-
WITH doc AS (
|
|
140
|
-
SELECT id, rag.text_from_pdf(content) AS full_text
|
|
141
|
-
FROM raw_documents WHERE id = 1
|
|
142
|
-
),
|
|
143
|
-
chunked AS (
|
|
144
|
-
SELECT doc.id AS document_id, unnest(
|
|
145
|
-
rag.chunks_by_character_count(doc.full_text, 1000, 200)
|
|
146
|
-
) AS chunk_text
|
|
147
|
-
FROM doc
|
|
148
|
-
)
|
|
149
|
-
INSERT INTO chunks (document_id, chunk_text, embedding)
|
|
150
|
-
SELECT document_id, chunk_text,
|
|
151
|
-
rag_bge_small_en_v15.embedding_for_passage(chunk_text)
|
|
152
|
-
FROM chunked;
|
|
153
|
-
|
|
154
|
-
-- 3. Create HNSW index
|
|
155
|
-
CREATE INDEX idx_chunks_embedding ON chunks
|
|
156
|
-
USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Similarity Search
|
|
160
|
-
|
|
161
|
-
```sql
|
|
162
|
-
-- Find top 10 similar chunks
|
|
163
|
-
SELECT id, chunk_text,
|
|
164
|
-
1 - (embedding <=> rag_bge_small_en_v15.embedding_for_query('What is Neon?')) AS similarity
|
|
165
|
-
FROM chunks
|
|
166
|
-
ORDER BY embedding <=> rag_bge_small_en_v15.embedding_for_query('What is Neon?')
|
|
167
|
-
LIMIT 10;
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## Reranking
|
|
171
|
-
|
|
172
|
-
Reranking refines initial vector search results using a cross-encoder model for higher accuracy:
|
|
173
|
-
|
|
174
|
-
```sql
|
|
175
|
-
-- Rerank top 10 vector results down to top 5
|
|
176
|
-
WITH vector_matches AS (
|
|
177
|
-
SELECT id, chunk_text,
|
|
178
|
-
1 - (embedding <=> rag_bge_small_en_v15.embedding_for_query('What is Neon?')) AS similarity
|
|
179
|
-
FROM chunks
|
|
180
|
-
ORDER BY embedding <=> rag_bge_small_en_v15.embedding_for_query('What is Neon?')
|
|
181
|
-
LIMIT 10
|
|
182
|
-
)
|
|
183
|
-
SELECT id, chunk_text, similarity,
|
|
184
|
-
rag_jina_reranker_v1_tiny_en.rerank_distance('What is Neon?', chunk_text) AS rerank_score
|
|
185
|
-
FROM vector_matches
|
|
186
|
-
ORDER BY rerank_score ASC
|
|
187
|
-
LIMIT 5;
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## LLM Integration in SQL
|
|
191
|
-
|
|
192
|
-
Send context + question to an LLM directly from SQL:
|
|
193
|
-
|
|
194
|
-
```sql
|
|
195
|
-
-- Set API key
|
|
196
|
-
SET neon.ai_api_key = 'sk-...';
|
|
197
|
-
|
|
198
|
-
-- Ask a question with retrieved context
|
|
199
|
-
WITH context AS (
|
|
200
|
-
SELECT string_agg(chunk_text, E'\n---\n') AS combined_context
|
|
201
|
-
FROM (
|
|
202
|
-
SELECT chunk_text FROM chunks
|
|
203
|
-
ORDER BY embedding <=> rag_bge_small_en_v15.embedding_for_query('What is Neon?')
|
|
204
|
-
LIMIT 5
|
|
205
|
-
) top_chunks
|
|
206
|
-
)
|
|
207
|
-
SELECT rag.openai_chat_completion(
|
|
208
|
-
json_build_object(
|
|
209
|
-
'model', 'gpt-4o',
|
|
210
|
-
'messages', json_build_array(
|
|
211
|
-
json_build_object('role', 'system', 'content',
|
|
212
|
-
'Answer based on the provided context. If unsure, say so.'),
|
|
213
|
-
json_build_object('role', 'user', 'content',
|
|
214
|
-
format('Context:\n%s\n\nQuestion: What is Neon?', context.combined_context))
|
|
215
|
-
)
|
|
216
|
-
)
|
|
217
|
-
) FROM context;
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## When to Use pgrag vs Application-Level RAG
|
|
221
|
-
|
|
222
|
-
| Factor | pgrag (In-Database) | SK + pgvector (Application) |
|
|
223
|
-
|--------|---------------------|----------------------------|
|
|
224
|
-
| Setup complexity | Minimal -- SQL only | Requires .NET service layer |
|
|
225
|
-
| Embedding model | Local (384d) or OpenAI | Any model via SK connectors |
|
|
226
|
-
| Reranking | Built-in (Jina) | Custom implementation |
|
|
227
|
-
| Custom logic | Limited to SQL | Full C# flexibility |
|
|
228
|
-
| Multi-model orchestration | Not supported | Native SK capability |
|
|
229
|
-
| Production readiness | Experimental | Stable (SK GA) |
|
|
230
|
-
| Cost | Zero for local models | API costs for remote models |
|
|
231
|
-
| Best for | Prototyping, simple RAG, SQL-only environments | Production .NET applications, complex pipelines |
|
|
232
|
-
|
|
233
|
-
**Recommendation:** Start with pgrag for prototyping and validation. Migrate to custom RAG (a typed MAF vector-search tool over pgvector — see ai-agents-rag-custom-pgvector) for production .NET applications that need custom retrieval logic, multi-model orchestration, or MAF agent integration.
|
|
234
|
-
|
|
235
|
-
## Common Mistakes
|
|
236
|
-
|
|
237
|
-
| Wrong | Right | Why |
|
|
238
|
-
|-------|-------|-----|
|
|
239
|
-
| Missing `neon.allow_unstable_extensions` | `SET neon.allow_unstable_extensions='true'` | pgrag won't install without it |
|
|
240
|
-
| Mixing local (384d) and OpenAI (1536d) embeddings | Use one model consistently per column | Dimension mismatch breaks similarity search |
|
|
241
|
-
| No HNSW index on chunks table | Create index after initial data load | Full table scan on every search |
|
|
242
|
-
| Using pgrag in production without testing | Validate with representative data first | Extension is experimental, may change |
|
|
243
|
-
| Storing API key in SQL scripts | Use session variables or environment config | Keys in scripts leak to version control |
|