@r1z4x/tezgah 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +96 -1
  2. package/MANIFEST +6 -1
  3. package/README.md +6 -4
  4. package/bin/consult +13 -10
  5. package/bin/tezgah-docs +1 -1
  6. package/bin/tezgah-research +53 -3
  7. package/bin/tezgah-route +8 -5
  8. package/bin/tezgah-setup +45 -25
  9. package/bin/tezgah-task +194 -41
  10. package/docs/architecture.md +1 -1
  11. package/docs/citations-baseline.json +1 -1
  12. package/docs/clarity-baseline.json +4 -4
  13. package/docs/contract.md +4 -1
  14. package/docs/feature-audit.md +24 -3
  15. package/docs/gate.md +10 -11
  16. package/docs/hosts.md +9 -0
  17. package/docs/index.json +21 -7
  18. package/docs/judge.md +3 -1
  19. package/docs/layers.md +1 -1
  20. package/docs/models.md +17 -7
  21. package/docs/operations.md +0 -1
  22. package/docs/research.md +46 -0
  23. package/docs/skills.md +23 -5
  24. package/docs/testing.md +1 -1
  25. package/hooks/tezgah_agents.py +130 -96
  26. package/hooks/tezgah_components.py +2 -1
  27. package/hooks/tezgah_context.py +67 -15
  28. package/hooks/tezgah_gate.py +62 -76
  29. package/hooks/tezgah_judge.py +15 -8
  30. package/hooks/tezgah_models.py +50 -3
  31. package/hooks/tezgah_paths.py +26 -11
  32. package/hooks/tezgah_policy.py +47 -19
  33. package/hooks/tezgah_product.py +107 -0
  34. package/hooks/tezgah_research.py +3 -3
  35. package/hooks/tezgah_skill_pick.py +58 -17
  36. package/hooks/tezgah_task.py +16 -8
  37. package/hosts/opencode/plugins/tezgah.js +17 -37
  38. package/package.json +1 -2
  39. package/skills/analyze-app/SKILL.md +57 -0
  40. package/skills/design-contract/EVALS.md +24 -1
  41. package/skills/design-contract/SKILL.md +17 -1
  42. package/skills/design-contract/data-views.md +86 -0
  43. package/skills/feature-audit/SKILL.md +32 -3
  44. package/skills/plan-add/EVALS.md +8 -8
  45. package/skills/plan-add/SKILL.md +20 -21
  46. package/skills/plan-sync/EVALS.md +2 -2
  47. package/skills/plan-sync/SKILL.md +11 -7
  48. package/skills/pm-frameworks/SKILL.md +6 -0
  49. package/skills/product-analysis/EVALS.md +23 -1
  50. package/skills/product-analysis/SKILL.md +50 -11
  51. package/skills/product-flow/EVALS.md +81 -0
  52. package/skills/product-flow/SKILL.md +91 -0
  53. package/skills/research/SKILL.md +10 -1
  54. package/skills/tezgah-contract/SKILL.md +67 -41
  55. package/agents/tezgah-reviewer.md +0 -79
package/docs/index.json CHANGED
@@ -267,7 +267,8 @@
267
267
  "what do init, claim, migrate and source write",
268
268
  "how does a session learn that a research line is broken",
269
269
  "what lights the research mark and how is the layer switched off",
270
- "why may a new research line not be opened while another is unfinished"
270
+ "why may a new research line not be opened while another is unfinished",
271
+ "what does tezgah-research next print for a product flow, and when is a decision due for re-measure"
271
272
  ],
272
273
  "answers_tr": [
273
274
  "bir araştırma hattı nerede yaşar ve ne tutar",
@@ -275,11 +276,13 @@
275
276
  "init, claim, migrate ve source ne yazar",
276
277
  "bir oturum bir araştırma hattının bozuk olduğunu nasıl öğrenir",
277
278
  "araştırma işaretini ne yakar ve katman nasıl kapatılır",
278
- "başka biri bitmemişken neden yeni bir araştırma hattı açılamaz"
279
+ "başka biri bitmemişken neden yeni bir araştırma hattı açılamaz",
280
+ "tezgah-research next bir ürün akışı için ne yazdırır ve bir karar ne zaman yeniden ölçülmeli"
279
281
  ],
