@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.
Files changed (37) hide show
  1. package/AGENTS.md +18 -191
  2. package/README.md +13 -9
  3. package/commands/build_my_app.md +7 -8
  4. package/commands/deploy_agent.md +7 -7
  5. package/commands/update_branding.md +1 -1
  6. package/commands/update_instructions.md +25 -17
  7. package/package.json +2 -4
  8. package/skills/aether/SKILL.md +57 -0
  9. package/{rules/agents-data.mdc → skills/aether/agents-data.md} +3 -6
  10. package/{rules/agents.mdc → skills/aether/agents.md} +49 -28
  11. package/{rules/architecture.mdc → skills/aether/architecture.md} +14 -21
  12. package/{rules/branding.mdc → skills/aether/branding.md} +7 -12
  13. package/{rules/cookbook-data.mdc → skills/aether/cookbook-data.md} +13 -28
  14. package/{rules/cookbook.mdc → skills/aether/cookbook.md} +2 -9
  15. package/skills/aether/cursor-cloud.md +57 -0
  16. package/{rules/data.mdc → skills/aether/data.md} +80 -70
  17. package/skills/aether/deployment.md +14 -0
  18. package/{rules/design.mdc → skills/aether/design.md} +1 -6
  19. package/skills/aether/env.md +10 -0
  20. package/{rules/git-support.mdc → skills/aether/git-support.md} +4 -9
  21. package/{rules/instructions_warning.mdc → skills/aether/instructions_warning.md} +6 -12
  22. package/skills/aether/local-setup.md +15 -0
  23. package/{rules/mcp-servers.mdc → skills/aether/mcp-servers.md} +3 -7
  24. package/{rules/pref.mdc → skills/aether/pref.md} +9 -14
  25. package/skills/aether/server-data.md +48 -0
  26. package/skills/aether/server.md +60 -0
  27. package/{rules/something-broke.mdc → skills/aether/something-broke.md} +3 -7
  28. package/{rules/server.mdc → skills/aether/storage.md} +78 -108
  29. package/{rules/ui.mdc → skills/aether/ui.md} +2 -6
  30. package/skills/elemental-mcp-patterns/SKILL.md +57 -51
  31. package/variants/mcp-only/commands/build_my_app.md +6 -6
  32. package/variants/mcp-only/{rules/agents-data.mdc → skills/aether/agents-data.md} +0 -6
  33. package/variants/mcp-only/{rules/cookbook-data.mdc → skills/aether/cookbook-data.md} +3 -6
  34. package/variants/mcp-only/{rules/data.mdc → skills/aether/data.md} +1 -6
  35. package/variants/mcp-only/{rules/server-data.mdc → skills/aether/server-data.md} +9 -15
  36. package/rules/aether.mdc +0 -21
  37. 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
