From 0ecf7b4d8b376e4b5af7e04f4325d74584ed2fc3 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 11 Feb 2026 00:04:58 +0100 Subject: [PATCH] chore(db): add sqlite-init and sqlite-seed wrappers, update ticket skill Complete the set of whitelistable wrapper scripts so all SQLite access goes through db/connectors/sqlite-* (query, exec, init, seed). Update the ticket skill to reference wrappers instead of calling sqlite_connector.py directly, making permissions allowlisting clean. Co-Authored-By: Claude Opus 4.6 --- .claude/skills/ticket/SKILL.md | 53 ++++++++++++++++++++-------------- db/connectors/sqlite-init | 4 +++ db/connectors/sqlite-seed | 4 +++ 3 files changed, 39 insertions(+), 22 deletions(-) create mode 100755 db/connectors/sqlite-init create mode 100755 db/connectors/sqlite-seed diff --git a/.claude/skills/ticket/SKILL.md b/.claude/skills/ticket/SKILL.md index 9a2d5c916..f3225e00d 100644 --- a/.claude/skills/ticket/SKILL.md +++ b/.claude/skills/ticket/SKILL.md @@ -14,42 +14,46 @@ Manage the Commonwealth project ticketing database at `db/commonwealth.db`. ## Access Method -**Always use the connector script, never the sqlite3 CLI:** -```bash -python3 db/connectors/sqlite_connector.py [args] -``` +**Always use the wrapper scripts, never the sqlite3 CLI or python3 directly:** + +| Script | Purpose | +|--------|---------| +| `db/connectors/sqlite-query ""` | Run SELECT queries | +| `db/connectors/sqlite-exec ""` | Run INSERT/UPDATE/DELETE | +| `db/connectors/sqlite-init` | Create/update database from schema | +| `db/connectors/sqlite-seed` | Seed initiatives from DECISIONS.md | ## Commands ### List tickets Show tickets filtered by status, type, or assignee: ```bash -python3 db/connectors/sqlite_connector.py query "SELECT id, type, title, status, priority, assigned_to FROM tickets WHERE status != 'cancelled' ORDER BY priority, id" +db/connectors/sqlite-query "SELECT id, type, title, status, priority, assigned_to FROM tickets WHERE status != 'cancelled' ORDER BY priority, id" ``` Filter examples: ```bash # By status -python3 db/connectors/sqlite_connector.py query "SELECT id, type, title, status FROM tickets WHERE status='in_progress'" +db/connectors/sqlite-query "SELECT id, type, title, status FROM tickets WHERE status='in_progress'" # By type -python3 db/connectors/sqlite_connector.py query "SELECT id, title, status FROM tickets WHERE type='initiative'" +db/connectors/sqlite-query "SELECT id, title, status FROM tickets WHERE type='initiative'" # By assignee -python3 db/connectors/sqlite_connector.py query "SELECT id, title, status FROM tickets WHERE assigned_to='tyre'" +db/connectors/sqlite-query "SELECT id, title, status FROM tickets WHERE assigned_to='tyre'" # Current sprint -python3 db/connectors/sqlite_connector.py query "SELECT t.id, t.title, t.status, t.assigned_to FROM tickets t JOIN sprints s ON t.sprint_id=s.id WHERE s.status='active'" +db/connectors/sqlite-query "SELECT t.id, t.title, t.status, t.assigned_to FROM tickets t JOIN sprints s ON t.sprint_id=s.id WHERE s.status='active'" ``` ### Show ticket detail ```bash -python3 db/connectors/sqlite_connector.py query "SELECT * FROM tickets WHERE id=" +db/connectors/sqlite-query "SELECT * FROM tickets WHERE id=" ``` ### Create ticket ```bash -python3 db/connectors/sqlite_connector.py execute "INSERT INTO tickets (type, title, description, priority, decision_ref, parent_id) VALUES ('', '', '<description>', '<priority>', '<decision_ref>', <parent_id_or_NULL>)" +db/connectors/sqlite-exec "INSERT INTO tickets (type, title, description, priority, decision_ref, parent_id) VALUES ('<type>', '<title>', '<description>', '<priority>', '<decision_ref>', <parent_id_or_NULL>)" ``` Types: `initiative`, `epic`, `story`, `task`, `bug` @@ -58,42 +62,47 @@ Statuses: `backlog`, `ready`, `in_progress`, `review`, `done`, `cancelled` ### Update ticket ```bash -python3 db/connectors/sqlite_connector.py execute "UPDATE tickets SET status='in_progress', assigned_to='tyre', updated_at=datetime('now') WHERE id=<N>" +db/connectors/sqlite-exec "UPDATE tickets SET status='in_progress', assigned_to='tyre', updated_at=datetime('now') WHERE id=<N>" ``` ### Ticket tree (parent-child hierarchy) ```bash -python3 db/connectors/sqlite_connector.py query "SELECT t.id, t.type, t.title, t.status, p.title as parent_title FROM tickets t LEFT JOIN tickets p ON t.parent_id=p.id ORDER BY COALESCE(t.parent_id, t.id), t.id" +db/connectors/sqlite-query "SELECT t.id, t.type, t.title, t.status, p.title as parent_title FROM tickets t LEFT JOIN tickets p ON t.parent_id=p.id ORDER BY COALESCE(t.parent_id, t.id), t.id" ``` ### Sprint management ```bash # Create sprint -python3 db/connectors/sqlite_connector.py execute "INSERT INTO sprints (name, goal, start_date, end_date) VALUES ('<name>', '<goal>', '<start>', '<end>')" +db/connectors/sqlite-exec "INSERT INTO sprints (name, goal, start_date, end_date) VALUES ('<name>', '<goal>', '<start>', '<end>')" # Activate sprint -python3 db/connectors/sqlite_connector.py execute "UPDATE sprints SET status='active' WHERE id=<N>" +db/connectors/sqlite-exec "UPDATE sprints SET status='active' WHERE id=<N>" # Assign ticket to sprint -python3 db/connectors/sqlite_connector.py execute "UPDATE tickets SET sprint_id=<sprint_id> WHERE id=<ticket_id>" +db/connectors/sqlite-exec "UPDATE tickets SET sprint_id=<sprint_id> WHERE id=<ticket_id>" # Sprint status -python3 db/connectors/sqlite_connector.py query "SELECT s.name, s.goal, s.status, COUNT(t.id) as tickets, SUM(CASE WHEN t.status='done' THEN 1 ELSE 0 END) as done FROM sprints s LEFT JOIN tickets t ON t.sprint_id=s.id WHERE s.status='active' GROUP BY s.id" +db/connectors/sqlite-query "SELECT s.name, s.goal, s.status, COUNT(t.id) as tickets, SUM(CASE WHEN t.status='done' THEN 1 ELSE 0 END) as done FROM sprints s LEFT JOIN tickets t ON t.sprint_id=s.id WHERE s.status='active' GROUP BY s.id" ``` ### Dependencies ```bash # Add blocker -python3 db/connectors/sqlite_connector.py execute "INSERT INTO ticket_deps (blocker_id, blocked_id) VALUES (<blocker>, <blocked>)" +db/connectors/sqlite-exec "INSERT INTO ticket_deps (blocker_id, blocked_id) VALUES (<blocker>, <blocked>)" # Show blockers for a ticket -python3 db/connectors/sqlite_connector.py query "SELECT t.id, t.title, t.status FROM ticket_deps d JOIN tickets t ON d.blocker_id=t.id WHERE d.blocked_id=<N>" +db/connectors/sqlite-query "SELECT t.id, t.title, t.status FROM ticket_deps d JOIN tickets t ON d.blocker_id=t.id WHERE d.blocked_id=<N>" ``` ### Seed from decisions To re-seed the database with initiatives from DECISIONS.md: ```bash -python3 db/connectors/sqlite_connector.py seed-decisions +db/connectors/sqlite-seed +``` + +### Initialise database +```bash +db/connectors/sqlite-init ``` ## Workflow @@ -109,8 +118,8 @@ python3 db/connectors/sqlite_connector.py seed-decisions ## Labels ```bash # Add label -python3 db/connectors/sqlite_connector.py execute "INSERT INTO ticket_labels (ticket_id, label) VALUES (<id>, '<label>')" +db/connectors/sqlite-exec "INSERT INTO ticket_labels (ticket_id, label) VALUES (<id>, '<label>')" # Find by label -python3 db/connectors/sqlite_connector.py query "SELECT t.id, t.title FROM tickets t JOIN ticket_labels l ON t.id=l.ticket_id WHERE l.label='<label>'" +db/connectors/sqlite-query "SELECT t.id, t.title FROM tickets t JOIN ticket_labels l ON t.id=l.ticket_id WHERE l.label='<label>'" ``` diff --git a/db/connectors/sqlite-init b/db/connectors/sqlite-init new file mode 100755 index 000000000..8ef705cb9 --- /dev/null +++ b/db/connectors/sqlite-init @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Initialise the ticketing database from schema.sql. Whitelistable command. +# Usage: sqlite-init +exec python3 "$(dirname "$0")/sqlite_connector.py" init "$@" diff --git a/db/connectors/sqlite-seed b/db/connectors/sqlite-seed new file mode 100755 index 000000000..2b9bd9a47 --- /dev/null +++ b/db/connectors/sqlite-seed @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Seed the ticketing database with initiatives from DECISIONS.md. Whitelistable command. +# Usage: sqlite-seed +exec python3 "$(dirname "$0")/sqlite_connector.py" seed-decisions "$@"