280
282
  "sources": [
281
283
  "hooks/tezgah_research.py",
282
284
  "bin/tezgah-research",
285
+ "hooks/tezgah_product.py",
283
286
  "hooks/tezgah_policy.py",
284
287
  "hooks/tezgah_context.py",
285
288
  "skills/research/SKILL.md",
@@ -294,12 +297,18 @@
294
297
  "answers": [
295
298
  "what is a skill here and how does it reach a host",
296
299
  "which skills ship and what does each do",
297
- "how do I add a skill without breaking the router or the install report"
300
+ "how do I add a skill without breaking the router or the install report",
301
+ "which skill designs a metric dashboard and where do its data-view rules live",
302
+ "does the local skill search reach design-library's nested entries",
303
+ "which skill carries a new metric dashboard or feature from research to re-measure"
298
304
  ],
299
305
  "answers_tr": [
300
306
  "burada beceri nedir ve bir hosta nasıl ulaşır",
301
307
  "hangi beceriler gelir ve her biri ne yapar",
302
- "yönlendiriciyi veya kurulum raporunu bozmadan nasıl beceri eklerim"
308
+ "yönlendiriciyi veya kurulum raporunu bozmadan nasıl beceri eklerim",
309
+ "metrik dashboard tasarımını hangi beceri yapar ve veri görünümü kuralları nerede",
310
+ "yerel beceri araması design-library'nin iç girdilerine ulaşır mı",
311
+ "yeni bir metrik dashboard'u veya özelliği araştırmadan yeniden ölçüme hangi beceri taşır"
303
312
  ],
304
313
  "sources": [
305
314
  "bin/tezgah-setup",
@@ -309,7 +318,10 @@
309
318
  "commands/",
310
319
  "NOTICE",
311
320
  "tests/test_setup.py",
312
- "tests/test_skills.py"
321
+ "tests/test_skills.py",
322
+ "hooks/tezgah_skill_pick.py",
323
+ "skills/design-contract/data-views.md",
324
+ "skills/product-flow/SKILL.md"
313
325
  ]
314
326
  },