- # Nitro Server Routes
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
- The `server/` directory contains Nuxt's Nitro server layer. These routes deploy
10
- with the app to Vercel -- they are NOT a separate service. They handle
11
- server-side concerns like KV storage, database access, and image proxying
12
- that can't run in the browser.
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
- ## Directory Layout
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
- Route handler pattern:
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
- ```typescript
41
- export default defineEventHandler(async (event) => {
42
- const params = getQuery(event); // query string
43
- const body = await readBody(event); // POST body
44
- const id = getRouterParam(event, 'id'); // path params
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
- // ... implementation ...
47
- return { result: 'data' };
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 Storage (Upstash Redis)
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
- await redis.hset(toRedisKey('/users/abc/settings'), { theme: 'dark' });
65
- const theme = await redis.hget(toRedisKey('/users/abc/settings'), 'theme');
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 the `pref` rule.
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
- (mirror the `getDb()` lazy-init pattern in `server/utils/redis.ts`).
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
- const sql = getDb();
115
- if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
97
+ const sql = getDb();
98
+ if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
116
99
 
117
- const rows = await sql`SELECT * FROM notes ORDER BY created_at DESC`;
118
- return rows;
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 * FROM notes WHERE id = ${id}\`` is safe.
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 the `CREATE TABLE IF NOT EXISTS` in each route that
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
- ### If `server/utils/neon.ts` doesn't exist
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
- const sql = getDb();
185
- if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
186
-
187
- try {
188
- const rows = await sql`SELECT * FROM companies ORDER BY updated_at DESC`;
189
- return rows;
190
- } catch (err: any) {
191
- if (err.message?.includes('does not exist')) {
192
- return [];
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
- if (_initialized) return;
211
- const sql = getDb();
212
- if (!sql) return;
163
+ if (_initialized) return;
164
+ const sql = getDb();
165
+ if (!sql) return;
213
166
 
214
- await sql`CREATE TABLE IF NOT EXISTS companies (
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
- _initialized = true;
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
- ## Key Differences from Client-Side Code
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
- - Server routes run on the server (Node.js), not in the browser
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
- See `architecture` rule for the full data architecture overview, `pref` rule
238
- for client-side KV preferences.
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 the **cookbook** rule for a full dialog pattern.
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`.** `SseConnectionParams` is for
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 | Use when you need to... |
124
- |---|---|
125
- | `elemental_get_entity` | Resolve an entity by name or ID, fetch its properties (supports `history` for time-series) |
126
- | `elemental_get_related` | Find related entities (requires `related_flavor`); use `direction` and `relationship_types` to filter |
127
- | `elemental_get_events` | Get typed events with categories, dates, participants |
128
- | `elemental_get_citations` | Look up provenance for `ref` hashes returned by other tools |
129
- | `elemental_get_schema` | Discover flavors (entity types), property names, and property types |
130
- | `elemental_get_relationships` | Get relationship types and counts between two entities |
131
- | `elemental_graph_neighborhood` | Get the most influential neighbors of an entity |
132
- | `elemental_graph_sentiment` | Sentiment time series, trend analysis, and statistics from news articles |
133
- | `elemental_introspect` | Discover what data **actually exists**: entity counts, populated properties with fill rates, sample values. Use before building features to verify data availability. |
134
- | `elemental_traverse` | Stateful graph navigation — build a working set of entities across multiple calls (start → expand → filter → inspect) |
135
- | `elemental_health` | Health check — verify MCP server connectivity |
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 | Purpose |
143
- |---|---|
144
- | `company-deep-dive` | Comprehensive company research workflow |
145
- | `blast-radius` | Analyze impact/connections radiating from an entity |
146
- | `event-monitor` | Track events and developments for entities |
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 | Description |
153
- |---|---|
154
- | `elemental_data_model` | Entity types, properties, and relationships |
155
- | `elemental_guide` | Usage guide for the MCP tools |
156
- | `elemental_schema` | Live schema data |
157
- | `elemental_workflows` | Common workflow patterns and examples |
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 | Value is | How to display |
387
- |---|---|---|
388
- | `string` | Plain text | Display directly |
389
- | `integer`, `float` | Number | Format with units (check `unit` in schema) |
390
- | `nindex` | Entity NEID | **Must resolve** via `elemental_get_entity` |
391
- | `boolean` | `true`/`false` | Display as Yes/No |
392
- | `datetime` | ISO 8601 string | Format as human-readable date |
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 | Common properties |
542
- |---|---|
543
- | `organization` | `country` (nindex), `ticker_symbol`, `total_revenue`, `net_income`, `total_assets`, `industry` (nindex), `lei`, `company_cik`, `ein`, `website` |
544
- | `person` | `nationality` (nindex), `title`, `birth_date`, `gender` |
545
- | `government_body` | `country` (nindex), `jurisdiction` |
546
- | `article` | `headline`, `published_date`, `source`, `url` |
547
- | `event` | `category`, `date`, `description`, `likelihood` |
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 | Meaning | Direction from center |
560
- |---|---|---|
561
- | `board_member_of` | Person sits on org's board | `"incoming"` when center is org |
562
- | `is_officer` | Person is an officer of org | `"incoming"` when center is org |
563
- | `subsidiary_of` | Org is a subsidiary of parent | `"outgoing"` from subsidiary |
564
- | `owns` | Entity owns another entity | `"outgoing"` from owner |
565
- | `appears_in` | Entity mentioned in article | `"both"` is usually safest |
566
- | `participant` | Entity participates in event | `"both"` is usually safest |
567
- | `filed` | Org filed a document | `"outgoing"` from org |
568
- | `works_at` | Person works at org | `"outgoing"` from person |
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 the **`data`** and **`agents-data`** cursor rules for detail.
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 **`data`** rule and ship agents that use MCP at **runtime**.
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. **`data` rule** — MCP-only patterns
96
- 4. **`agents-data` rule** — wiring MCP into ADK
97
- 5. **`cookbook-data` / `server` / `server-data`** — when the UI lists data from **your** APIs / Postgres
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 `agents` rule ("McpToolset
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>{{ error }}</v-alert>
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 `server` rule). Align columns with the **data-model** skill where relevant.
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 rule 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.
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
- const sql = getDb();
20
- if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
13
+ const sql = getDb();
14
+ if (!sql) throw createError({ statusCode: 503, statusMessage: 'Database not configured' });
21
15
 
22
- const q = getQuery(event).q as string | undefined;
23
- if (q) {
24
- return await sql`
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
- return await sql`SELECT neid, name, updated_at FROM entities ORDER BY updated_at DESC LIMIT 50`;
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 `server` rule).
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