This feature (002-direct-db-access) enables scripts to query schedule data directly via SQL after loading XER files through MCP. Key additions: - spec.md: Feature specification with 3 user stories - plan.md: Implementation plan with constitution check - research.md: Technology decisions (SQLite file, WAL mode, atomic writes) - data-model.md: DatabaseInfo, SchemaInfo, TableInfo entities - contracts/mcp-tools.json: Extended load_xer schema, new get_database_info tool - quickstart.md: Usage examples for direct database access - tasks.md: 16 implementation tasks across 6 phases
5.3 KiB
5.3 KiB
Data Model: Direct Database Access for Scripts
Date: 2026-01-08
Branch: 002-direct-db-access
Entity Overview
┌─────────────────┐
│ DatabaseInfo │
└─────────────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐
│ SchemaInfo │───────│ TableInfo │
└─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ ColumnInfo │
└─────────────────┘
New Entities
DatabaseInfo
Information about the current database connection, returned by load operations and queryable separately.
| Field | Type | Required | Description |
|---|---|---|---|
| db_path | string | Yes | Absolute path to SQLite database file; :memory: for in-memory |
| is_persistent | boolean | Yes | True if file-based, false if in-memory |
| source_file | string | No | Path to XER file that was loaded |
| loaded_at | datetime | Yes | When data was loaded |
| schema | SchemaInfo | Yes | Database schema information |
Validation Rules:
- db_path must be an absolute path (or
:memory:) - loaded_at must be ISO 8601 format
SchemaInfo
Metadata describing the database structure.
| Field | Type | Required | Description |
|---|---|---|---|
| tables | list[TableInfo] | Yes | All tables in the database |
| version | string | Yes | Schema version (matches server version) |
TableInfo
Information about a single database table.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Table name |
| columns | list[ColumnInfo] | Yes | Column definitions |
| primary_key | list[string] | Yes | Column(s) forming primary key |
| foreign_keys | list[ForeignKeyInfo] | No | Foreign key relationships |
| row_count | integer | Yes | Number of rows in table |
ColumnInfo
Information about a single column.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Column name |
| type | string | Yes | SQLite data type (TEXT, INTEGER, REAL, etc.) |
| nullable | boolean | Yes | Whether NULL values are allowed |
| default | string | No | Default value if any |
ForeignKeyInfo
Foreign key relationship information.
| Field | Type | Required | Description |
|---|---|---|---|
| column | string | Yes | Column in this table |
| references_table | string | Yes | Referenced table |
| references_column | string | Yes | Referenced column |
Extended load_xer Response
The existing load_xer tool response is extended with database information:
{
"success": true,
"project": { ... },
"activity_count": 4440,
"relationship_count": 8583,
"database": {
"db_path": "/path/to/schedule.sqlite",
"is_persistent": true,
"source_file": "/path/to/schedule.xer",
"loaded_at": "2026-01-08T14:30:00",
"schema": {
"version": "0.2.0",
"tables": [
{
"name": "activities",
"columns": [
{"name": "task_id", "type": "TEXT", "nullable": false},
{"name": "task_name", "type": "TEXT", "nullable": false},
...
],
"primary_key": ["task_id"],
"foreign_keys": [
{"column": "proj_id", "references_table": "projects", "references_column": "proj_id"}
],
"row_count": 4440
},
...
]
}
}
}
New Tool Input Schema
load_xer (extended)
New optional parameter:
| Parameter | Type | Required | Description |
|---|---|---|---|
| db_path | string | No | Path for persistent database file. If omitted, uses in-memory database. If empty string, auto-generates path from XER filename. |
get_database_info
No input parameters required. Returns current database information.
SQLite Schema (Unchanged)
The underlying database schema remains unchanged from feature 001-schedule-tools:
projects- Project metadataactivities- Task/activity datarelationships- Predecessor/successor relationshipswbs- Work breakdown structurecalendars- Calendar definitions
The difference is storage location (file vs memory), not structure.
Query Examples for Scripts
Once scripts have the database path, they can execute standard SQL:
import sqlite3
# Connect using path from load_xer response
conn = sqlite3.connect("/path/to/schedule.sqlite")
# Query activities
cursor = conn.execute("""
SELECT task_code, task_name, target_start_date, target_end_date
FROM activities
WHERE task_type = 'TT_Mile'
ORDER BY target_start_date
""")
for row in cursor:
print(row)
-- Find critical path activities
SELECT task_code, task_name, total_float_hr_cnt
FROM activities
WHERE driving_path_flag = 1
ORDER BY target_start_date;
-- Join activities with WBS
SELECT a.task_code, a.task_name, w.wbs_name
FROM activities a
JOIN wbs w ON a.wbs_id = w.wbs_id;