oneie
Version:
Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.
374 lines (322 loc) • 11.1 kB
Markdown
# Read and Parse Convex Schema
**Category:** convex
**Version:** 1.0.0
**Used By:** agent-backend, agent-builder, agent-quality, agent-director, agent-integrator
## Purpose
Reads and parses a Convex schema file to extract table definitions, field types, indexes, and relationships for use by other skills and agents.
## Inputs
- **schemaPath** (string): Path to schema file. Default: `backend/convex/schema.ts`
- **tableFilter** (array, optional): Only return specific tables. Default: all tables
## Outputs
- **tables** (object): Map of table name → table definition
- **tableCount** (number): Total number of tables
- **indexes** (object): Map of table → array of indexes
- **relationships** (array): Foreign key relationships detected
- **schemaVersion** (string): Convex schema version used
- **raw** (string): Raw schema file content (for advanced usage)
## Prerequisites
- Schema file exists at specified path
- Schema follows Convex `defineSchema` format
- TypeScript/JavaScript syntax is valid
## Steps
1. **Read Schema File**
- Use Read tool to load file from schemaPath
- Handle file not found gracefully
- Verify file contains `defineSchema`
2. **Parse Schema Structure**
- Extract `defineSchema({ ... })` block
- Identify all table definitions (defineTable)
- Parse each table's field definitions
- Extract validator types (v.string(), v.number(), etc.)
3. **Extract Table Definitions**
- For each table:
- Table name
- Field names and types
- Required vs optional fields
- Default values
- Validator constraints
4. **Parse Indexes**
- Find all `.index()` calls
- Extract index name
- Extract indexed fields
- Determine index type (single field, compound, search)
5. **Detect Relationships**
- Find all `v.id("tableName")` references
- Map foreign key fields to target tables
- Identify relationship type (one-to-one, one-to-many)
- Note bidirectional relationships
6. **Determine Schema Version**
- Check import statement for Convex version
- Look for version-specific features
- Default to latest known version
7. **Apply Table Filter** (if provided)
- Filter tables object to only requested tables
- Maintain relationships for filtered tables
- Update tableCount
8. **Return Parsed Schema**
- Structured data ready for other skills
- Include raw content for advanced parsing
- Provide metadata about schema
## Examples
### Example 1: Read Full Schema
**Input:**
```typescript
schemaPath: "backend/convex/schema.ts"
tableFilter: null
```
**Schema Content:**
```typescript
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
groups: defineTable({
name: v.string(),
type: v.union(
v.literal("friend_circle"),
v.literal("business"),
v.literal("community"),
v.literal("dao"),
v.literal("government"),
v.literal("organization")
),
parentGroupId: v.optional(v.id("groups")),
properties: v.any(),
status: v.union(v.literal("draft"), v.literal("active"), v.literal("archived")),
createdAt: v.number(),
updatedAt: v.number(),
})
.index("by_type", ["type"])
.index("by_parent", ["parentGroupId"]),
things: defineTable({
groupId: v.id("groups"),
type: v.string(),
name: v.string(),
properties: v.any(),
status: v.union(v.literal("draft"), v.literal("active"), v.literal("published"), v.literal("archived")),
createdAt: v.number(),
updatedAt: v.number(),
})
.index("by_group", ["groupId"])
.index("by_type", ["type"])
.index("by_group_and_type", ["groupId", "type"]),
connections: defineTable({
groupId: v.id("groups"),
sourceId: v.id("things"),
targetId: v.id("things"),
type: v.string(),
metadata: v.any(),
validFrom: v.optional(v.number()),
validTo: v.optional(v.number()),
createdAt: v.number(),
updatedAt: v.number(),
})
.index("by_group", ["groupId"])
.index("by_source", ["sourceId"])
.index("by_target", ["targetId"])
.index("by_type", ["type"]),
});
```
**Output:**
```json
{
"tables": {
"groups": {
"fields": {
"_id": { "type": "Id<'groups'>", "required": true },
"name": { "type": "string", "required": true },
"type": { "type": "union", "values": ["friend_circle", "business", "community", "dao", "government", "organization"], "required": true },
"parentGroupId": { "type": "Id<'groups'>", "required": false },
"properties": { "type": "any", "required": true },
"status": { "type": "union", "values": ["draft", "active", "archived"], "required": true },
"createdAt": { "type": "number", "required": true },
"updatedAt": { "type": "number", "required": true }
},
"indexes": ["by_type", "by_parent"]
},
"things": {
"fields": {
"_id": { "type": "Id<'things'>", "required": true },
"groupId": { "type": "Id<'groups'>", "required": true },
"type": { "type": "string", "required": true },
"name": { "type": "string", "required": true },
"properties": { "type": "any", "required": true },
"status": { "type": "union", "values": ["draft", "active", "published", "archived"], "required": true },
"createdAt": { "type": "number", "required": true },
"updatedAt": { "type": "number", "required": true }
},
"indexes": ["by_group", "by_type", "by_group_and_type"]
},
"connections": {
"fields": {
"_id": { "type": "Id<'connections'>", "required": true },
"groupId": { "type": "Id<'groups'>", "required": true },
"sourceId": { "type": "Id<'things'>", "required": true },
"targetId": { "type": "Id<'things'>", "required": true },
"type": { "type": "string", "required": true },
"metadata": { "type": "any", "required": true },
"validFrom": { "type": "number", "required": false },
"validTo": { "type": "number", "required": false },
"createdAt": { "type": "number", "required": true },
"updatedAt": { "type": "number", "required": true }
},
"indexes": ["by_group", "by_source", "by_target", "by_type"]
}
},
"tableCount": 3,
"indexes": {
"groups": [
{ "name": "by_type", "fields": ["type"] },
{ "name": "by_parent", "fields": ["parentGroupId"] }
],
"things": [
{ "name": "by_group", "fields": ["groupId"] },
{ "name": "by_type", "fields": ["type"] },
{ "name": "by_group_and_type", "fields": ["groupId", "type"] }
],
"connections": [
{ "name": "by_group", "fields": ["groupId"] },
{ "name": "by_source", "fields": ["sourceId"] },
{ "name": "by_target", "fields": ["targetId"] },
{ "name": "by_type", "fields": ["type"] }
]
},
"relationships": [
{
"fromTable": "groups",
"fromField": "parentGroupId",
"toTable": "groups",
"toField": "_id",
"type": "self-reference",
"optional": true
},
{
"fromTable": "things",
"fromField": "groupId",
"toTable": "groups",
"toField": "_id",
"type": "many-to-one",
"optional": false
},
{
"fromTable": "connections",
"fromField": "groupId",
"toTable": "groups",
"toField": "_id",
"type": "many-to-one",
"optional": false
},
{
"fromTable": "connections",
"fromField": "sourceId",
"toTable": "things",
"toField": "_id",
"type": "many-to-one",
"optional": false
},
{
"fromTable": "connections",
"fromField": "targetId",
"toTable": "things",
"toField": "_id",
"type": "many-to-one",
"optional": false
}
],
"schemaVersion": "1.0",
"raw": "[full schema file content]"
}
```
### Example 2: Read Specific Tables
**Input:**
```typescript
schemaPath: "backend/convex/schema.ts"
tableFilter: ["things", "connections"]
```
**Output:**
```json
{
"tables": {
"things": { "fields": {...}, "indexes": [...] },
"connections": { "fields": {...}, "indexes": [...] }
},
"tableCount": 2,
"indexes": {
"things": [...],
"connections": [...]
},
"relationships": [
{
"fromTable": "things",
"fromField": "groupId",
"toTable": "groups",
"toField": "_id",
"type": "many-to-one",
"optional": false
},
{
"fromTable": "connections",
"fromField": "sourceId",
"toTable": "things",
"toField": "_id",
"type": "many-to-one",
"optional": false
}
],
"schemaVersion": "1.0",
"raw": "[full schema file content]"
}
```
## Error Handling
- **File Not Found:** Return clear error with correct path
- **Parse Error:** Return line number and syntax error description
- **Invalid Schema:** Explain what's wrong with schema structure
- **No Tables Found:** Check if defineSchema is present
## Dependencies
- **Tools:** Read (to load schema file), Grep (optional, for pattern matching)
- **Skills:** None (foundational Convex skill)
- **Docs:**
- `https://docs.convex.dev/database/schemas` - Convex schema documentation
- `/one/knowledge/ontology.md` - ONE ontology for expected tables
## Tests
1. **Test Valid Schema:** Parse complete 6-dimension schema successfully
2. **Test Minimal Schema:** Parse schema with single table
3. **Test Complex Types:** Parse nested objects, arrays, unions
4. **Test Relationships:** Detect all foreign key references
5. **Test Indexes:** Extract all index definitions correctly
6. **Test Table Filter:** Return only requested tables
7. **Test Invalid Syntax:** Handle malformed schema gracefully
## Performance
- **Parse Time:** < 500ms for typical schema (5-10 tables)
- **Caching:** Cache parsed schema (invalidate on file change)
- **Optimization:** Parse incrementally for large schemas
## Usage Patterns
### In Other Skills
```markdown
## In create-mutation.md
1. USE SKILL: `skills/convex/read-schema.md`
- Input: schemaPath
- SAVE result as SCHEMA
2. Check if target table exists
- IF SCHEMA.tables["targetTable"] is undefined
- RETURN error: "Table not found in schema"
3. Get field types from schema
- Use SCHEMA.tables["targetTable"].fields
- Validate input types match schema
```
### In Agents
```markdown
## In agent-backend
Before creating mutation:
1. USE SKILL: `skills/convex/read-schema.md`
- Understand current schema structure
- Identify available tables and fields
- Check relationships for validation logic
```
## Lessons Learned
- **Parse AST, Not Strings:** Use proper TypeScript parser for robust parsing
- **Cache Aggressively:** Schema doesn't change often, cache parsed result
- **Relationships Are Key:** Foreign keys drive query patterns and validation
- **Index Awareness:** Knowing indexes helps generate efficient queries
- **Version Matters:** Different Convex versions have different features
## Version History
- **1.0.0** (2025-10-18): Initial implementation with relationship detection