Implement approved specification #32 and tickets #33-#37. Keep host authentication server-verified and pin session interaction language. Compile scoped base selectors for browser compatibility and retain full gutters during CSS pruning.
7.1 KiB
AGENTS.md
Agent skills
Issue tracker
Issues for this repository live in the self-hosted Gitea repository at https://git.tylconsulting.it/mptyl/ThothII; use its web UI or authenticated Gitea API. See docs/agents/issue-tracker.md.
Triage labels
Use the canonical labels needs-triage, needs-info, ready-for-agent, ready-for-human, and wontfix. See docs/agents/triage-labels.md.
Domain docs
This is a single-context repository with root CONTEXT.md and docs/adr/. See docs/agents/domain.md.
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Start here
Read PROJECT_STATE.md for the current-state snapshot: what was last
built, pending manual gates, workspace/secret layout, and design-doc locations. This file
holds the stable commands + architecture mental model; PROJECT_STATE.md holds the evolving
detail. Current architecture and contracts live in docs/architecture/, docs/contracts/,
and docs/evidence.md; durable design decisions live in docs/adr/. Git history is the source
for superseded designs and implementation plans.
Commands
The repo has three independently-built layers. Run the local Docker stack with ./scripts/run-stack.sh after creating deploy/env/local.env; it starts the base+local Compose profile with frontend, core, qdrant, embedding, and the one-shot embedding-model-init. The core image contains Pi. Qdrant and Ollama are internal Compose services; DWH and LLM remain external configuration endpoints.
Native host CLI tht (tools/tht/)
- Operator surface:
setup,start,stop,status,doctor,auth,workspace, andpi. - Use
tht --installation <absolute-path>/thothii-installation.yaml <command>for installation, authentication, diagnostics, lifecycle, and workspace operations.
harness/ (Python workflow tht CLI + Pi gate extension)
- Install:
cd harness && python -m venv .venv && pip install -e ".[dev]"(putsthton PATH) - Test:
.venv/bin/pytest -q—l2(real GLM + remote DB) is opt-in viaaddopts = -m 'not l2';l0(testcontainers) needs Docker - Single test:
.venv/bin/pytest tests/test_session_mutations.py::test_set_name -v(or-k <pattern>); include e2e with-m l2 - Lint:
.venv/bin/ruff check .(line-length 100)
backend/ (Fastify + TypeScript, vitest)
- Dev:
npm run dev(tsx watchsrc/server.ts) · Build:npm run build(tsc →dist/) - Test:
npx vitest run· Single:npx vitest run test/routes-sessions.test.ts -t "rename" - Typecheck:
npx tsc --noEmit -p .(vitest does NOT type-check — run this before committing)
frontend/ (React 18 + Vite + vitest)
- Dev:
npm run dev(Vite; setVITE_BACKEND_URL) · Build:npm run build - Test:
npx vitest run· Single:npx vitest run src/shell/NavSessions.test.tsx - Typecheck:
npx tsc -b· E2E:npm run e2e(Playwright)
Documentation (MkDocs, repository-locked Python dependencies)
- Strict build:
./scripts/build-docs.sh - Refresh lock:
./scripts/update-docs-lock.sh
No ESLint on the TS layers — tsc is the gate. Tests use vitest + MSW (no network).
Architecture (the parts that need multiple files to see)
frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → DWH (read-only)
-
The harness owns the workflow and all persistence. The Python workflow CLI
thtinsidecoreis deterministic;harness/.pi/extensions/tht-gate.jsis a Pi extension that drives an 8-phase NL→SQL workflow. The single source of workflow truth isharness/workflow.yaml; the orchestration rules the model must follow areharness/.pi/skills/tht-sessione/SKILL.md. "Current phase" is computed by folding the decision ledger (harness/tht/phase.py), not stored — read it before reasoning about phase logic. -
Persistence = phase documents, NOT chat. A session is a directory under the workspace's
sessions/path:session_manifest.yaml+ per-phase artifacts (question.md,schema_linking.json,sql_final.sql, …) +review_decisions.jsonl. The contract (SKILL.md): "the persisted state is the truth — what is not recorded did not happen." There is no verbatim transcript store. A resumed Pi process rebuilds context fromtht session show <id>+ the on-disk artifacts. -
The backend bridges sessions and owns the installation-local metadata catalog.
ThtRunnershells the Python workflowthtsubcommands insidecore;PiProcessManagerruns one Pi child per session and bridges its RPC stream;SessionBridgemaps Pi RPC events → client events (ui_request/text_delta/info);SseHubfans them out over SSE to the browser. The separate PostgreSQL catalog stores database metadata and sequential AI description-generation runs. Description generation samples the DWH through read-only connectors and calls a short-lived Python LiteLLM helper; it does not use Pi or expose a public CLI command. Sessions, metadata generation, and embedding resolve models from the generated Installation Model Catalog;thothii-installation.yamlis its only authored source. -
Human-in-the-loop gate contract. The model proposes; a human reviewer decides at gates via widgets (
reviewer_select= single pick — a chosen option carrying adecisionpayload auto-confirms/persists directly, an option without one only asks;reviewer_decide= multiselect, each choice IS a decision;reviewer_confirm= artifact/phase gate). The frontend renders these widget-descriptors (src/widgets/registry) and the live transcript is rebuilt in-memory from the SSE stream (src/store/sessionStore.ts) — it is not persisted.
Project-specific gotchas
tht's-c/--configis a PER-COMMAND option — it must follow the subcommand, never precede it (ThtRunner.buildArgvenforces this; prepending caused live 500s).--jsonoutput must be pristine (only valid JSON on stdout) — used as a machine contract.- Localization: deterministic UI uses the EN/IT catalogs with English fallback;
model interaction uses the session manifest's immutable
interaction_language. Workspace content, SQL, and identifiers remain unchanged. For shell modes, portal integration, or translations, readdocs/operations/shell-and-localization.md. - Workspace schema v4 defines workspace identity and optional Evidence only. PostgreSQL Metadata
Catalog owns database identity, binding, schema, descriptions, sensitivity, and relationships;
embedding/model facts come from the installation catalog. The legacy
harness/workspaces/*.yamlruntime snapshots still use absolute session/artifact/index paths; secrets stay inharness/.env(gitignored). - Settings are global (
backend/data/settings.json: workspace/thinking). Provider/model choices are ephemeral canonical catalog selections pinned into the session manifest. - Resume: a resumable session re-enters at its last incomplete phase. The backend refuses
resume with 409 when
finalizedorarchived, andPiProcessManager.spawnFormust send/riprendi-sessione <id>(resume mode) vs/nuova-domanda(new) — sending the wrong prompt silently turns a resume into a new question.