@yottagraph-app/aether-instructions 1.1.42 → 1.1.44
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/AGENTS.md +12 -30
- package/CLAUDE.md +1 -0
- package/README.md +13 -9
- package/commands/build_my_app.md +7 -8
- package/commands/deploy_agent.md +7 -7
- package/commands/update_branding.md +1 -1
- package/commands/update_instructions.md +34 -21
- package/package.json +4 -5
- package/skills/aether/SKILL.md +57 -0
- package/{rules/agents-data.mdc → skills/aether/agents-data.md} +3 -6
- package/{rules/agents.mdc → skills/aether/agents.md} +42 -28
- package/{rules/architecture.mdc → skills/aether/architecture.md} +14 -20
- package/{rules/branding.mdc → skills/aether/branding.md} +7 -12
- package/{rules/cookbook-data.mdc → skills/aether/cookbook-data.md} +13 -28
- package/{rules/cookbook.mdc → skills/aether/cookbook.md} +2 -9
- package/{rules/cursor-cloud.mdc → skills/aether/cursor-cloud.md} +1 -6
- package/{rules/data.mdc → skills/aether/data.md} +80 -70
- package/{rules/deployment.mdc → skills/aether/deployment.md} +1 -6
- package/{rules/design.mdc → skills/aether/design.md} +1 -6
- package/{rules/env.mdc → skills/aether/env.md} +0 -5
- package/{rules/git-support.mdc → skills/aether/git-support.md} +4 -9
- package/{rules/instructions_warning.mdc → skills/aether/instructions_warning.md} +12 -13
- package/{rules/local-setup.mdc → skills/aether/local-setup.md} +1 -6
- package/{rules/mcp-servers.mdc → skills/aether/mcp-servers.md} +3 -7
- package/{rules/pref.mdc → skills/aether/pref.md} +9 -14
- package/skills/aether/server-data.md +48 -0
- package/skills/aether/server.md +60 -0
- package/{rules/something-broke.mdc → skills/aether/something-broke.md} +3 -7
- package/{rules/server.mdc → skills/aether/storage.md} +78 -108
- package/{rules/ui.mdc → skills/aether/ui.md} +2 -6
- package/skills/elemental-mcp-patterns/SKILL.md +57 -51
- package/variants/mcp-only/commands/build_my_app.md +6 -6
- package/variants/mcp-only/{rules/agents-data.mdc → skills/aether/agents-data.md} +0 -6
- package/variants/mcp-only/{rules/cookbook-data.mdc → skills/aether/cookbook-data.md} +3 -6
- package/variants/mcp-only/{rules/data.mdc → skills/aether/data.md} +1 -6
- package/variants/mcp-only/{rules/server-data.mdc → skills/aether/server-data.md} +9 -15
- package/rules/server-data.mdc +0 -54
- package/rules/storage.mdc +0 -54
|
@@ -27,7 +27,7 @@ from google.adk.tools.mcp_tool import McpToolset
|
|
|
27
27
|
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
> **Do NOT use `SseConnectionParams`.**
|
|
30
|
+
> **Do NOT use `SseConnectionParams`.** `SseConnectionParams` is for
|
|
31
31
|
> legacy SSE-based MCP servers. Using it against the Elemental MCP server
|
|
32
32
|
> will silently fail — the agent starts with zero tools and no error is
|
|
33
33
|
> raised. The LLM then hallucinates tool calls.
|
|
@@ -95,12 +95,14 @@ McpToolset(
|
|
|
95
95
|
|
|
96
96
|
If `McpToolset` cannot connect, **no error is raised at agent startup**.
|
|
97
97
|
The agent simply has zero MCP tools. Symptoms:
|
|
98
|
+
|
|
98
99
|
- The agent never calls any `elemental_*` tools
|
|
99
100
|
- The LLM fabricates code or data instead of using tools
|
|
100
101
|
- No connection error in logs
|
|
101
102
|
|
|
102
103
|
**Always validate** the MCP URL and check for tool availability during
|
|
103
104
|
development. If MCP tools aren't working, verify:
|
|
105
|
+
|
|
104
106
|
1. The URL is correct (check `broadchurch.yaml` `mcp.elemental` or env var)
|
|
105
107
|
2. You're using `StreamableHTTPConnectionParams` (not `SseConnectionParams`)
|
|
106
108
|
3. The MCP server is reachable (try `curl -X POST <url> -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'`)
|
|
@@ -120,42 +122,42 @@ adk web
|
|
|
120
122
|
|
|
121
123
|
## Tool Quick Reference
|
|
122
124
|
|
|
123
|
-
| Tool
|
|
124
|
-
|
|
125
|
-
| `elemental_get_entity`
|
|
126
|
-
| `elemental_get_related`
|
|
127
|
-
| `elemental_get_events`
|
|
128
|
-
| `elemental_get_citations`
|
|
129
|
-
| `elemental_get_schema`
|
|
130
|
-
| `elemental_get_relationships`
|
|
131
|
-
| `elemental_graph_neighborhood` | Get the most influential neighbors of an entity
|
|
132
|
-
| `elemental_graph_sentiment`
|
|
133
|
-
| `elemental_introspect`
|
|
134
|
-
| `elemental_traverse`
|
|
135
|
-
| `elemental_health`
|
|
125
|
+
| Tool | Use when you need to... |
|
|
126
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
127
|
+
| `elemental_get_entity` | Resolve an entity by name or ID, fetch its properties (supports `history` for time-series) |
|
|
128
|
+
| `elemental_get_related` | Find related entities (requires `related_flavor`); use `direction` and `relationship_types` to filter |
|
|
129
|
+
| `elemental_get_events` | Get typed events with categories, dates, participants |
|
|
130
|
+
| `elemental_get_citations` | Look up provenance for `ref` hashes returned by other tools |
|
|
131
|
+
| `elemental_get_schema` | Discover flavors (entity types), property names, and property types |
|
|
132
|
+
| `elemental_get_relationships` | Get relationship types and counts between two entities |
|
|
133
|
+
| `elemental_graph_neighborhood` | Get the most influential neighbors of an entity |
|
|
134
|
+
| `elemental_graph_sentiment` | Sentiment time series, trend analysis, and statistics from news articles |
|
|
135
|
+
| `elemental_introspect` | Discover what data **actually exists**: entity counts, populated properties with fill rates, sample values. Use before building features to verify data availability. |
|
|
136
|
+
| `elemental_traverse` | Stateful graph navigation — build a working set of entities across multiple calls (start → expand → filter → inspect) |
|
|
137
|
+
| `elemental_health` | Health check — verify MCP server connectivity |
|
|
136
138
|
|
|
137
139
|
### MCP Prompts
|
|
138
140
|
|
|
139
141
|
The server also exposes built-in prompts that provide pre-composed
|
|
140
142
|
workflows:
|
|
141
143
|
|
|
142
|
-
| Prompt
|
|
143
|
-
|
|
144
|
-
| `company-deep-dive` | Comprehensive company research workflow
|
|
145
|
-
| `blast-radius`
|
|
146
|
-
| `event-monitor`
|
|
144
|
+
| Prompt | Purpose |
|
|
145
|
+
| ------------------- | --------------------------------------------------- |
|
|
146
|
+
| `company-deep-dive` | Comprehensive company research workflow |
|
|
147
|
+
| `blast-radius` | Analyze impact/connections radiating from an entity |
|
|
148
|
+
| `event-monitor` | Track events and developments for entities |
|
|
147
149
|
|
|
148
150
|
### MCP Resources
|
|
149
151
|
|
|
150
152
|
Documentation resources are available directly from the server:
|
|
151
153
|
|
|
152
|
-
| Resource
|
|
153
|
-
|
|
154
|
-
| `elemental_data_model`
|
|
155
|
-
| `elemental_guide`
|
|
156
|
-
| `elemental_schema`
|
|
157
|
-
| `elemental_workflows`
|
|
158
|
-
| `elemental_mcp_server_info` | Server capabilities and configuration
|
|
154
|
+
| Resource | Description |
|
|
155
|
+
| --------------------------- | ------------------------------------------- |
|
|
156
|
+
| `elemental_data_model` | Entity types, properties, and relationships |
|
|
157
|
+
| `elemental_guide` | Usage guide for the MCP tools |
|
|
158
|
+
| `elemental_schema` | Live schema data |
|
|
159
|
+
| `elemental_workflows` | Common workflow patterns and examples |
|
|
160
|
+
| `elemental_mcp_server_info` | Server capabilities and configuration |
|
|
159
161
|
|
|
160
162
|
These prompts and resources can be useful shortcuts — check if your MCP
|
|
161
163
|
client supports them before building equivalent logic from scratch.
|
|
@@ -204,6 +206,7 @@ result = await mcp_call("elemental_get_entity", {
|
|
|
204
206
|
```
|
|
205
207
|
|
|
206
208
|
Key points:
|
|
209
|
+
|
|
207
210
|
- `entity` is `null` if resolution failed
|
|
208
211
|
- Each property value is `{"value": ..., "ref"?: "...", "attributes"?: {...}}`
|
|
209
212
|
- **`value` can be a NEID** for reference-typed properties — see
|
|
@@ -247,6 +250,7 @@ result = await mcp_call("elemental_get_related", {
|
|
|
247
250
|
```
|
|
248
251
|
|
|
249
252
|
Key points:
|
|
253
|
+
|
|
250
254
|
- `related_flavor` is **required** — you must specify what type of entity
|
|
251
255
|
to look for
|
|
252
256
|
- `resolved` is the center entity (can be `null` if resolution failed)
|
|
@@ -298,6 +302,7 @@ result = await mcp_call("elemental_get_events", {
|
|
|
298
302
|
```
|
|
299
303
|
|
|
300
304
|
Key points:
|
|
305
|
+
|
|
301
306
|
- Events have typed fields: `category`, `date`, `description`, `likelihood`
|
|
302
307
|
- Use `categories` to filter — do NOT try to find events by scanning
|
|
303
308
|
property names for keywords
|
|
@@ -383,13 +388,13 @@ def _format_large_number(n: float) -> str:
|
|
|
383
388
|
|
|
384
389
|
### Property type values you'll encounter
|
|
385
390
|
|
|
386
|
-
| Schema type
|
|
387
|
-
|
|
388
|
-
| `string`
|
|
389
|
-
| `integer`, `float` | Number
|
|
390
|
-
| `nindex`
|
|
391
|
-
| `boolean`
|
|
392
|
-
| `datetime`
|
|
391
|
+
| Schema type | Value is | How to display |
|
|
392
|
+
| ------------------ | --------------- | ------------------------------------------- |
|
|
393
|
+
| `string` | Plain text | Display directly |
|
|
394
|
+
| `integer`, `float` | Number | Format with units (check `unit` in schema) |
|
|
395
|
+
| `nindex` | Entity NEID | **Must resolve** via `elemental_get_entity` |
|
|
396
|
+
| `boolean` | `true`/`false` | Display as Yes/No |
|
|
397
|
+
| `datetime` | ISO 8601 string | Format as human-readable date |
|
|
393
398
|
|
|
394
399
|
---
|
|
395
400
|
|
|
@@ -538,14 +543,14 @@ tables below are a starting-point cheat sheet — not exhaustive.
|
|
|
538
543
|
|
|
539
544
|
### Properties by flavor
|
|
540
545
|
|
|
541
|
-
| Flavor
|
|
542
|
-
|
|
543
|
-
| `organization`
|
|
544
|
-
| `person`
|
|
545
|
-
| `government_body`
|
|
546
|
-
| `article`
|
|
547
|
-
| `event`
|
|
548
|
-
| `financial_instrument` | `ticker_symbol`, `exchange`, `currency`
|
|
546
|
+
| Flavor | Common properties |
|
|
547
|
+
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
548
|
+
| `organization` | `country` (nindex), `ticker_symbol`, `total_revenue`, `net_income`, `total_assets`, `industry` (nindex), `lei`, `company_cik`, `ein`, `website` |
|
|
549
|
+
| `person` | `nationality` (nindex), `title`, `birth_date`, `gender` |
|
|
550
|
+
| `government_body` | `country` (nindex), `jurisdiction` |
|
|
551
|
+
| `article` | `headline`, `published_date`, `source`, `url` |
|
|
552
|
+
| `event` | `category`, `date`, `description`, `likelihood` |
|
|
553
|
+
| `financial_instrument` | `ticker_symbol`, `exchange`, `currency` |
|
|
549
554
|
|
|
550
555
|
Properties marked `(nindex)` are entity references — their raw value is
|
|
551
556
|
a NEID that must be resolved to a display name. See "The Property Type
|
|
@@ -556,16 +561,16 @@ Problem" above.
|
|
|
556
561
|
The `direction` parameter on `elemental_get_related` controls traversal.
|
|
557
562
|
Getting it wrong returns zero results with no error.
|
|
558
563
|
|
|
559
|
-
| Relationship
|
|
560
|
-
|
|
561
|
-
| `board_member_of` | Person sits on org's board
|
|
562
|
-
| `is_officer`
|
|
563
|
-
| `subsidiary_of`
|
|
564
|
-
| `owns`
|
|
565
|
-
| `appears_in`
|
|
566
|
-
| `participant`
|
|
567
|
-
| `filed`
|
|
568
|
-
| `works_at`
|
|
564
|
+
| Relationship | Meaning | Direction from center |
|
|
565
|
+
| ----------------- | ----------------------------- | ------------------------------- |
|
|
566
|
+
| `board_member_of` | Person sits on org's board | `"incoming"` when center is org |
|
|
567
|
+
| `is_officer` | Person is an officer of org | `"incoming"` when center is org |
|
|
568
|
+
| `subsidiary_of` | Org is a subsidiary of parent | `"outgoing"` from subsidiary |
|
|
569
|
+
| `owns` | Entity owns another entity | `"outgoing"` from owner |
|
|
570
|
+
| `appears_in` | Entity mentioned in article | `"both"` is usually safest |
|
|
571
|
+
| `participant` | Entity participates in event | `"both"` is usually safest |
|
|
572
|
+
| `filed` | Org filed a document | `"outgoing"` from org |
|
|
573
|
+
| `works_at` | Person works at org | `"outgoing"` from person |
|
|
569
574
|
|
|
570
575
|
> **Tip:** If you're unsure about direction, use `"both"` (the default)
|
|
571
576
|
> first and check the results. Then narrow to `"incoming"` or
|
|
@@ -627,6 +632,7 @@ Revenue was $52.9B [ref_a3f2b1c8]
|
|
|
627
632
|
```
|
|
628
633
|
|
|
629
634
|
The chat UI translates these into numbered source citations. Rules:
|
|
635
|
+
|
|
630
636
|
- Only include refs that are present in the actual response data
|
|
631
637
|
- Copy the ref string exactly — never construct or modify refs
|
|
632
638
|
- Omit the bracket when no ref is present for a value
|
|
@@ -11,7 +11,7 @@ Read the project brief and build the described application.
|
|
|
11
11
|
- **Channeling** — Agents invoke MCP tools and return **natural-language** answers to the user (often chat-first; minimal or no Postgres for graph data).
|
|
12
12
|
- **Mixes** — e.g. a sync job for dashboards plus a research agent plus a channel agent for Q&A.
|
|
13
13
|
|
|
14
|
-
Read
|
|
14
|
+
Read [`data.md`](../skills/aether/data.md) and [`agents-data.md`](../skills/aether/agents-data.md) in the `aether` skill for detail.
|
|
15
15
|
|
|
16
16
|
**This is meant to be the first thing a user runs after opening their project in Cursor.**
|
|
17
17
|
|
|
@@ -78,7 +78,7 @@ If the file exists but tools aren't active yet:
|
|
|
78
78
|
>
|
|
79
79
|
> Open **Cursor Settings** (Cmd+Shift+J on macOS) → **Tools & MCP** and enable the `lovelace-*` servers listed there. They should show green toggles when active. Let me know when they're enabled (or if you'd like to skip this).
|
|
80
80
|
|
|
81
|
-
Wait for confirmation before proceeding if you asked the user to enable servers. If the user skips or the panel isn't available (e.g. Cursor Cloud), proceed — you can still follow the
|
|
81
|
+
Wait for confirmation before proceeding if you asked the user to enable servers. If the user skips or the panel isn't available (e.g. Cursor Cloud), proceed — you can still follow [`data.md`](../skills/aether/data.md) in the `aether` skill and ship agents that use MCP at **runtime**.
|
|
82
82
|
|
|
83
83
|
The **Nuxt** layer may combine **your APIs** (often Postgres-backed), **chat** via **`useAgentChat`**, or both — not Elemental REST from Vue for graph data.
|
|
84
84
|
|
|
@@ -92,9 +92,9 @@ Read:
|
|
|
92
92
|
|
|
93
93
|
1. `DESIGN.md` — which of the valid shapes above (or a mix) the brief implies
|
|
94
94
|
2. `broadchurch.yaml`
|
|
95
|
-
3.
|
|
96
|
-
4.
|
|
97
|
-
5.
|
|
95
|
+
3. [`data.md`](../skills/aether/data.md) in the `aether` skill — MCP-only patterns
|
|
96
|
+
4. [`agents-data.md`](../skills/aether/agents-data.md) in the `aether` skill — wiring MCP into ADK
|
|
97
|
+
5. [`cookbook-data.md`](../skills/aether/cookbook-data.md), [`server.md`](../skills/aether/server.md) and [`storage.md`](../skills/aether/storage.md), [`server-data.md`](../skills/aether/server-data.md) in the `aether` skill — when the UI lists data from **your** APIs (server routes) or **Postgres** (storage)
|
|
98
98
|
|
|
99
99
|
---
|
|
100
100
|
|
|
@@ -119,7 +119,7 @@ research assistant, investigation tool, etc.), build the agent FIRST:
|
|
|
119
119
|
|
|
120
120
|
1. **`agents/`** — Build the full agent with all tools specified in DESIGN.md.
|
|
121
121
|
Each named tool must be a Python function — do NOT just pass `McpToolset`
|
|
122
|
-
through and write a system prompt. Read the `
|
|
122
|
+
through and write a system prompt. Read [`agents.md`](../skills/aether/agents.md) in the `aether` skill ("McpToolset
|
|
123
123
|
passthrough" section) for why this matters.
|
|
124
124
|
2. Test the agent locally with `adk web` before building the UI.
|
|
125
125
|
3. Then build the UI around the working agent.
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "MCP-only: ADK agents use Elemental MCP for sync, research, investigation, aggregation, or channeling — Postgres optional."
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
globs: agents/**
|
|
5
|
-
---
|
|
6
|
-
|
|
7
1
|
# Agents: Elemental MCP (MCP-only)
|
|
8
2
|
|
|
9
3
|
In **mcp-only** mode, **Elemental MCP** is the primary way agents reach the knowledge graph. **`broadchurch_auth` HTTP** to the Query Server is the **api-mcp** path; here you wire **MCP tools** into ADK via **McpToolset** + **`StreamableHTTPConnectionParams`** to your Elemental MCP URL — from env or `broadchurch.yaml` / gateway.
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "MCP-only: UI recipes when data is exposed via your own APIs (often Postgres). Chat-first or agent-only flows may skip these."
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
---
|
|
5
|
-
|
|
6
1
|
# Data-fetching cookbook (MCP-only)
|
|
7
2
|
|
|
8
3
|
**Valid UIs for mcp-only include:** (a) **Chat-first** surfaces where the user talks to an agent that calls MCP tools (`useAgentChat`, agent design — see `data` / `agents-data`). (b) **List/detail/table** screens fed by **your** Nitro APIs, often backed by **Postgres** rows populated by agents that used Elemental MCP upstream.
|
|
@@ -19,7 +14,9 @@ Assume composables like `useEntities()` wrap `$fetch('/api/entities')` — adjus
|
|
|
19
14
|
<template>
|
|
20
15
|
<div class="d-flex flex-column fill-height pa-4">
|
|
21
16
|
<h1 class="text-h5 mb-4">Entities</h1>
|
|
22
|
-
<v-alert v-if="error" type="error" variant="tonal" class="mb-4" closable>{{
|
|
17
|
+
<v-alert v-if="error" type="error" variant="tonal" class="mb-4" closable>{{
|
|
18
|
+
error
|
|
19
|
+
}}</v-alert>
|
|
23
20
|
<v-data-table :items="items" :loading="loading" />
|
|
24
21
|
</div>
|
|
25
22
|
</template>
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "MCP-only data mode: no Elemental REST client in Nuxt; Elemental MCP is used by ADK agents — sync, research, or direct channeling."
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
---
|
|
5
|
-
|
|
6
1
|
# Data — MCP-only (agents + Elemental MCP, not the Elemental API in the SPA)
|
|
7
2
|
|
|
8
3
|
In **mcp-only** mode the Nuxt app does **not** call the Elemental API via `useElementalClient()` or gateway REST from the browser. **Elemental MCP** is how custom **ADK agents** reach the Lovelace knowledge graph.
|
|
@@ -28,7 +23,7 @@ In **mcp-only** mode the Nuxt app does **not** call the Elemental API via `useEl
|
|
|
28
23
|
If you **do** use the sync pattern, treat Neon as the **read model** for those pages:
|
|
29
24
|
|
|
30
25
|
1. **`DATABASE_URL`** — Use `getDb()` from `~/server/utils/neon.ts` in server routes.
|
|
31
|
-
2. **Schema** — `CREATE TABLE IF NOT EXISTS` / `ensureTables()` (see
|
|
26
|
+
2. **Schema** — `CREATE TABLE IF NOT EXISTS` / `ensureTables()` (see [storage.md](storage.md) in this skill). Align columns with the **data-model** skill where relevant.
|
|
32
27
|
3. **Composables** — Thin wrappers around `$fetch('/api/...')` to your own APIs (`useEntities`, etc.).
|
|
33
28
|
4. **Agents that populate tables** — Call Elemental MCP tools, map to rows, **UPSERT** idempotently. Document env (`DATABASE_URL`, MCP URL) in `DESIGN.md` or the agent README.
|
|
34
29
|
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "MCP-only: Nitro routes that read your own store (often Neon). Not used for proxying Elemental REST to the SPA."
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
globs: server/**
|
|
5
|
-
---
|
|
6
|
-
|
|
7
1
|
# Server routes: your data store (MCP-only)
|
|
8
2
|
|
|
9
3
|
In mcp-only mode, **server routes do not** implement the **Elemental REST** proxy pattern from api-mcp for the **primary** SPA data path. Graph access lives in **agents + Elemental MCP**.
|
|
10
4
|
|
|
11
|
-
This
|
|
5
|
+
This guidance applies when your architecture includes a **local read model** (usually **Neon Postgres**) filled by agents that called MCP upstream. **Chat-only** or **agent-only** products may have **few or no** such routes — that is fine.
|
|
12
6
|
|
|
13
7
|
## Pattern (Postgres-backed lists / detail)
|
|
14
8
|
|
|
@@ -16,24 +10,24 @@ This rule applies when your architecture includes a **local read model** (usuall
|
|
|
16
10
|
import { getDb } from '~/server/utils/neon';
|
|
17
11
|
|
|
18
12
|
export default defineEventHandler(async (event) => {
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
const sql = getDb();
|
|
14
|
+
if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
const q = getQuery(event).q as string | undefined;
|
|
17
|
+
if (q) {
|
|
18
|
+
return await sql`
|
|
25
19
|
SELECT neid, name, updated_at FROM entities
|
|
26
20
|
WHERE name ILIKE ${'%' + q + '%'}
|
|
27
21
|
ORDER BY updated_at DESC LIMIT 50
|
|
28
22
|
`;
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
}
|
|
24
|
+
return await sql`SELECT neid, name, updated_at FROM entities ORDER BY updated_at DESC LIMIT 50`;
|
|
31
25
|
});
|
|
32
26
|
```
|
|
33
27
|
|
|
34
28
|
## `ensureTables`
|
|
35
29
|
|
|
36
|
-
Call a shared `ensureTables()` before reads if tables might be missing on cold start (see
|
|
30
|
+
Call a shared `ensureTables()` before reads if tables might be missing on cold start (see [storage.md](storage.md) in this skill).
|
|
37
31
|
|
|
38
32
|
## Secrets
|
|
39
33
|
|
package/rules/server-data.mdc
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Calling the Elemental API from Nitro server routes via the Portal Gateway. Read when proxying Query Server calls server-side."
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
globs: server/**
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Server routes: Elemental API (Query Server)
|
|
8
|
-
|
|
9
|
-
Server routes can call the Elemental API through the Portal Gateway proxy,
|
|
10
|
-
just like client-side code does. The gateway URL, tenant org ID, and API key
|
|
11
|
-
are available via `useRuntimeConfig()`.
|
|
12
|
-
|
|
13
|
-
**NEVER use `readFileSync('broadchurch.yaml')` in server routes.** The YAML
|
|
14
|
-
file is read at build time by `nuxt.config.ts` and its values flow into
|
|
15
|
-
`runtimeConfig`. Nitro serverless functions (Vercel) don't bundle arbitrary
|
|
16
|
-
project files — `readFileSync` will crash with ENOENT in production even
|
|
17
|
-
though it works locally.
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
export default defineEventHandler(async (event) => {
|
|
21
|
-
const { public: config } = useRuntimeConfig();
|
|
22
|
-
|
|
23
|
-
const gatewayUrl = config.gatewayUrl; // Portal Gateway base URL
|
|
24
|
-
const orgId = config.tenantOrgId; // Tenant org ID (path segment)
|
|
25
|
-
const apiKey = config.qsApiKey; // API key for X-Api-Key header
|
|
26
|
-
|
|
27
|
-
if (!gatewayUrl || !orgId) {
|
|
28
|
-
throw createError({ statusCode: 503, statusMessage: 'Gateway not configured' });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const res = await $fetch(`${gatewayUrl}/api/qs/${orgId}/entities/search`, {
|
|
32
|
-
method: 'POST',
|
|
33
|
-
headers: {
|
|
34
|
-
'Content-Type': 'application/json',
|
|
35
|
-
...(apiKey && { 'X-Api-Key': apiKey }),
|
|
36
|
-
},
|
|
37
|
-
body: { queries: [{ queryId: 1, query: 'Microsoft' }], maxResults: 5 },
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return res;
|
|
41
|
-
});
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Available runtime config keys (all under `runtimeConfig.public`):
|
|
45
|
-
|
|
46
|
-
| Key | Source | Purpose |
|
|
47
|
-
|---|---|---|
|
|
48
|
-
| `gatewayUrl` | `broadchurch.yaml` → `gateway.url` | Portal Gateway base URL |
|
|
49
|
-
| `tenantOrgId` | `broadchurch.yaml` → `tenant.org_id` | Tenant ID for API path |
|
|
50
|
-
| `qsApiKey` | `broadchurch.yaml` → `gateway.qs_api_key` | API key sent as `X-Api-Key` |
|
|
51
|
-
| `queryServerAddress` | `broadchurch.yaml` → `query_server.url` | Direct QS URL (prefer gateway) |
|
|
52
|
-
|
|
53
|
-
Build the request URL as `{gatewayUrl}/api/qs/{tenantOrgId}/{endpoint}`.
|
|
54
|
-
See the `data` rule for endpoint reference and response shapes.
|
package/rules/storage.mdc
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Storage backends available to the app (KV/Upstash Redis always on; Neon Postgres if provisioned). Apply when choosing persistence, deciding if Postgres is available, or wiring up getRedis()/getDb().
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Two storage services are available. Check `.env` to see which are connected:
|
|
7
|
-
|
|
8
|
-
| Store | How to check | Env var | Utility file | Always available? |
|
|
9
|
-
| ---------------------- | --------------------------------------------------------------------------------- | --------------------------------------- | --------------------------------------------------------- | ----------------------------------- |
|
|
10
|
-
| **KV** (Upstash Redis) | `KV_REST_API_URL` in `.env` | `KV_REST_API_URL`, `KV_REST_API_TOKEN` | `server/utils/redis.ts` (pre-scaffolded) | Yes |
|
|
11
|
-
| **Neon Postgres** | `curl <gateway.url>/api/tenants/<tenant.org_id>` → `vercel.postgres_store_id` set | `DATABASE_URL`, `DATABASE_URL_UNPOOLED` | `server/utils/neon.ts` (create it if missing — see below) | Only if enabled at project creation |
|
|
12
|
-
|
|
13
|
-
### Quick start
|
|
14
|
-
|
|
15
|
-
**KV** is ready to use out of the box. Use `getRedis()` from
|
|
16
|
-
`server/utils/redis.ts` in server routes, or `usePrefsStore()` on the client
|
|
17
|
-
(see `pref` rule for the `Pref<T>` pattern).
|
|
18
|
-
|
|
19
|
-
**Neon Postgres** — provisioning is determined by the portal, not by `.env`.
|
|
20
|
-
To check whether Neon is enabled for this tenant, pull `gateway.url` and
|
|
21
|
-
`tenant.org_id` out of `broadchurch.yaml` and query the portal:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
curl <gateway.url>/api/tenants/<tenant.org_id>
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
If the response has `vercel.postgres_store_id` set, Neon is provisioned. The
|
|
28
|
-
`DATABASE_URL` is also present under `agent_secrets` in that response, but
|
|
29
|
-
you usually do not need to read it directly.
|
|
30
|
-
|
|
31
|
-
`DATABASE_URL` and `DATABASE_URL_UNPOOLED` are intentionally left commented
|
|
32
|
-
out in local `.env` — Neon does not work locally. On deploy, Vercel
|
|
33
|
-
auto-injects `DATABASE_URL` at runtime, so pushed builds connect
|
|
34
|
-
transparently.
|
|
35
|
-
|
|
36
|
-
For the `getDb()` lazy-init pattern, `@neondatabase/serverless` install, and
|
|
37
|
-
full code examples (creating tables, handling missing tables in GET routes,
|
|
38
|
-
etc.), see the `server` rule.
|
|
39
|
-
|
|
40
|
-
### Where credentials come from
|
|
41
|
-
|
|
42
|
-
**Deployed builds** (push to `main` → Vercel): storage env vars are
|
|
43
|
-
auto-injected and decrypted at runtime. Storage works with zero
|
|
44
|
-
configuration. **This is the primary development path** — push your code
|
|
45
|
-
and test on the deployed preview/production URL.
|
|
46
|
-
|
|
47
|
-
**Local dev / Cursor Cloud:** storage credentials are not yet available for
|
|
48
|
-
local use. `getRedis()` and `getDb()` will return `null`, and the app should
|
|
49
|
-
handle this gracefully (show a "not configured" state, use defaults, etc.).
|
|
50
|
-
KV preferences fall back to their default values. Postgres features should
|
|
51
|
-
check `getDb()` and show appropriate UI when it returns `null`.
|
|
52
|
-
|
|
53
|
-
This is a known platform limitation — the Broadchurch team is working on
|
|
54
|
-
making storage credentials available for local development.
|