315
327
  {
@@ -320,12 +332,14 @@
320
332
  "answers": [
321
333
  "what does a feature-level audit cover that a screen review misses",
322
334
  "what are the five matrices and the capability-change proposal",
323
- "how is the feature-audit skill reached and what evidence backs it"
335
+ "how is the feature-audit skill reached and what evidence backs it",
336
+ "how do I specify a feature before it is built and audit it against that spec"
324
337
  ],
325
338
  "answers_tr": [
326
339
  "özellik düzeyinde bir denetim, ekran incelemesinin kaçırdığı neyi kapsar",
327
340
  "beş matris ve yetenek değişikliği önerisi nedir",
328
- "özellik denetimi becerisine nasıl ulaşılır ve onu hangi kanıt destekler"
341
+ "özellik denetimi becerisine nasıl ulaşılır ve onu hangi kanıt destekler",
342
+ "bir özelliği yapılmadan önce nasıl tanımlarım ve yapıldıktan sonra o tanıma göre nasıl denetlerim"
329
343
  ],
330
344
  "sources": [
331
345
  "skills/feature-audit/SKILL.md",
package/docs/judge.md CHANGED
@@ -138,7 +138,7 @@ shape, so a caller that needs a typed answer takes them like Jev.
138
138
  | Carrier | Endpoint | Credential (env, else file, stripped) | Body |
139
139
  |---|---|---|---|
140
140
  | `typesafe` | `https://api.typesafe.ai/v1/systemone` | `TYPESAFE_API_KEY`, else `~/.config/typesafe/key`, else the active omp login (`~/.omp/agent/agent.db`, read-only; `typesafe_key`, `hooks/tezgah_paths.py::typesafe_key`) | `{state, model, questions}` |
141
- | `jev-openrouter` | `https://openrouter.ai/api/v1/systemone` | `OPENROUTER_API_KEY`, else `~/.config/openrouter/key` | the same, a bare `jev-*` id sent as `typesafe/<id>` |
141
+ | `jev-openrouter` | `https://openrouter.ai/api/v1/systemone` | `OPENROUTER_API_KEY`, else `~/.config/openrouter/key` | the same; a bare `jev-*` id is sent as it is, and OpenRouter maps it onto `typesafe/` |
142
142
  | `jev-cloudflare` | `https://api.cloudflare.com/client/v4/accounts/<id>/ai/run` | `JEV_CLOUDFLARE_API_TOKEN`, else `CLOUDFLARE_API_TOKEN`, else `~/.config/cloudflare/token`; the account id from `CLOUDFLARE_ACCOUNT_ID`, else `~/.config/cloudflare/account_id` | `{model: "typesafe/jev", input: {state, questions}}`; the reply is read bare or inside `result` |
143
143
  | `jev-compatible` | `JEV_API_BASE_URL`, used verbatim | `JEV_API_KEY` | TypeSafe's, the model from `TEZGAH_JEV_MODEL` if set |
144
144
  | `clef`, `clef-flash` | `https://api.cloudflare.com/client/v4/accounts/<id>/ai/run/@cf/cloudflare/<name>` | the Cloudflare token and account id above | `{model: "<name>", state, questions}`; the reply read like Cloudflare's above |
@@ -148,6 +148,8 @@ reads, so one export serves both. `TEZGAH_JEV_PROVIDER` chooses the carrier,
148
148
  else `JEV_PROVIDER`, else `jev` in `~/.config/tezgah/config.json`, else `auto`
149
149
  (`jev_choice`, `hooks/tezgah_paths.py::jev_choice`). The values are `auto`,
150
150
  `typesafe`, `openrouter`, `cloudflare`, `compatible`, `clef` and `clef-flash`.
151
+ The Workers AI ids `@cf/cloudflare/clef` and `@cf/cloudflare/clef-flash` name
152
+ the same two (`jev_name`, `hooks/tezgah_paths.py::jev_name`).
151
153
  `tezgah-setup --jev <value>` writes the config key
152
154
  (`set_jev`, `bin/tezgah-setup::set_jev`). `auto`
153
155
  asks every carrier that resolves, in the table's order (`jev_carriers`,
package/docs/layers.md CHANGED
@@ -76,7 +76,7 @@ lessons and research lines.
76
76
  Must not own the loop, the model, the tools or the network. tezgah never runs
77
77
  the work and never rolls back on its own - rollback is the explicit
78
78
  `bin/tezgah-rollback` - and the subagents it defines are rendered into a host's
79
- own agent surface for that host to run (`hooks/tezgah_agents.py:2-22`).
79
+ own agent surface for that host to run (`hooks/tezgah_agents.py:2-30`).
80
80
 
81
81
  ## The boundary, one term at a time
82
82
 
package/docs/models.md CHANGED
@@ -59,21 +59,21 @@ invoices).
59
59
  | Host | Family | Where the model lands |
60
60
  |---|---|---|
61
61
  | Claude Code | anthropic | the agent file's alias and `effort:` (`_model_lines`): an alias follows the provider and keeps the main session's variant, where a full id breaks on Bedrock, Vertex and a gateway (code.claude.com/docs/en/sub-agents) |
62
- | Codex | openai | `model` and `model_reasoning_effort` in `.codex/agents/*.toml` |
62
+ | Codex | openai | `model` and `model_reasoning_effort` in `$CODEX_HOME/agents/*.toml` |
63
63
  | opencode | any | a selector `--refresh` found in `opencode models` for the slot's model under any configured provider (`resolve_opencode`); none found, no model line, so the agent inherits. The slot's effort rides the JSON agent config as `reasoningEffort` (opencode.ai/docs/agents) |
64
64
  | omp | anthropic when the session default is an Anthropic model, any otherwise (`omp_mode`); a non-Anthropic default is `any`, never a silent fall back to the Anthropic column | `task.agentModelOverrides`, which omp resolves before the agent or bundled model (omp's own docs: `omp://task-agent-discovery.md`, *Model and structured-output precedence*); every slot is written, the frontier row included, so no agent in the row runs on the session default; each override is a **fallback chain** (`omp_overrides`, `_chain`): the mode's family first, then what `fallback` in `~/.config/tezgah/config.json` allows (`tp.fallback_policy`) over the families this machine holds a credential for (`funded_families` reads omp's auth store and the provider env keys; a family it cannot see is left out, never guessed in) - `vendor`, the default, keeps only the session vendor's model (`openrouter/anthropic/claude-opus-5.5:<effort>` behind an Anthropic session, `OPENROUTER_ID`), so a 429 never moves an Opus session's subagent onto GPT or GLM; `any` adds every other funded family, rotated per agent; `none` writes the first entry alone - omp splits the chain into per-spawn patterns (omp's own docs: `omp://settings.md (its `retry.fallbackChains` section)`), so one provider's 429 falls through instead of killing the spawn, measured before this: 24 of 26 post-routing 429s hit a subagent's first request, all on one Opus account every slot shared; `apply_omp` also writes `modelRoles.plan` and `.slow` on that frontier row (same record, same ownership) so plan mode designs on it, and their fallbacks go to `retry.fallbackChains.<role>` under the same `fallback` rule, the only chain keys tezgah owns (`default` and provider-keyed chains stay the user's); `apply_omp` writes through the installer's own binary and agent dir, from HOME so a repository's `.omp/config.yml` never leaks machine-wide, and touches only the entries tezgah wrote (recorded in `~/.config/tezgah/models.json` as `omp_written`; a machine written before that record is adopted by its value, `_ours_by_shape`); a changed `fallback` reaches omp on the next `tezgah-route --refresh` or `tezgah-setup --install` |
65
65
  | dsh | - | none: no model setting was found to write |
66
66
 
67
67
  The orchestrator agent keeps `model: inherit`: it is the main thread's own agent.
68
68
 
69
- | Cursor | - | reads `.claude/agents/` today; Cursor wants its own model ids with the effort **inside** the id (`claude-opus-5[effort=high]`, cursor.com/docs/subagents), and no id this table names was verified against Cursor's models page - so a `.cursor/agents/` rendering that pins a model is not generated yet |
69
+ | Cursor | - | `model: inherit` in `.cursor/agents/*.md` (`render_md_cursor`): `cursor-agent` passes the value through as a raw id, an alias such as `opus` is not in its model list, and the effort belongs **inside** the id (`claude-opus-5[effort=high]`, cursor.com/docs/subagents). No id this table names was verified against Cursor's models page, so no tier model is pinned there yet |
70
70
 
71
71
  omp's bundled agents are routed through the same record (omp's own docs: `omp://task-agent-discovery.md`, *Bundled agents*): `scout` on the explore slot, `sonic` on the cheap slot, `task` on the standard slot, and `reviewer`/`security-reviewer` left to inherit, because a review is frontier work. A user's own value for any of them wins (see the ownership rule above). Those two are the gap this leaves: the record carries no entry for them, so a session on a cheap model reviews on that model - routing them is one more `BUNDLED` entry, not decided here.
72
72
 
73
73
  ## What is not routed yet
74
74
 
75
75
  - **Claude Code's built-in subagents** (Explore, general-purpose, Plan) run on the session model. `CLAUDE_CODE_SUBAGENT_MODEL` and a settings `env` block exist but carry no effort, and whether a project agent with a built-in's name replaces it is not stated where it can be cited - so nothing is generated on a guess. What would close it: a documented per-agent effort for built-ins, or a confirmed name-collision rule.
76
- - **Codex's default subagent** (spawned with no agent file): only `.codex/agents/*.toml` carries a model today. What would close it: a documented `[agents]` default settable from a repo-scoped file tezgah already writes.
76
+ - **Codex's default subagent** (spawned with no agent file): only `$CODEX_HOME/agents/*.toml` carries a model today. What would close it: a documented `[agents]` default settable from a file tezgah already writes.
77
77
  - **opencode's built-in agents**: the injected JSON could carry `model`/`reasoningEffort` for them, but the merge semantics for a built-in entry are not documented where they can be cited, and a wrong merge would replace a built-in prompt instead of adding a model.
78
78
  - **dsh**: the model is a plugin config, not an agent field. The composed profile carries `agent-default-model` with `config: {provider: deepseek-official, model: deepseek-flash}` (`dsh --profile web --dump-config`, 2026-09-30) and tezgah's managed patch block already patches plugin config by id (its `llm-pi-ai` row), so a `- id: agent-default-model` row would set the profile's model. Not written, because that knob is one model for the whole session - no `subagent*` entry in the composed tree carries a model - and a single session-wide model is the main thread's setting, which this design deliberately leaves alone ([why the main thread keeps one model](#the-shape)). What would close it: a per-agent model in dsh's config surface.
79
79
 
@@ -91,7 +91,9 @@ fixed:
91
91
  (`OVERRIDE`, `hooks/tezgah_models.py::OVERRIDE`) - the class the judge
92
92
  under-routed in its measurement, and the classes a wrong call cannot be
93
93
  undone on. A 12-brief fixture pins it: 8 high-stakes briefs route to
94
- frontier, 4 near-miss controls do not (`tests/test_models.py`).
94
+ frontier, 4 near-miss controls do not (`tests/test_models.py`). Such a brief
95
+ that only reviews goes to `tezgah-security` instead (`REVIEW_ONLY`,
96
+ `hooks/tezgah_models.py::REVIEW_ONLY`).
95
97
  2. Otherwise the brief - redacted with the ledger's own reader
96
98
  (`redact`, `hooks/tezgah_integrity.py::redact`) - goes to the judge as one Choice over three tiers (`TIER_QUESTION`,
97
99
  `hooks/tezgah_models.py::TIER_QUESTION`). The judge asks the session's own model first ([judge](judge.md)).
@@ -99,9 +101,17 @@ fixed:
99
101
  the same session that wrote the rubric (2026-09-30, twice): under-route 0.025,
100
102
  accuracy 0.925 and 0.900, 392 ms median, about 656 input tokens per call; a
101
103
  keyword rule on the same set under-routed 0.100. The session model was not measured on that set.
102
- 3. With no judgement (`judge-off`, no key, a failed call) `--phase` picks the tier
103
- from the static table (`PHASE_TIER`, `hooks/tezgah_models.py::PHASE_TIER`), and
104
- with no phase the middle tier is used.
104
+ The same call asks a second Choice (`ROLE_QUESTION`,
105
+ `hooks/tezgah_models.py::ROLE_QUESTION`): is the brief the whole job of a
106
+ specialist? A yes names that agent on its own tier (`AGENT_SLOT`,
107
+ `hooks/tezgah_models.py::AGENT_SLOT`). Before this question, sessions
108
+ spawned the five specialists 0 times in 121 delegations (2026-10-07 to 10-09).
109
+ Clef agreed on 9 of 10 briefs this session labelled (2026-10-09).
110
+ 3. With no judgement (`judge-off`, no key, a failed call) `--phase review` and
111
+ `--phase research` name the reviewer and the researcher (`PHASE_AGENT`,
112
+ `hooks/tezgah_models.py::PHASE_AGENT`). Another phase picks the tier from the
113
+ static table (`PHASE_TIER`, `hooks/tezgah_models.py::PHASE_TIER`). With no
114
+ phase the middle tier is used.
105
115
 
106
116
  The brief leaves the machine for the judge, like every judgement ([judge](judge.md)).
107
117
  Every routed call writes one `route` row to the session's ledger. The row names the
@@ -28,7 +28,6 @@ before an install is considered.
28
28
  | `--status [PATH]` | Print the armed/used checklist for PATH (default cwd) and stop — the same line as `bin/tezgah-status` (`bin/tezgah-setup::main`, `hooks/tezgah_context.py::health_lines`). It also prints the report's `config.json hosts (...) match the hosts wired (...)` row when the recorded list and the wiring on disk disagree (`hosts_row`), and nothing when they agree: install health is checked here, not only in a full report. |
29
29
  | `--agents [PATH]` | Regenerate PATH's per-repo subagent set (default cwd); outside a [root](glossary.md#root) it prints `no agents generated` (`bin/tezgah-setup::main`). |
30
30
  | `--write-manifest` | Regenerate the tracked `MANIFEST` from `git ls-files` and stop — the release step, its only writer, and it says so on a tree with no `.git` rather than writing an empty listing (`bin/tezgah-setup::write_manifest`, `bin/tezgah-setup::plugin_files`). |
31
- | `--write-plugin-agents` | Re-render the plugin's tracked `agents/*.md` from the role bodies `hooks/tezgah_agents.py` generates per repo, and stop — the release step that keeps the shipped reviewer from drifting from the generated one; `tests/test_agents.py` fails until it has run (`write_plugin_agents`, `plugin_agents`). |
32
31
  | `--deps` | Install the missing optional tools and stop; with `--install` the install already does it. Like `--install` and `--enable`, it exits 1 when a requested tool is still missing (`bin/tezgah-setup::main`). |
33
32
  | `--host-deps` | With `--install` or `--deps`, also install the missing third-party host CLIs (cursor-agent, pnpm, dsh). They are opt-in because each one is a vendor `curl \| sh` that uninstall does not take back. Every installer runs with a 600 s timeout, each `curl` with `--max-time 300` and each pipeline under `pipefail`, so a stalled or refused download fails instead of hanging or reading as success (audit M-9). |
34
33
  | `--mcp-schemas` | Measure the MCP tool-schema band by asking each registered server (`initialize` + `tools/list`) and stop (`bin/tezgah-setup::main`, `bin/tezgah-setup::mcp_schema_report`). |
package/docs/research.md CHANGED
@@ -238,14 +238,59 @@ through its seal.
238
238
  | `tezgah-research source <slug> <hypothesis> --run <orxRunId> [--command "..."] [--scope real\|fixture\|derived] [--fixture "<what was generated>"]` | keeps the receipt: runs `orx logs <runId>`, writes `raw/<runId>.log`, appends the results row `{"source": "orx:<runId>", ...}` and the scope and fixture description the filer states (`source_run`, `hooks/tezgah_research.py::source_run`). A `--scope fixture` filed without `--fixture` still writes the row and prints the field it still owes, so the tool is never the thing that makes its own checker warn silently; a given `--fixture` that is empty is misuse | 0, 1 nothing filed, 2 without orx |
239
239
  | `tezgah-research compare <slug> <decision>` | reads one variants x criteria cell from stdin and appends it to `decisions/<decision>/comparison.jsonl` under the lock, or refuses it by the rule `check` applies (`append_comparison` and `comparison_problems`, `hooks/tezgah_research.py`); it notes when `criteria.json` is not committed yet | 0, 1 refused, 2 misuse |
240
240
  | `tezgah-research close <slug> --limit "<reason>"` | concludes the line as a deliberate limit, writing the reasons it was still open into `state.json` `closed` and `log.md`, and seals it (`close_line`) | 0, 1 unreadable state, 2 misuse |
241
+ | `tezgah-research verdict <slug> <id> met\|not-met\|unanswerable --evidence "<ref>"` | records one success criterion's verdict and the evidence it rests on in the line's `state.json`, or refuses it with one `FAIL verdict:` line per problem (`verdict_problems`, `hooks/tezgah_research.py::verdict_problems`) | 0, 1 refused or unreadable state, 2 misuse |
242
+ | `tezgah-research conclude <slug>` | concludes a line once every success criterion carries a verdict, seals it and moves it to `done/` (`conclude_line`, `hooks/tezgah_research.py::conclude_line`) | 0, 1 refused, 2 misuse |
243
+ | `tezgah-research migrate-layout` | moves flat `research/<slug>` directories into `open/` or `done/` by each line's state, and is idempotent (`migrate_layout`, `hooks/tezgah_research.py::migrate_layout`) | 0, 2 misuse |
241
244
  | `tezgah-research seal <slug> [--history-lost] --ack "<owner decision>"` | seals a line under `done/` that was concluded before seals existed: plainly, as `conclude` would, when every experiment's order still checks; with `--history-lost`, with that verdict for every experiment whose order the lost history left undecidable. Refuses a line with a real order violation, a plain seal on any order finding, and a `history-lost` seal with nothing lost (`retro_seal`, `hooks/tezgah_research.py::retro_seal`) | 0, 1 refused, 2 misuse |
242
245
  | `tezgah-research import <checkout> [<slug>] [--allow-open "<reason>"]` | brings a line - or every line this checkout lacks - from another checkout's `.tezgah` repository with its history; an open line arrives beside open ones only with `--allow-open` (`import_line`, `hooks/tezgah_research.py::import_line`) | 0, 1 refused, 2 misuse |
246
+ | `tezgah-research next --topic <t> [--flow f] [--json]` | prints every step of a product flow with its status from the topic's files under `.tezgah/analysis/<topic>/`, then the first missing or due step's skill and command; `--flow` picks `metric-dashboard` (the default) or `feature`, and `--json` prints the same steps as data (`next_steps`, `hooks/tezgah_product.py::next_steps`) | 0, 2 unknown flow or no `--topic` |
243
247
 
244
248
  Exit code 2 is always misuse, so a caller can tell it from a line that fails the
245
249
  checks (`misuse`, `bin/tezgah-research::misuse`). `check` asks nothing at all - no
246
250
  network, no model - so its answer is reproducible on a machine with no
247
251
  credential; only `--orx` asks the one question that leaves the machine.
248
252
 
253
+ ## The next step of a product flow
254
+
255
+ `tezgah-research next --topic <t>` tells the session which step of a product flow
256
+ comes next. Its step table is `FLOWS` (`hooks/tezgah_product.py::FLOWS`).
257
+ Each step names its `id`, the `skill` that runs it, what it `leaves` behind and
258
+ the `command` that writes it. The `product-flow` skill lists the same nine steps
259
+ in prose and names `next` as their status source.
260
+
261
+ Two flows exist. `metric-dashboard` is the default and has nine steps. `feature`
262
+ drops the metrics and instrumentation steps, unless the topic's `flow.md` already
263
+ holds `## metrics`. `--flow <f>` picks one.
264
+
265
+ `next_steps` (`hooks/tezgah_product.py::next_steps`) computes each status from the
266
+ topic's folder, `.tezgah/analysis/<topic>/`, and reads nothing else. Nothing
267
+ stores a status. A step is `done`, `missing` or `due`:
268
+
269
+ | Step | Done when |
270
+ |---|---|
271
+ | `forward-spec` | `.tezgah/analysis/<topic>/spec.md` exists |
272
+ | `re-measure` | `flow.md` holds `## re-measure`. Before that it reads `due` once the `observe after: YYYY-MM-DD` date under `## decision` has passed |
273
+ | every other step | `flow.md` holds its `## <step>` heading |
274
+
275
+ The `design` and `build` commands start with `tezgah-design check`. The design
276
+ check and the Stop UI rule judge those two steps. The flow only asks for their
277
+ note. A topic that is not kebab-case (at most 64 characters) reads no file. A
278
+ topic with no folder yet lists every step as `missing`.
279
+
280
+ The text output prints one line per step, then one `next:` line:
281
+
282
+ ```
283
+ <n>. <id> [<status>] <skill> - <detail>
284
+ next: <skill> - <command>
285
+ ```
286
+
287
+ The `next:` line names the first `missing` or `due` step's skill and command.
288
+ With no such step it reads `next: nothing left`. `--json` prints the same steps
289
+ as a list of objects with `id`, `skill`, `status`, `detail` and `command`.
290
+
291
+ `next` exits 0 when it prints the steps. It exits 2 for an unknown flow or a
292
+ missing `--topic`.
293
+
249
294
  ## The pair the order rule compares
250
295
 
251
296
  The order rule is decided on the commit graph, so it needs both files committable
@@ -832,6 +877,7 @@ armed. It removes the rule, not just the mark - the diff is in `core_split`,
832
877
  component, the keys a prediction row names and the rules a row's outcome is
833
878
  attributed to.
834
879
  - `bin/tezgah-research` - the CLI, its subcommands and its exit codes.
880
+ - `hooks/tezgah_product.py` - the product-flow steps and the `next` status reader.
835
881
  - `hooks/tezgah_policy.py` - the `RESEARCH` paragraph a session is armed with.
836
882
  - `hooks/tezgah_context.py` - the prompt hint, the missing-orx note, the broken
837
883
  line note and the `research` mark.
package/docs/skills.md CHANGED
@@ -128,6 +128,12 @@ rebuilds that index only when a SKILL.md's mtime or size moves
128
128
  (`hooks/tezgah_skill_pick.py::_open_index`). A prompt reads its own terms'
129
129
  postings and the length column, never the corpus.
130
130
 
131
+ Some skills route through their own `INDEX.md`, like design-library's 39 entries.
132
+ The search indexes each routed entry as one row for the whole file, addressed
133
+ `skill://<skill>/<path>` (`hooks/tezgah_skill_pick.py::_entries`). The vendored
134
+ sections are short, and per section BM25 let them outrank whole skills on two
135
+ common words.
136
+
131
137
  The hook then appends one line, `A local skill search matched this request:
132
138
  skill://<name>:<start>-<end>`, with the section title. Every host but omp also
133
139
  gets the absolute path. The top section must carry 60% of the prompt's
@@ -174,15 +180,16 @@ it (`tests/test_skills.py::SkillStandards`).
174
180
  | `ponytail` | Forces the laziest solution that works, in levels lite/full/ultra; fires on any coding task, or "be lazy", "yagni", "shortest path". |
175
181
  | `i-have-adhd` | Shapes output for a reader who acts on it - action first, numbered steps, errors as location/cause/fix; fires on any answer the reader must act on, not on code, commits or docs. |
176
182
  | `no-ai-slop` | Edits a draft sharper and more human without losing the voice, or flags slop; fires on a draft review, on a draft in a language other than English, on text that must keep terms, identifiers or unit symbols verbatim, and before publishing English prose tezgah writes itself. |
177
- | `analyze-app` | Inspects and drives a running web or mobile app from its accessibility / DOM / view tree, its rendered screen (screenshots, blur and grayscale tests, breakpoints) and measurements taken in the page; fires when a task must verify behaviour or read the UI, not just read source. |
183
+ | `analyze-app` | Inspects and drives a running web or mobile app from its accessibility / DOM / view tree, its rendered screen (screenshots, blur and grayscale tests, breakpoints) and measurements taken in the page, and writes the `.tezgah/design/measurement.json` that `design-contract`'s check reads; fires when a task must verify behaviour or read the UI, not just read source. |
178
184
  | `plan-add` | Creates a plan under `.tezgah/plans/open/` with its own `allowed_paths:` scope, bootstraps the `.tezgah/plans/` layer if missing, commits it in the private `.tezgah` repository (`git -C .tezgah`, never the project's git); fires on `/tezgah:plan-add`, "track this as a plan". |
179
185
  | `plan-status` | Reads every open plan and `tezgah-task status` (each plan's Acceptance boxes ticked, the plans its `after:` waits on, the ready plans that can run at once), enriches rows with live PR state from `gh`, rewrites the README table (committed in the private `.tezgah` repository) and recommends the next plan; fires on `/tezgah:plan-status` or "what plans are open". |
180
- | `plan-sync` | Closes finished plans whose PR merged or closed through `tezgah-task close`, which moves a plan to `.tezgah/plans/done/` as done only when it records an approving `review:`; commits one message per plan in the private `.tezgah` repository; fires on `/tezgah:plan-sync`, "sync plans". |
186
+ | `plan-sync` | Closes finished plans whose PR merged or closed through `tezgah-task close`, which moves a plan to `.tezgah/plans/done/` as done only when it records an approving `review:`, clears an active task's phase and removes every merged worktree that holds nothing else; commits one message per plan in the private `.tezgah` repository; fires on `/tezgah:plan-sync`, "sync plans". |
181
187
  | `research` | Runs an auditable research line - two loops, protocol before run, six-dimension review, provenance; fires when the deliverable is evidence: a lit review, a hypothesis, a benchmark or ablation. |
182
- | `product-analysis` | Runs a product analysis across five axes - value (HEART), usability (heuristics, the cognitive walkthrough, WCAG 2.2, axe-core, the running app read through `analyze-app` down to component x state, tree and image both), feasibility (a cited `path:line`), competition (a dated teardown) and triage (keep/fix/cut/bet) - with one named evidence class per finding, executed as a research line; fires on a product, feature, retention or roadmap question rather than a code change. |
188
+ | `product-analysis` | Runs a product analysis across five axes - value (HEART), usability (heuristics, the cognitive walkthrough, WCAG 2.2, axe-core, the running app read through `analyze-app` down to component x state, tree and image both), feasibility (a cited `path:line`), competition (a dated teardown) and triage (keep/fix/cut/bet) - with one named evidence class per finding and a metric record per metric (North Star and inputs; goal, definition, window, baseline, logged or not), executed as a research line; fires on a product, feature, retention or roadmap question rather than a code change. |
189
+ | `product-flow` | Carries a new product capability - a metric dashboard, a metric, a feature - from research to re-measure by running `tezgah-research next --topic <t>` and doing the first missing step with the skill it names; the skill lists the nine steps in prose and `FLOWS` in `hooks/tezgah_product.py` holds their done rules; fires on "bu veriye uygun metric dashboard tasarla" or a new-feature ask, not on an audit of an existing feature. |
183
190
  | `pm-frameworks` | The two vendored product methods the analysis skill defers to - intended-vs-implemented and the Opportunity Solution Tree - kept offline so an offline session reads the method instead of citing its name. |
184
- | `feature-audit` | Audits ONE feature across every layer it is spread over - the surfaces a person uses (a control, a list or table, a detail view, a filter, a picker, a step flow, a notification), the route, the authorization, the service and the data - by filling the capability, field-contract, flow/step and interaction-dependency matrices, where a disagreement between layers is a finding and a fix needing an absent capability becomes a capability-change proposal; fires on an admin screen, CRUD, form, wizard, data table, filter or permission question about an existing feature. |
185
- | `design-contract` | The artifact shape of the per-repo `.tezgah/design-contract.md` - colour roles, type scale, spacing unit and rhythm, the component inventory, the state set every interactive control and data view owes - the derivation rule that reads it out of the repository's own tokens, and the rules `bin/tezgah-design check` fails on; fires on a UI or component turn that needs a floor, a token, a state set, or the design check itself. |
191
+ | `feature-audit` | Audits ONE feature across every layer it is spread over - the surfaces a person uses (a control, a list or table, a detail view, a filter, a picker, a step flow, a notification), the route, the authorization, the service and the data - by filling the capability, field-contract, flow/step and interaction-dependency matrices, where a disagreement between layers is a finding and a fix needing an absent capability becomes a capability-change proposal; fires on an admin screen, CRUD, form, wizard, data table, filter or permission question about an existing feature, and in forward mode specifies a feature not built yet so the post-build audit diffs against it. |
192
+ | `design-contract` | The artifact shape of the per-repo `.tezgah/design-contract.md` - colour roles, type scale, spacing unit and rhythm, the component inventory, the state set every interactive control and data view owes - the derivation rule that reads it out of the repository's own tokens, the rules `bin/tezgah-design check` fails on, and the data-view rules for dashboards (`skills/design-contract/data-views.md`); fires on a UI or component turn that needs a floor, a token, a state set, or the design check itself. |
186
193
  | `design-library` | The vendored MC Dean design/UX subset - 39 skills in the `cognitive-accessibility`, `adaptive-interfaces`, `inclusive-interaction`, `visual-critique` and `design-research` plugins - read one entry at a time through its own `INDEX.md`, never the tree; fires when a UI or product turn needs a cognitive-load, inclusive-interaction or visual-critique method tezgah has no counterpart for. |
187
194
  | `ai-research` | The vendored 98-skill library for AI/ML machinery - training and serving a model, benchmarks, interpretability, retrieval pipelines; read one entry, never the tree. |
188
195
  | `rl-env` | The vendored FineEnvs skill set for authoring an RL environment from a description - OpenEnv, OpenReward/ORS, Verifiers and NeMo Gym, plus the orchestrator that ports one description across all four; read one entry, never the tree. |
@@ -198,6 +205,17 @@ The generated specialists load skills first (`hooks/tezgah_agents.py::SPECIALIST
198
205
  | `tezgah-security` | the host's `wstg-*`, `attack-*`, `ci-assessment` and `llm-security` skills, which tezgah does not ship |
199
206
  | `tezgah-tester` | none |
200
207
 
208
+ ### The product chain
209
+
210
+ A new product capability runs as one chain: research -> `product-analysis` ->
211
+ decision -> forward spec -> `design-contract` -> build -> re-measure. Each link
212
+ leaves a file under `.tezgah/analysis/<topic>/` that names the one before it.
213
+ `flow.md` holds one `## <step>` note per step. The forward spec
214
+ (`feature-audit`'s forward mode) is `spec.md`. `FLOWS`
215
+ (`hooks/tezgah_product.py::FLOWS`) holds the steps and their done rules.
216
+ `tezgah-research next` prints them with their status (docs/research.md, "The
217
+ next step of a product flow").
218
+
201
219
  ## Vendored material
202
220
 
203
221
  `NOTICE` records every third-party skill and its terms: it opens by saying the
package/docs/testing.md CHANGED
@@ -171,7 +171,7 @@ into the test process would answer about the developer's real machine.
171
171
  | `tests/_probe_paths.py` | argv op, no payload (`:11`) | `roots`, `root_for`, `off`, `default_root`, `config`, `off_dirs`, `cache_dir`, `which_user`, `orx_bin`, `consult_options`, `have_typesafe_key`, `codegraph_bin` |
172
172
  | `tests/_probe_context.py` | JSON on stdin, `{"fn": ...}` (`:4-5`) | `context_for`, `health_lines`, `health_segments`, `record` |
173
173
  | `tests/_probe_integrity.py` | JSON on stdin (`:4-6`) | `note`, `note_tool`, `note_turn`, `kinds`, `events`, `prior_calls`, `counters`, `shortcut_command`, `shortcut_edit`, `stop_reason`, `verify_command` |
174
- | `tests/_probe_agents.py` | JSON on stdin (`:3-4`) | `sync_root`, `opencode_json`, `cleanup`, `detect` |
174
+ | `tests/_probe_agents.py` | JSON on stdin (`:3-4`) | `sync_root`, `opencode_json`, `cleanup`, `detect`, `omp`, `user`, `steering` |
175
175
  | `tests/_probe_gate.py` | JSON on stdin (`:4-8`) | the shared gate `decision(tool, input, cwd, session_id)`; `capture_log` plants a stub `tezgah_snapshot` in `sys.modules`, so the snapshot call site is pinned whether or not that module has landed |
176
176
 
177
177
  A probe is invoked through `support.run`/`run_json` with its path constant