@yottagraph-app/aether-instructions 1.1.41 → 1.1.43
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 +18 -191
- 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 +25 -17
- package/package.json +2 -4
- 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} +49 -28
- package/{rules/architecture.mdc → skills/aether/architecture.md} +14 -21
- 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/skills/aether/cursor-cloud.md +57 -0
- package/{rules/data.mdc → skills/aether/data.md} +80 -70
- package/skills/aether/deployment.md +14 -0
- package/{rules/design.mdc → skills/aether/design.md} +1 -6
- package/skills/aether/env.md +10 -0
- package/{rules/git-support.mdc → skills/aether/git-support.md} +4 -9
- package/{rules/instructions_warning.mdc → skills/aether/instructions_warning.md} +6 -12
- package/skills/aether/local-setup.md +15 -0
- 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/aether.mdc +0 -21
- package/rules/server-data.mdc +0 -54
|
@@ -1,54 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
description: Nitro server-side API routes and utilities in server/
|
|
3
|
-
globs: server/**
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
---
|
|
1
|
+
# Storage
|
|
6
2
|
|
|
7
|
-
|
|
3
|
+
Two storage services are available. KV is always connected; Neon Postgres
|
|
4
|
+
is only present if the tenant was provisioned with it. Each store has its
|
|
5
|
+
own way of checking availability — see the **How to check** column below:
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
| Store | How to check | Env var | Utility file | Always available? |
|
|
8
|
+
| ---------------------- | --------------------------------------------------------------------------------- | --------------------------------------- | --------------------------------------------------------- | ----------------------------------- |
|
|
9
|
+
| **KV** (Upstash Redis) | `KV_REST_API_URL` in `.env` | `KV_REST_API_URL`, `KV_REST_API_TOKEN` | `server/utils/redis.ts` (pre-scaffolded) | Yes |
|
|
10
|
+
| **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 |
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
Both utilities live in `server/utils/` and are consumed from Nitro server
|
|
13
|
+
routes (`server/api/**`). For how to add a server route, see
|
|
14
|
+
[server.md](server.md) in this skill. For client-side user preferences that
|
|
15
|
+
sit on top of KV, see [pref.md](pref.md) in this skill.
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
server/
|
|
18
|
-
├── api/
|
|
19
|
-
│ ├── kv/ # KV (Upstash Redis) CRUD — read, write, delete, documents, status
|
|
20
|
-
│ └── avatar/[url].ts # Avatar image proxy
|
|
21
|
-
└── utils/
|
|
22
|
-
├── redis.ts # Upstash Redis client (lazy-init from KV_REST_API_URL)
|
|
23
|
-
├── neon.ts # Neon Postgres client (lazy-init from DATABASE_URL) — create if missing when Neon is provisioned
|
|
24
|
-
└── cookies.ts # Cookie handling (@hapi/iron)
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Adding Routes
|
|
28
|
-
|
|
29
|
-
Follow Nitro file-based routing. The filename determines the HTTP method and
|
|
30
|
-
path:
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
server/api/my-resource.get.ts → GET /api/my-resource
|
|
34
|
-
server/api/my-resource.post.ts → POST /api/my-resource
|
|
35
|
-
server/api/my-resource/[id].get.ts → GET /api/my-resource/:id
|
|
36
|
-
```
|
|
17
|
+
## Where credentials come from
|
|
37
18
|
|
|
38
|
-
|
|
19
|
+
**Deployed builds** (push to `main` → Vercel): storage env vars are
|
|
20
|
+
auto-injected and decrypted at runtime. Storage works with zero
|
|
21
|
+
configuration. **This is the primary development path** — push your code
|
|
22
|
+
and test on the deployed preview/production URL.
|
|
39
23
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
24
|
+
**Local dev / Cursor Cloud:** storage credentials are not yet available for
|
|
25
|
+
local use. `getRedis()` and `getDb()` will return `null`, and the app should
|
|
26
|
+
handle this gracefully (show a "not configured" state, use defaults, etc.).
|
|
27
|
+
KV preferences fall back to their default values. Postgres features should
|
|
28
|
+
check `getDb()` and show appropriate UI when it returns `null`.
|
|
45
29
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
});
|
|
49
|
-
```
|
|
30
|
+
This is a known platform limitation — the Broadchurch team is working on
|
|
31
|
+
making storage credentials available for local development.
|
|
50
32
|
|
|
51
|
-
## KV
|
|
33
|
+
## KV (Upstash Redis)
|
|
52
34
|
|
|
53
35
|
`server/utils/redis.ts` initializes the Upstash Redis client from env vars
|
|
54
36
|
that Vercel auto-injects when a KV store is connected:
|
|
@@ -61,15 +43,16 @@ import { getRedis, toRedisKey } from '~/server/utils/redis';
|
|
|
61
43
|
|
|
62
44
|
const redis = getRedis();
|
|
63
45
|
if (redis) {
|
|
64
|
-
|
|
65
|
-
|
|
46
|
+
await redis.hset(toRedisKey('/users/abc/settings'), { theme: 'dark' });
|
|
47
|
+
const theme = await redis.hget(toRedisKey('/users/abc/settings'), 'theme');
|
|
66
48
|
}
|
|
67
49
|
```
|
|
68
50
|
|
|
69
|
-
Returns `null` if KV is not configured (env vars missing). Always check
|
|
51
|
+
Returns `null` if KV is not configured (env vars missing). Always check
|
|
52
|
+
before using.
|
|
70
53
|
|
|
71
54
|
For client-side preferences, use `usePrefsStore()` and `Pref<T>` instead of
|
|
72
|
-
calling KV routes directly — see
|
|
55
|
+
calling KV routes directly — see [pref.md](pref.md) in this skill.
|
|
73
56
|
|
|
74
57
|
## Neon Postgres
|
|
75
58
|
|
|
@@ -91,7 +74,7 @@ curl <gateway.url>/api/tenants/<tenant.org_id>
|
|
|
91
74
|
`DATABASE_URL` is also findable under `agent_secrets`, but you usually
|
|
92
75
|
don't need to read it.
|
|
93
76
|
- `server/utils/neon.ts` present → ready to use. If missing, create it
|
|
94
|
-
(
|
|
77
|
+
(see "If `server/utils/neon.ts` doesn't exist" below).
|
|
95
78
|
- `@neondatabase/serverless` in `package.json` → ready. If missing, run
|
|
96
79
|
`npm install @neondatabase/serverless`.
|
|
97
80
|
|
|
@@ -111,16 +94,16 @@ database on the deployed build, where credentials are auto-injected.
|
|
|
111
94
|
import { getDb } from '~/server/utils/neon';
|
|
112
95
|
|
|
113
96
|
export default defineEventHandler(async () => {
|
|
114
|
-
|
|
115
|
-
|
|
97
|
+
const sql = getDb();
|
|
98
|
+
if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
|
|
116
99
|
|
|
117
|
-
|
|
118
|
-
|
|
100
|
+
const rows = await sql`SELECT * FROM notes ORDER BY created_at DESC`;
|
|
101
|
+
return rows;
|
|
119
102
|
});
|
|
120
103
|
```
|
|
121
104
|
|
|
122
105
|
The Neon driver uses tagged template literals for automatic SQL injection
|
|
123
|
-
protection — `await sql\`SELECT
|
|
106
|
+
protection — `await sql\`SELECT \* FROM notes WHERE id = ${id}\`` is safe.
|
|
124
107
|
No ORM, no query builder, no connection pool setup needed.
|
|
125
108
|
|
|
126
109
|
### Creating tables
|
|
@@ -137,42 +120,12 @@ await sql`CREATE TABLE IF NOT EXISTS notes (
|
|
|
137
120
|
)`;
|
|
138
121
|
```
|
|
139
122
|
|
|
140
|
-
For simple apps, putting
|
|
123
|
+
For simple apps, putting `CREATE TABLE IF NOT EXISTS` in each route that
|
|
141
124
|
uses the table is fine — it's a no-op after the first call. For more complex
|
|
142
125
|
schemas, create a `server/api/db/setup.post.ts` route that initializes all
|
|
143
126
|
tables.
|
|
144
127
|
|
|
145
|
-
###
|
|
146
|
-
|
|
147
|
-
Create it manually (or re-run init):
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
npm install @neondatabase/serverless
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
// server/utils/neon.ts
|
|
155
|
-
import { neon, type NeonQueryFunction } from '@neondatabase/serverless';
|
|
156
|
-
|
|
157
|
-
let _sql: NeonQueryFunction | null = null;
|
|
158
|
-
|
|
159
|
-
export function isDbConfigured(): boolean {
|
|
160
|
-
return Boolean(process.env.DATABASE_URL);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export function getDb(): NeonQueryFunction | null {
|
|
164
|
-
if (_sql) return _sql;
|
|
165
|
-
const url = process.env.DATABASE_URL;
|
|
166
|
-
if (!url) return null;
|
|
167
|
-
_sql = neon(url);
|
|
168
|
-
return _sql;
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
For **Query Server / Elemental API** calls from server routes (gateway URL,
|
|
173
|
-
`X-Api-Key`, request shapes), see the `server-data` rule.
|
|
174
|
-
|
|
175
|
-
## Neon Postgres: Handle Missing Tables in GET Routes
|
|
128
|
+
### Handle missing tables in GET routes
|
|
176
129
|
|
|
177
130
|
Tables created by POST/setup routes won't exist on a fresh deployment.
|
|
178
131
|
**Every GET route that queries a table must handle the case where the table
|
|
@@ -181,18 +134,18 @@ until the setup route runs.
|
|
|
181
134
|
|
|
182
135
|
```typescript
|
|
183
136
|
export default defineEventHandler(async () => {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
137
|
+
const sql = getDb();
|
|
138
|
+
if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const rows = await sql`SELECT * FROM companies ORDER BY updated_at DESC`;
|
|
142
|
+
return rows;
|
|
143
|
+
} catch (err: any) {
|
|
144
|
+
if (err.message?.includes('does not exist')) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
throw err;
|
|
193
148
|
}
|
|
194
|
-
throw err;
|
|
195
|
-
}
|
|
196
149
|
});
|
|
197
150
|
```
|
|
198
151
|
|
|
@@ -207,11 +160,11 @@ import { getDb } from '~/server/utils/neon';
|
|
|
207
160
|
let _initialized = false;
|
|
208
161
|
|
|
209
162
|
export async function ensureTables() {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
163
|
+
if (_initialized) return;
|
|
164
|
+
const sql = getDb();
|
|
165
|
+
if (!sql) return;
|
|
213
166
|
|
|
214
|
-
|
|
167
|
+
await sql`CREATE TABLE IF NOT EXISTS companies (
|
|
215
168
|
id SERIAL PRIMARY KEY,
|
|
216
169
|
neid TEXT UNIQUE NOT NULL,
|
|
217
170
|
name TEXT NOT NULL,
|
|
@@ -219,7 +172,7 @@ export async function ensureTables() {
|
|
|
219
172
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
220
173
|
)`;
|
|
221
174
|
|
|
222
|
-
|
|
175
|
+
_initialized = true;
|
|
223
176
|
}
|
|
224
177
|
```
|
|
225
178
|
|
|
@@ -227,12 +180,29 @@ Then call `await ensureTables()` at the start of any route that reads the
|
|
|
227
180
|
table. The `_initialized` flag makes it a no-op after the first call within
|
|
228
181
|
the same serverless invocation.
|
|
229
182
|
|
|
230
|
-
|
|
183
|
+
### If `server/utils/neon.ts` doesn't exist
|
|
184
|
+
|
|
185
|
+
Create it manually (or re-run init):
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm install @neondatabase/serverless
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// server/utils/neon.ts
|
|
193
|
+
import { neon, type NeonQueryFunction } from '@neondatabase/serverless';
|
|
231
194
|
|
|
232
|
-
|
|
233
|
-
- They have access to Redis, Neon Postgres, secrets, and server-only APIs
|
|
234
|
-
- They do NOT have access to Vue composables, Vuetify, or any client-side code
|
|
235
|
-
- Use `defineEventHandler`, not Vue component patterns
|
|
195
|
+
let _sql: NeonQueryFunction | null = null;
|
|
236
196
|
|
|
237
|
-
|
|
238
|
-
|
|
197
|
+
export function isDbConfigured(): boolean {
|
|
198
|
+
return Boolean(process.env.DATABASE_URL);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function getDb(): NeonQueryFunction | null {
|
|
202
|
+
if (_sql) return _sql;
|
|
203
|
+
const url = process.env.DATABASE_URL;
|
|
204
|
+
if (!url) return null;
|
|
205
|
+
_sql = neon(url);
|
|
206
|
+
return _sql;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Apply when creating or editing page templates, layouts, scrollable content, data tables, or loading states in Vue/Vuetify components.
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
---
|
|
5
|
-
|
|
6
1
|
# UI Patterns
|
|
7
2
|
|
|
8
3
|
## Vuetify Layout System
|
|
@@ -14,6 +9,7 @@ alwaysApply: false
|
|
|
14
9
|
## Page Layout Template
|
|
15
10
|
|
|
16
11
|
For pages with a header and scrollable content, use flexbox:
|
|
12
|
+
|
|
17
13
|
- `d-flex flex-column` on the column container
|
|
18
14
|
- `flex-shrink-0` on fixed elements (header, toolbar)
|
|
19
15
|
- `flex-grow-1 overflow-y-auto` on scrollable content
|
|
@@ -50,7 +46,7 @@ Full page template covering all four data states (loading, error, empty, content
|
|
|
50
46
|
|
|
51
47
|
- Cards inside `v-dialog` automatically get `variant="flat"` (solid background) via the nested Vuetify default in `nuxt.config.ts`. No manual override needed.
|
|
52
48
|
- Use `v-card` directly inside `v-dialog` — it will have a solid surface background despite the global `outlined` default.
|
|
53
|
-
- See
|
|
49
|
+
- See [cookbook.md](cookbook.md) in this skill for a full dialog pattern.
|
|
54
50
|
|
|
55
51
|
## Loading States
|
|
56
52
|
|
|
@@ -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
|
|