11 KiB
User-owned sessions implementation plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Associate every ThothII session and preference with a stable logged-in or local OS principal.
Architecture: The harness owns a repository contract. FilesystemSessionRepository stores readable phase documents under the local user home; PostgresSessionRepository stores the same logical snapshot in a private Supabase schema. The backend resolves a trusted principal before every action and passes it through to tht; the portal proxy supplies that identity.
Tech Stack: Python 3.12, Typer, SQLAlchemy/psycopg2, PostgreSQL/Supabase RLS, Fastify/TypeScript, React/Vitest, Django/nginx.
Global Constraints
- Server storage is PostgreSQL wire protocol with TLS verification, schema
thoth_sessions; never PostgREST or browser DB access. - Server identity is
(issuer, Django request.user.pk); clients never choose session owner. - Admin authorization uses Authentik group
authentik Admins; unauthorized and missing session both return HTTP 404. - Server has no persistent session filesystem fallback or dual write; DB failure is HTTP 503 before Pi starts.
- Local mode uses
~/.thothiiorTHT_HOME, runs loopback-only, and creates a UUID identity inidentity.json. - Persist current artifacts and append-only decisions only; no chat transcript, artifact revisions, session embeddings, or content in audit logs.
- New session IDs are UUIDv4. Existing
solved_questionbehavior is unchanged. - Follow TDD: each behavior test must fail before its implementation is written.
Task 1: Session repository contract and local implementation
Files:
- Create:
harness/tht/session/repository.py,harness/tht/session/filesystem_repository.py - Modify:
harness/tht/config.py,harness/tht/session/store.py,harness/tht/session/models.py,harness/pyproject.toml - Test:
harness/tests/test_session_repository.py,harness/tests/test_local_identity.py
Interfaces: Produce PrincipalContext, SessionSnapshot, SessionRepository, and build_session_repository(config, principal). The filesystem adapter must preserve the present documents under <THT_HOME>/workspaces/<workspace>/sessions/<uuid4> and read/write artifact keys, decisions, manifest fields, and per-principal preferences.
- Write failing tests proving UUIDv4 creation, principal-scoped local roots, readable phase artifacts, decision append,
THT_HOMEoverride, and an identity UUID stable across restarts. - Run
cd harness && .venv/bin/pytest tests/test_session_repository.py tests/test_local_identity.py -q; confirm failure because repository and identity interfaces do not exist. - Implement the smallest repository contract and filesystem adapter. Use
portalockerfor mutations and private local directory/file permissions where supported. - Run the focused tests and
cd harness && .venv/bin/pytest -q && .venv/bin/ruff check .. - Commit
feat(harness): add local session repository.
Task 2: PostgreSQL schema, migrations, and repository
Files:
- Create:
harness/tht/session/postgres_repository.py,harness/tht/migrations/sessions/001_schema.sql,harness/tht/migrations/sessions/002_security.sql - Modify:
harness/tht/cli/session_cmd.py,harness/tht/config.py - Test:
harness/tests/test_postgres_session_repository.py,harness/tests/test_session_migrate_cmd.py
Interfaces: Add tht session migrate --database-url URL [--status] --json; PostgresSessionRepository implements the Task 1 contract, starts a transaction, sets actor/admin local settings, and maps cte_sql:<name> to artifacts.
- Write failing unit/integration tests for migration status, owner isolation, admin cross-user access, cascade delete with content-free audit tombstone, and no embedding invocation.
- Run the focused tests and confirm expected RED failures.
- Implement idempotent migration runner, private tables, forced RLS policies, role separation, advisory transaction locks, and repository methods using direct PostgreSQL TLS settings.
- Run focused tests, then full harness tests and Ruff.
- Commit
feat(harness): persist server sessions in postgres.
Task 3: Migrate harness workflow and deterministic write commands
Files:
- Modify:
harness/tht/session/store.py,harness/tht/decisions.py,harness/tht/phase.py,harness/tht/taskdoc.py,harness/tht/ctetest.py,harness/tht/solved.py,harness/tht/teardown.py,harness/tht/cli/{session,decision,cte,sql,phase,search,memory}_cmd.py,harness/.pi/skills/tht-sessione/SKILL.md,harness/.pi/extensions/tht-gate.js - Test:
harness/tests/test_session_repository_workflow.py,harness/gate/__tests__/session-repository-writes.test.js
Interfaces: Existing workflow commands operate through the configured repository. Add tht cte save --session ID --name NAME --file - and tht sql set-final --session ID --file -; Pi tools write_cte_sql and write_final_sql use them instead of direct session paths.
- Write failing tests that run phase calculation and finalize against an in-memory/filesystem repository, and prove Pi write tools persist CTE/final SQL without direct
sessions/<id>writes. - Run focused tests and record RED results.
- Refactor path-bound helpers into snapshot/ledger and repository calls; retain backwards-compatible readable local documents and pristine
--jsonstdout. - Make finalization atomically store report/evidence/status only after DWH verification; leave solved-question creation best-effort.
- Run harness and gate test suites, then commit
refactor(harness): route workflow persistence through repositories.
Task 4: Trusted portal identity and proxy forwarding
Files:
- Modify:
/home/chirone/omics_portal/kokoro/datamart_catalog_views.py,/home/chirone/omics_portal/nginx/nginx.conf - Create:
/home/chirone/omics_portal/kokoro/test_thothii_auth.py
Interfaces: The auth-request response supplies only X-Thoth-Principal-Issuer, X-Thoth-Principal-Subject, X-Thoth-Principal-Display-Name, and X-Thoth-Is-Admin. nginx removes client values for those headers and forwards subrequest values to ThothII.
- Write Django tests for authenticated capability user, denied user, Django PK subject, admin group flag, and absent/spoofed client headers.
- Run the focused Docker test and confirm RED.
- Emit normalized headers from the capability endpoint and configure nginx auth-request header capture/injection.
- Run
docker compose exec -T web python manage.py test accounts.test_capabilities kokoro.test_thothii_auth -v 2. - Commit the portal changes in its own repository with
feat(thothii): forward trusted principal.
Task 5: Backend principal enforcement and per-user settings
Files:
- Create:
backend/src/auth/principal.ts - Modify:
backend/src/auth/auth.ts,backend/src/config.ts,backend/src/app.ts,backend/src/routes/{sessions,settings,sql,meta}.ts,backend/src/tht/tht-runner.ts,backend/src/pi/pi-process-manager.ts - Test:
backend/test/auth.test.ts,backend/test/routes-sessions.test.ts,backend/test/sse-route.test.ts,backend/test/routes-settings.test.ts
Interfaces: Add GET /me; require a PrincipalContext for all session, document, SQL, response, steer and SSE operations. GET /sessions?scope=mine|all permits all only for admins. Local mode creates ~/.thothii/identity.json; upstream mode accepts only proxy-injected normalized headers.
- Write failing route tests for missing identity (401), foreign session (404), admin all-scope, owner assignment server-side, SSE denial before Pi spawn, and preference isolation.
- Run
cd backend && npx vitest run test/auth.test.ts test/routes-sessions.test.ts test/sse-route.test.ts test/routes-settings.test.ts; confirm RED. - Implement principal parser, local identity, upstream validation, repository-aware
ThtRunner, session authorization before Pi,/me, scope enforcement and async per-user settings. - Run backend Vitest, typecheck, and build; commit
feat(backend): enforce user-owned sessions.
Task 6: Frontend identity and administrator UX
Files:
- Modify:
frontend/src/api/{client,sessions,settings,types}.ts,frontend/src/shell/{AppShell,NavSessions,SessionMenu}.tsx - Test:
frontend/src/api/sessions.test.ts,frontend/src/shell/AppShell.session-mgmt.test.tsx,frontend/src/shell/NavSessions.test.tsx
Interfaces: Fetch /me; default to scope=mine. Display explicit All sessions only to admins, show owner labels/admin banner, and require confirmation before cross-owner destructive actions.
- Write failing component/API tests for regular-user scope, admin scope switch, owner label, admin banner, and cross-owner confirmation.
- Run focused Vitest tests and confirm RED.
- Implement typed client calls, session scope state, and explicit admin affordances without changing ordinary user flow.
- Run frontend Vitest,
npx tsc -b, build and E2E; commitfeat(frontend): expose owned session scopes.
Task 7: Deployment contract, migration and cutover tooling
Files:
- Modify:
docker/, deployment examples,README.md,PROJECT_STATE.md - Test:
harness/tests/test_session_migrate_cmd.py,backend/test/config.test.ts
Interfaces: Define runtime/migrator DB secret names, AUTH_MODE=upstream server configuration, local loopback-only configuration, and health/readiness behavior returning 503 when repository storage is unavailable.
- Write failing config tests for required server database/TLS inputs and rejected public/local combinations.
- Run focused tests and confirm RED.
- Document runtime/migrator roles, CA/secret injection, backup then deletion of the three legacy server sessions, maintenance-mode cutover, and no dual-write rollback policy.
- Run all three layer gates; commit
docs(deploy): document user-owned session cutover.
Task 8: End-to-end authorization verification and final review
Files:
-
Modify: test fixtures only as required by earlier tasks.
-
Add cross-layer tests for A/B/admin isolation, spoofed-header rejection, concurrent session mutation, local two-home isolation, absent embeddings, and failed DB startup before Pi.
-
Run harness, backend and frontend complete gates plus portal Docker tests.
-
Run the final whole-branch review, fix all Critical and Important findings, and re-run the covering tests.
-
Commit
test: cover user-owned session security boundariesand prepare the branch for integration.