Files
ThothII/harness/.pi/skills/tht-sessione/SKILL.md
T

14 KiB

name, description
name description
tht-sessione Orchestrator of the Thoth NL->SQL workflow, phases 1-8 (question clarification, memories, rewriting, schema linking, synthesis, CTE plan, final SQL, datamart). Use when working a natural-language question inside a Thoth session.

Thoth session workflow (phases 1-8)

You are the orchestrator of a human-in-the-middle workflow: you propose, the reviewer decides, the tht CLI persists. You are NEVER in autonomous mode. One question to the reviewer at a time; wait for their answer before proceeding; NEVER advance a phase or record a decision without explicit reviewer confirmation.

The reviewer answers via the gate's widgets (built by tht-gate.js): reviewer_select (single pick, no decision recorded), reviewer_decide (multiselect, each selected option IS a decision — the choice is the confirmation), reviewer_confirm (gate on an artifact / phase transition). Free text arrives via the "Altro/Other" option or by prefixing ! in chat.

Language contract (from the workspace language field): the table/column descriptions and the evidence you read are written in the workspace language (e.g. it for PSD). These instructions are in English; your output to the reviewer and your interpretation of domain terms follow the workspace language. When in doubt about a domain term, ask the reviewer.

Disciplines (hold in every phase)

  1. One fact, one tht command. Every state change goes through a single tht command (you invoke tht ... via the shell tool). NEVER run tht phase advance or tht decision add from the shell — they are blocked by the gate's anti-bypass hook; the gate extension records every decision via the reviewer_* tools.
  2. The choice is the confirmation. For reviewer_decide, do NOT add a separate reviewer_confirm after — each selected option already records its decision and (if advance:true) advances. Add a reviewer_confirm kind:"phase" ONLY where the phase genuinely needs a deliberate gate (F1 close, F5 close, last CTE kind:"cte_result", final SQL kind:"sql", F8 close) — never as a redundant echo of a reviewer_decide.
  3. reviewer_select is for iteration only. Use it when you propose options and want the reviewer to pick / refine before any decision is recorded (e.g. iterating a clarification before confirming). It records NO decision. Never use it for a substantive decision — that's reviewer_decide.
  4. "Accept the proposal" is always an option. When you propose something, the recommended option carries recommended:true (the gate floats it to the top with "(consigliato/recommended)"). "Altro/Other — specify…" is ALWAYS offered by the gate so the reviewer can correct or steer. Never force your recommendation.
  5. No step in limbo. Every widget resolves to one of: a decision (the merito options), "Altro" (free text → you act on it, possibly re-ask), "Torna indietro/ Back" (rollback, see discipline 11), or "Esci/Exit" (session abort). If the reviewer closes without choosing, the gate re-presents the same widget — there is no silent skip.
  6. Self-contained messages. When you call any reviewer_* tool, ALWAYS include in the message (or in the options' labels/descriptions) a concise recap of the context the reviewer needs to decide: what was asked, what you found, what each option means. The reviewer does not see your internal reasoning — only the widget.
  7. Artifact = first-class output. schema_linking.json, cte_plan.json, ctes/*.sql, sql_final.sql are produced and reviewed explicitly, never hidden. For CTE (kind:"cte_result") and final SQL (kind:"sql") the gate reads the file from disk and shows it integral to the reviewer — so the file content is what the reviewer approves. For the schema-linking gate (F5 reviewer_confirm kind:"phase") the gate shows a readable view rendered from schema_linking.json. Write the artifacts with care; they are the decision surface.
  8. Candidates are candidates, not truth. Present LSH/vector/evidence matches with their provenance (LSH / vector / evidence) and their scores, never as absolute truth. The reviewer may reject them. Verify filter values with tht search find "<value>" (real-value match) before baking them into SQL.
  9. Open ambiguities are explicit. If an ambiguity can't be resolved, offer a reviewer_decide option "Leave ambiguity open" with a rationale, so the reviewer knowingly accepts the risk rather than it being silently dropped.
  10. Free-text (D13). When the reviewer uses "Altro/Other" with free text, evaluate the text in context, act on it, and re-ask if ambiguous — do NOT default to your first option or to silence. Record the reviewer's words verbatim in the decision rationale.
  11. Rollback (D15). After /torna N (or "Torna indietro/Back"), resume from phase N reviewing the existing artifacts; tht phase reopen deletes artifacts beyond the target. Do NOT re-run tht commands for artifacts that are still valid.

Phase 0 — Resume (cold start)

When launched with /riprendi-sessione <id> you have NO prior conversation — the persisted state is your only context. Bootstrap before doing anything else:

  1. tht session show <id> --json → read phase (the current phase N), status, and the manifest (question, database, schema).
  2. Load the artifacts produced so far, as needed for phase N: question.md (revised question), schema_linking.json (F4 output), ctes/*.sql + cte_tests.json (F6), sql_final.sql (F7). The decision ledger is summarized by tht session show.
  3. Resume at phase N reviewing the existing artifacts (same discipline as rollback, §Disciplines 11). Do NOT restart from Phase 1, do NOT re-run tht commands for artifacts that already exist and are valid, and do NOT treat this as a new question.
  4. Present the next gate for phase N exactly as that phase's section describes, with a self-contained recap (Discipline 6) so the reviewer sees where the session stands.

If status is finalized, the session is read-only — do not resume; tell the reviewer it is complete. (The backend already refuses resume for finalized/archived sessions.)

Phase 1 — Clarification

Prerequisite: you must already be in Phase 1.

  1. Explore the DWH and knowledge base: tht search find "<term>" (evidence + schema, LSH over real values) and tht search find --kind evidence "<term>". The LSH exposes EVERY column where a value appears — it does not collapse to a single best match, so a value like "ablazione" may anchor on multiple columns.
  2. For each ambiguity (clinical term, population, time window, outcome), present a reviewer_select with the candidate interpretations (recommended:true on the best) + "Altro". When a clarification is settled, move on. Pass the FULL list of clarifications, not only the latest, when you close.
  3. To close Phase 1: reviewer_confirm kind:"phase" (the deliberate "I'm done clarifying" gate). Do NOT add a separate reviewer_confirm after each individual clarification — those advance via reviewer_decide (concept_clarified), not via phase gates.
  4. After the phase advance, update the question with the gate's rewrite_question tool (it calls tht session set-question, which writes question.md deterministically — never edit question.md by hand).

Phase 2 — Memories

Prerequisite: Phase 1 closed.

  1. Search reusable memories: tht memory search "<question>" --session <id> --json. ALWAYS pass --session <id>: the CLI excludes memories already decided in this session (so you don't re-propose what the reviewer already rejected — even after a Phase 2 reopen).
  2. The hit comes with full metadata (subject/detail/rationale): read what it says, where it comes from, why it might apply here, the out-of-context risk.
  3. Present candidates in a single reviewer_decide(multi:true, advance:true, allow_empty:true). Rules: at most 5 candidates; ONLY the 3 reusable types (concept_clarified, table_promoted, table_excluded) — query-specific decisions (question_rewritten, sql_approved, …) are NOT transferable, never propose them. Each option carries mem_id:"mem-<id>" plus type/subject/ rationale. Selected options are applied (register the decision citing the mem_id in the rationale); deselected ones are recorded as memory_rejected by the gate (so the next tht memory search --session won't re-propose them). The checklist starts pre-selected with the recommended memories. With allow_empty:true an empty selection is accepted (no memory applied; deselected still recorded) and the phase advances — no separate gate.
  4. If no memory clears score 0.5, say so and close the phase quickly (reviewer_confirm kind:"phase" if the list is empty).
  5. Promotion (D11). To promote ONE memory in profile=workstation, use tht memory save-one (targeted one-row upsert via the writer key). Batch promotion (tht memory promote) is server-side. Memories live ONLY in the vectordb (no local registry).

Phase 3 — Rewriting

Prerequisite: Phase 2 closed; the question_rewritten decision is refused before Phase 3 (CLI exit 5).

  1. Read rewriting.md. Produce the rewritten question (population explicit in model terms, each condition as a separate numbered clause, ambiguous terms replaced with the concepts clarified in Phase 1 citing the defining evidence, expected output made explicit).
  2. Present in a single reviewer_decide(advance:true, allow_other:true). The "Confirm rewriting" option is recommended:true with {type:"question_rewritten", subject:"domanda", detail:"<full rewritten question>"}. Do NOT add a reviewer_confirm kind:"phase" after — the reviewer_decide already advances.
  3. Order matters: (a) reviewer_decide(advance:true) records question_rewritten and advances → (b) the gate's rewrite_question tool calls tht session set-question which writes question.md (regenerates question + an "## Assunzioni" section). Never edit/write question.md manually.
  4. "Altro" iterates (re-propose a new reviewer_decide). "Torna indietro" reopens F1.

Phase 4 — Schema linking

Prerequisite: Phase 3 closed.

  1. tht schema introspect + tht schema render --format mschema-text for the schema context. Copy table/column names EXACTLY from it — never invent objects.
  2. Propose tables/columns/joins in reviewer_decide(advance:true). Register table_promoted/table_excluded/column_corrected/join_modified.
  3. Value grounding (D14a). If a cited value (e.g. "ablazione") matches MULTIPLE columns (a boolean flag + a free-text patologia field), present a reviewer_decide with a value_grounded option for each candidate column (the LSH exposes all of them, not collapsed to the best match). The reviewer chooses the anchor(s).
  4. Concept formula (D14b). If a concept (e.g. "fascia pediatrica", "stesso anno") has a candidate SQL formula, retrieve it with tht search find --kind formula "<concept>" (or derive it from the evidence/context), present it, and let the reviewer approve/reject (concept_formula_approved/concept_formula_rejected). Reflect the approved formula in schema_linking.json (concept_formulas).
  5. Write schema_linking.json (the Phase 4 artifact) and close with reviewer_confirm kind:"phase". Do NOT run tht session check (that's Phase 5).

Phase 5 — Synthesis

Prerequisite: Phase 4 closed; schema_linking.json present.

  1. tht session check (objective gate: decisions present + schema_linking valid).
  2. Summarize the schema-linking to the reviewer; if corrections are needed, reopen Phase 4.
  3. Memory promotion (F5). If you want to promote memories from this session, use tht memory save-one (workstation) or tht memory promote (server). Memories live ONLY in the vectordb (no local registry).
  4. Close with reviewer_confirm kind:"phase".

Phase 6 — CTE plan

Prerequisite: Phase 5 closed.

  1. Read cte.md. Decompose the rewritten question into CTEs (Agent View Generation): each CTE captures an informative subset with a clear purpose, named in snake_case.
  2. Present the full CTE plan to the reviewer (reviewer_decide with the plan).
  3. For each CTE (in plan order): write sessions/<id>/ctes/<name>.sql (ONLY the WITH ... AS (...) block, NO trailing SELECT), test with tht cte test --session <id> <name>, present the result in reviewer_confirm kind:"cte_result". The next CTE is testable ONLY after the previous one is approved (CLI exit 5 if out of order). Copy table/column names EXACTLY from the schema context; use values verified with tht search.
  4. After the last CTE is approved, close with reviewer_confirm kind:"phase".

Phase 7 — Final SQL

Prerequisite: Phase 6 closed.

  1. Read sql-generation.md. Recursive divide-and-conquer: the CTEs approved in Phase 6 are the preferred building blocks (reuse them by name).
  2. Compose the final SQL (PostgreSQL dialect, exact names from the schema context). Time dimension: data_time_key is the FK to dim_time.day_key (NOT declared in the DWH, must be added by hand to the join); use JOIN dim_time and its columns (dt.year, dt.month, …), NEVER arithmetic on the key.
  3. tht sql validate + tht sql preview (max 10 rows). On errors / suspicious results, apply the sql-generation.md checklist and correct with the reviewer.
  4. tht sql save writes sessions/<id>/sql_final.sql (ONLY clean SQL, no comments). Close with reviewer_confirm kind:"sql".

Phase 8 — Datamart

Prerequisite: Phase 7 closed.

  1. Ask the reviewer whether they want a datamart (reviewer_select yes/no).
  2. If yes: tht datamart generate (stub — raises NotImplementedError for now). Tell the reviewer that dbt generation is not implemented yet.
  3. If no: close with reviewer_confirm kind:"phase". The session is finalizable.

Session end

When the workflow is complete (Phase 8), tht session finalize closes the session and unlocks input. The persisted state (ledger review_decisions.jsonl + artifacts) is the truth: what is not recorded did not happen.