@r1z4x/tezgah 1.11.0 → 1.14.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.
- package/CHANGELOG.md +507 -1
- package/MANIFEST +40 -0
- package/NOTICE +152 -0
- package/README.de.md +41 -20
- package/README.es.md +39 -19
- package/README.fr.md +41 -20
- package/README.md +18 -10
- package/README.tr.md +39 -21
- package/bin/codegen +9 -2
- package/bin/consult +6 -0
- package/bin/tezgah-adhd +3 -0
- package/bin/tezgah-agents +3 -0
- package/bin/tezgah-capture +3 -0
- package/bin/tezgah-design +329 -54
- package/bin/tezgah-docs +158 -42
- package/bin/tezgah-dsh +1 -1
- package/bin/tezgah-gate +7 -2
- package/bin/tezgah-import-ai-research +16 -4
- package/bin/tezgah-index +3 -0
- package/bin/tezgah-lessons +13 -4
- package/bin/tezgah-mcp +4 -0
- package/bin/tezgah-migrate +3 -0
- package/bin/tezgah-ocr-review +2 -1
- package/bin/tezgah-optimize +4 -1
- package/bin/tezgah-pony +3 -0
- package/bin/tezgah-research +51 -10
- package/bin/tezgah-rollback +3 -0
- package/bin/tezgah-route +1 -1
- package/bin/tezgah-setup +1741 -95
- package/bin/tezgah-status +11 -1
- package/bin/tezgah-task +58 -17
- package/bin/tezgah.js +10 -3
- package/commands/adhd.md +1 -1
- package/docs/README.md +19 -8
- package/docs/architecture.md +2 -2
- package/docs/citations-baseline.json +11 -17
- package/docs/clarity-baseline.json +12 -6
- package/docs/contract.md +83 -34
- package/docs/environment.md +59 -24
- package/docs/evidence.md +128 -25
- package/docs/gate.md +77 -23
- package/docs/glossary.md +1 -1
- package/docs/hosts.md +343 -48
- package/docs/layers.md +2 -2
- package/docs/models.md +6 -0
- package/docs/operations.md +83 -29
- package/docs/research.md +37 -11
- package/docs/skills.md +31 -8
- package/docs/status-line.md +39 -23
- package/docs/testing.md +50 -17
- package/docs/vision.md +6 -2
- package/hooks/hooks.json +1 -1
- package/hooks/lang/en.json +16 -2
- package/hooks/lang/tr.json +14 -2
- package/hooks/projects-posttooluse.py +11 -3
- package/hooks/projects-stop.py +3 -2
- package/hooks/tezgah_agents.py +27 -3
- package/hooks/tezgah_attest.py +79 -10
- package/hooks/tezgah_context.py +61 -31
- package/hooks/tezgah_gate.py +480 -126
- package/hooks/tezgah_integrity.py +577 -133
- package/hooks/tezgah_lessons.py +5 -2
- package/hooks/tezgah_paths.py +60 -8
- package/hooks/tezgah_policy.py +48 -18
- package/hooks/tezgah_replay.py +8 -2
- package/hooks/tezgah_research.py +167 -24
- package/hooks/tezgah_skill_pick.py +1 -1
- package/hooks/tezgah_snapshot.py +6 -3
- package/hooks/tezgah_stack.py +236 -1
- package/hooks/tezgah_stopspec.py +2 -1
- package/hooks/tezgah_task.py +2 -1
- package/hosts/amp/hook.py +217 -0
- package/hosts/amp/tezgah-plugin.ts.in +396 -0
- package/hosts/antigravity/hook.py +255 -0
- package/hosts/codex/hook.py +3 -2
- package/hosts/commandcode/hook.py +239 -0
- package/hosts/copilot/hook.py +284 -0
- package/hosts/cursor/hook.py +4 -2
- package/hosts/droid/hook.py +259 -0
- package/hosts/dsh/hooks.json +1 -1
- package/hosts/gemini/hook.py +213 -0
- package/hosts/goose/hook.py +145 -0
- package/hosts/omp/hook.py +5 -2
- package/hosts/omp/tezgah-hook.ts.in +157 -42
- package/hosts/opencode/plugins/tezgah.js +209 -63
- package/hosts/qwen/hook.py +206 -0
- package/output-styles/tezgah.md +11 -6
- package/package.json +6 -3
- package/packaging/build.sh +4 -4
- package/packaging/install.sh +11 -0
- package/packaging/upgrade.sh +3 -0
- package/skills/ai-research/LICENSE +21 -0
- package/skills/design-contract/SKILL.md +27 -6
- package/skills/design-library/LICENSE +21 -0
- package/skills/harness/SKILL.md +2 -0
- package/skills/i-have-adhd/SKILL.md +10 -1
- package/skills/plan-add/SKILL.md +5 -1
- package/skills/plan-add/render_table.py +7 -0
- package/skills/pm-frameworks/LICENSE +21 -0
- package/skills/research/SKILL.md +22 -9
- package/skills/rl-env/LICENSE +201 -0
- package/skills/tezgah-contract/SKILL.md +21 -8
- package/statusline.py +20 -9
- package/third_party/open-code-review/LICENSE +201 -0
- package/third_party/open-code-review/README.md +15 -0
- package/third_party/open-code-review/prompts/main_task_system.md +26 -0
- package/third_party/open-code-review/prompts/review_filter_task_system.md +13 -0
- package/workflows/graph-map.js +14 -5
- package/workflows/graph-review.js +14 -2
package/bin/tezgah-status
CHANGED
|
@@ -117,7 +117,8 @@ import sys
|
|
|
117
117
|
HERE = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
|
118
118
|
sys.path.insert(0, os.path.join(HERE, "hooks"))
|
|
119
119
|
from tezgah_context import ( # noqa: E402
|
|
120
|
-
LEGEND, color_default, health_segments, render_line,
|
|
120
|
+
LEGEND, TOOL_USE_MEASURES, color_default, health_segments, render_line,
|
|
121
|
+
skill_fitness)
|
|
121
122
|
|
|
122
123
|
# How many rows of the tool histogram the plain report prints. The count is on
|
|
123
124
|
# the line and `--json` carries every row, so a reader can always see what was
|
|
@@ -432,6 +433,15 @@ def main():
|
|
|
432
433
|
if "--help" in flags:
|
|
433
434
|
sys.stdout.write(__doc__.strip() + "\n")
|
|
434
435
|
return 0
|
|
436
|
+
# the two skill-read marks are measures too; a typo here blanked every mark
|
|
437
|
+
measures = TOOL_USE_MEASURES | {"pony", "adhd"}
|
|
438
|
+
named = {n for f in flags if f.startswith("--observable=")
|
|
439
|
+
for n in f.split("=", 1)[1].split(",") if n}
|
|
440
|
+
if named - measures:
|
|
441
|
+
sys.stderr.write("tezgah-status: unknown measure(s) in --observable: %s "
|
|
442
|
+
"(known: %s)\n" % (", ".join(sorted(named - measures)),
|
|
443
|
+
", ".join(sorted(measures))))
|
|
444
|
+
return 2
|
|
435
445
|
if "--legend" in flags:
|
|
436
446
|
sys.stdout.write(LEGEND)
|
|
437
447
|
return 0
|
package/bin/tezgah-task
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
tezgah-task allow GLOB ... | --any-path --why REASON replace the allowlist, recording why
|
|
7
7
|
tezgah-task stop deactivate (clear phase)
|
|
8
8
|
tezgah-task status [--json] the active task, then every open plan: progress, what it waits on, what can run at once
|
|
9
|
-
tezgah-task review <NNN|path> <reviewer> approve|changes
|
|
9
|
+
tezgah-task review <NNN|path> <reviewer> approve|changes [--no-slice WHY] record a fresh review's verdict; approve needs the reviewer's slice record, or WHY it has none
|
|
10
10
|
tezgah-task close <NNN|path> done|discarded [--resolved TEXT] move a plan to .tezgah/plans/done, deactivate it, remove merged worktrees
|
|
11
11
|
tezgah-task tick <NNN|path> <n> [--undo] tick (or untick) Acceptance item n, counted from 1
|
|
12
12
|
tezgah-task note <NNN|path> state|next "<text>" replace the body of `## State` (the newest one) or `## Next`
|
|
@@ -1082,7 +1082,7 @@ def budget_spent(path, ident):
|
|
|
1082
1082
|
% (path, REVIEW_ROUNDS, ident, say()["decision"], ident))
|
|
1083
1083
|
|
|
1084
1084
|
|
|
1085
|
-
def unfinished_review(root, reviewer, plan="", since=0):
|
|
1085
|
+
def unfinished_review(root, reviewer, plan="", since=0, no_slice="", ran_since=0):
|
|
1086
1086
|
"""The refusal of an `approve` while a slice journal record whose id or agent
|
|
1087
1087
|
is `reviewer` is open, stopped or stale: a review slice that died on a
|
|
1088
1088
|
provider limit had its approve recorded anyway, and a NameError it would have
|
|
@@ -1097,7 +1097,11 @@ def unfinished_review(root, reviewer, plan="", since=0):
|
|
|
1097
1097
|
`tt.open_slice`) counts too. Under TEZGAH_SESSION only this session's
|
|
1098
1098
|
records and unowned ones count, by id, agent or name alike: another
|
|
1099
1099
|
session's review is not this approve's. The refusal names the exact id,
|
|
1100
|
-
which `slice resume` and `slice done` take from any session.
|
|
1100
|
+
which `slice resume` and `slice done` take from any session. No finished
|
|
1101
|
+
record changed at or after `ran_since` refuses too: a requested reviewer with
|
|
1102
|
+
no status did not run, and a plan-readiness review before the checkpoint, an
|
|
1103
|
+
earlier round's review or a `resumed` record with no re-run is not this
|
|
1104
|
+
review - unless `no_slice` says why the reviewer ran outside the journal."""
|
|
1101
1105
|
from tezgah_paths import off
|
|
1102
1106
|
if off("slices-off"):
|
|
1103
1107
|
return []
|
|
@@ -1113,21 +1117,42 @@ def unfinished_review(root, reviewer, plan="", since=0):
|
|
|
1113
1117
|
return rec["plan"] == plan
|
|
1114
1118
|
return (_stamp(rec.get("updated")) or 0) >= since
|
|
1115
1119
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1120
|
+
found = [rec for rec in tt.slices(root) if named(rec) and ours(rec)]
|
|
1121
|
+
refusals = ["review slice %s is %s%s: let it finish, or resume it with `tezgah-task "
|
|
1122
|
+
"slice resume %s` and wait for that run; if the review was finished "
|
|
1123
|
+
"another way, record it with `tezgah-task slice done %s` - an approve "
|
|
1124
|
+
"from a review that did not finish reads nothing"
|
|
1125
|
+
% (rec["id"], rec.get("status"),
|
|
1126
|
+
(" (%s)" % rec["failure"]) if rec.get("failure") else "",
|
|
1127
|
+
rec["id"], rec["id"])
|
|
1128
|
+
for rec in found if rec.get("status") in ("open", "stopped", "stale")]
|
|
1129
|
+
ran = [rec for rec in found if rec.get("status") == "done"
|
|
1130
|
+
and (_stamp(rec.get("updated")) or 0) >= ran_since]
|
|
1131
|
+
if not ran and not refusals and not no_slice:
|
|
1132
|
+
# a requested reviewer with no finished record since the work is a
|
|
1133
|
+
# review that did not run
|
|
1134
|
+
refusals.append(
|
|
1135
|
+
"no finished review slice names %s for this plan since its work began: "
|
|
1136
|
+
"a reviewer with no record did not run, and a readiness review, an "
|
|
1137
|
+
"earlier round or a resumed record is not this review. Spawn the fresh "
|
|
1138
|
+
"reviewer and approve once its slice is done; a host that keeps no "
|
|
1139
|
+
"slice journal records why with "
|
|
1140
|
+
"`--no-slice \"<why: the reviewer ran outside the slice journal>\"`"
|
|
1141
|
+
% reviewer)
|
|
1142
|
+
return refusals
|
|
1126
1143
|
|
|
1127
1144
|
|
|
1128
1145
|
def cmd_review(args):
|
|
1146
|
+
no_slice = ""
|
|
1147
|
+
if "--no-slice" in args:
|
|
1148
|
+
i = args.index("--no-slice")
|
|
1149
|
+
no_slice = " ".join((args[i + 1:i + 2] or [""])[0].split())
|
|
1150
|
+
args = args[:i] + args[i + 2:]
|
|
1151
|
+
if not no_slice:
|
|
1152
|
+
return misuse("--no-slice takes why the reviewer ran outside the slice journal")
|
|
1129
1153
|
if len(args) != 3 or args[2] not in VERDICTS:
|
|
1130
|
-
return misuse("review takes <NNN|path> <reviewer> %s
|
|
1154
|
+
return misuse("review takes <NNN|path> <reviewer> %s [--no-slice WHY]"
|
|
1155
|
+
% "|".join(VERDICTS))
|
|
1131
1156
|
path, problem = open_plan(args[0])
|
|
1132
1157
|
if problem:
|
|
1133
1158
|
return problems([problem])
|
|
@@ -1144,9 +1169,21 @@ def cmd_review(args):
|
|
|
1144
1169
|
mark = (fields.get("checkpoint") or "").split()
|
|
1145
1170
|
since = (git_out(root, "log", "-1", "--format=%ct", mark[-1])
|
|
1146
1171
|
if mark and mark[-1] != tt.CHECKPOINT_PENDING else None)
|
|
1172
|
+
since = int(since) if (since or "").isdigit() else 0
|
|
1173
|
+
# this round's review finished after the first commit of the work it
|
|
1174
|
+
# reads: past the checkpoint in round one (a plan-readiness review ran
|
|
1175
|
+
# before it), past the commit round one read in round two (round one's
|
|
1176
|
+
# reviewer finished before it); with no such commit, after the base itself
|
|
1147
1177
|
ident = fields.get("id") or os.path.basename(path).split("-")[0]
|
|
1148
|
-
|
|
1149
|
-
|
|
1178
|
+
base = fields.get("reviewed_sha") or (
|
|
1179
|
+
mark[-1] if mark and mark[-1] != tt.CHECKPOINT_PENDING else "")
|
|
1180
|
+
first = ""
|
|
1181
|
+
if base:
|
|
1182
|
+
after = (git_out(tt.plan_holders(root).get(ident) or root, "log",
|
|
1183
|
+
"--reverse", "--format=%ct", base + "..HEAD") or "").split()
|
|
1184
|
+
first = after[0] if after else git_out(root, "log", "-1", "--format=%ct", base)
|
|
1185
|
+
ran_since = max(since, int(first) if (first or "").isdigit() else 0)
|
|
1186
|
+
bad = unfinished_review(root, args[1], ident, since, no_slice, ran_since)
|
|
1150
1187
|
if bad:
|
|
1151
1188
|
return problems(bad)
|
|
1152
1189
|
# a plan held by its own worktree is built on that branch: its HEAD is the
|
|
@@ -1154,7 +1191,8 @@ def cmd_review(args):
|
|
|
1154
1191
|
ident = fields.get("id") or os.path.basename(path).split("-")[0]
|
|
1155
1192
|
where = tt.plan_holders(root).get(ident) or root
|
|
1156
1193
|
sha = (git_out(where, "rev-parse", "HEAD") or "")[:12]
|
|
1157
|
-
record = {"review": "%s %s %s" % (args[1], args[2], today()
|
|
1194
|
+
record = {"review": "%s %s %s%s" % (args[1], args[2], today(),
|
|
1195
|
+
" no-slice: " + no_slice if no_slice else ""),
|
|
1158
1196
|
"review_round": str(int(prior) + 1 if prior.isdigit() else 1),
|
|
1159
1197
|
"updated": today()}
|
|
1160
1198
|
if sha:
|
|
@@ -2010,6 +2048,9 @@ def main(argv):
|
|
|
2010
2048
|
print(__doc__, file=sys.stderr)
|
|
2011
2049
|
return 2
|
|
2012
2050
|
cmd, rest = argv[1], argv[2:]
|
|
2051
|
+
if cmd in ("-h", "--help"):
|
|
2052
|
+
print(__doc__.strip())
|
|
2053
|
+
return 0
|
|
2013
2054
|
if writes_a_record(cmd, rest):
|
|
2014
2055
|
mark = owner_mark(repo_root(os.getcwd()))
|
|
2015
2056
|
if mark:
|
package/bin/tezgah.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// bin/tezgah.js - npm's bin entry: finds a Python interpreter and execs
|
|
3
3
|
// bin/tezgah-setup with every argument passed through. npm resolves this
|
|
4
4
|
// symlink to the global prefix, so process.argv[1] is the shim, not the target.
|
|
5
|
-
const { spawn } = require("child_process");
|
|
5
|
+
const { spawn, spawnSync } = require("child_process");
|
|
6
6
|
const { existsSync } = require("fs");
|
|
7
7
|
const os = require("os");
|
|
8
8
|
const path = require("path");
|
|
@@ -18,9 +18,12 @@ const candidates = process.env.TEZGAH_PYTHON
|
|
|
18
18
|
? [process.env.TEZGAH_PYTHON]
|
|
19
19
|
: ["python3", "python3.12", "python3.11", "python3.10", "python"];
|
|
20
20
|
|
|
21
|
+
// Probed exactly as it is spawned below - no shell - so a value the probe
|
|
22
|
+
// accepts is one spawn can start (`TEZGAH_PYTHON="python3 -S"` passed a shell
|
|
23
|
+
// probe, then died in spawn with a stack trace).
|
|
21
24
|
const py = candidates.find(c => {
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const probe = spawnSync(c, ["-c", ""], { stdio: "ignore" });
|
|
26
|
+
return !probe.error && probe.status === 0;
|
|
24
27
|
});
|
|
25
28
|
|
|
26
29
|
if (!py) {
|
|
@@ -29,6 +32,10 @@ if (!py) {
|
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
const child = spawn(py, [setup, ...process.argv.slice(2)], { stdio: "inherit" });
|
|
35
|
+
child.on("error", err => {
|
|
36
|
+
process.stderr.write("tezgah: cannot start " + py + ": " + err.message + "\n");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
});
|
|
32
39
|
// A child killed by a signal reports code null, and process.exit(null) is exit
|
|
33
40
|
// 0: an installer killed mid-run read as a success (audit L-10, ENV-06). The
|
|
34
41
|
// shell convention 128 + signal number carries the failure out instead.
|
package/commands/adhd.md
CHANGED
|
@@ -12,7 +12,7 @@ adhd="$HOME/.config/tezgah/bin/tezgah-adhd"
|
|
|
12
12
|
|
|
13
13
|
- No argument: run it bare, which prints `on` or `off`.
|
|
14
14
|
- `off`: disarms the rule everywhere on this machine.
|
|
15
|
-
- `on`: arms it again (`
|
|
15
|
+
- `on`: arms it again (`on` is the default).
|
|
16
16
|
- Anything else: the CLI exits 2 with the usage on stderr - show that to the
|
|
17
17
|
user and stop.
|
|
18
18
|
|
package/docs/README.md
CHANGED
|
@@ -7,7 +7,8 @@ tool to someone deciding whether to install it; `AGENTS.md` says how to check a
|
|
|
7
7
|
change; these pages explain how the thing actually works, so a session does not
|
|
8
8
|
have to re-derive it by reading 55 Python files. Every page is written for one
|
|
9
9
|
reader with one question in mind, and every non-obvious claim in it carries a
|
|
10
|
-
citation you can open: `path::symbol` into Python
|
|
10
|
+
citation you can open: `path::symbol` into Python, JavaScript and TypeScript
|
|
11
|
+
code, `path:line` elsewhere.
|
|
11
12
|
|
|
12
13
|
## Start here
|
|
13
14
|
|
|
@@ -55,26 +56,36 @@ citation you can open: `path::symbol` into Python code, `path:line` elsewhere.
|
|
|
55
56
|
belong on a page: delete it rather than soften it.
|
|
56
57
|
- Code in a Python file is cited by symbol: `path::name` for a top-level def,
|
|
57
58
|
class or assignment, `path::Class.method` or `path::outer.inner` for a nested
|
|
58
|
-
one (`hooks/tezgah_gate.py::decision`).
|
|
59
|
+
one (`hooks/tezgah_gate.py::decision`). A page cites a JavaScript or
|
|
60
|
+
TypeScript file's top-level `const`, `let`, `function` or `class` the same way
|
|
61
|
+
(`hosts/opencode/plugins/tezgah.js::noteBegan`). It carries no line number, so an edit
|
|
59
62
|
that moves code above or inside the symbol moves no citation. The sentence says
|
|
60
63
|
which part of the symbol it means. Everything else stays `path:line`: a
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
JSON, YAML, shell or Markdown target, code outside every top-level symbol, and a
|
|
65
|
+
range across several symbols. Never name a symbol
|
|
63
66
|
that does not contain what the sentence cites.
|
|
64
67
|
- `bin/tezgah-docs --citations` checks both forms. It reads every page under `docs/`
|
|
65
68
|
and the comments and docstrings of the Python code. A string literal, such as a
|
|
66
69
|
fixture or a captured output, is data and is not read. A symbol citation is
|
|
67
|
-
resolved against the AST of the file it names
|
|
70
|
+
resolved against the AST of the Python file it names, or the top-level
|
|
71
|
+
declarations of a JavaScript or TypeScript one. It fails when that file defines
|
|
68
72
|
no such name. A name without a dot may also name the one method of that name
|
|
69
73
|
in a class. That is how a test pin names its test. A def local to a function
|
|
70
74
|
never stands in for it. A `path:line` with a symbol named
|
|
71
75
|
before it, or right after it in parentheses, must point inside that symbol's
|
|
72
|
-
body. A bare file name means the one code file of that name
|
|
76
|
+
body. A bare file name means the one code file of that name, else the file of
|
|
77
|
+
that name at the repository root. A path under the private `.tezgah/` is never
|
|
78
|
+
judged, because a CI checkout has no copy of it. A comma list reads every range in it. A bare
|
|
79
|
+
range, `(8-9)`, `(14,34-38)` or an unquoted :8-9, is read against the path cited
|
|
80
|
+
before it in the same sentence or table row. One that starts at 0 or runs
|
|
81
|
+
backwards is a value, not lines. The audit flags a cited range past the end of
|
|
82
|
+
its file, and one over blank lines only, with or without a symbol beside it. In a shell script, a name beside the range must be on its
|
|
83
|
+
lines. The suite also
|
|
73
84
|
checks that a cited file exists and that a cited line is inside it
|
|
74
85
|
(`tests/test_docs.py`). Whether a line still *shows the thing the sentence names*
|
|
75
86
|
is a judgement, not a regex. So a `path:line` with no symbol beside it is left
|
|
76
|
-
unjudged rather than guessed at. So is
|
|
77
|
-
|
|
87
|
+
unjudged rather than guessed at. So is an unquoted `path:N` the pattern cannot
|
|
88
|
+
read, but it is counted.
|
|
78
89
|
On this tree, 2026-10-06: 996 judged (995 of them symbol citations), 577 not
|
|
79
90
|
judgeable, 85 of those unreadable.
|
|
80
91
|
The unjudged count is a ratchet. `docs/citations-baseline.json` holds each file's
|
package/docs/architecture.md
CHANGED
|
@@ -222,8 +222,8 @@ So tezgah never creates a `.tezgah`, `.cursor`, `.opencode` or graph index insid
|
|
|
222
222
|
line armed (`hooks/tezgah_guard.py::safe`, `hooks/projects-pretooluse.py::main`).
|
|
223
223
|
A host that cannot call the core in process gets the same rule in its own
|
|
224
224
|
language: opencode's plugin runs every awaited core CLI through one `collect`
|
|
225
|
-
helper with a 10 s deadline (`SPAWN_DEADLINE_MS`,
|
|
226
|
-
`hosts/opencode/plugins/tezgah.js
|
|
225
|
+
helper with a 10 s deadline (`hosts/opencode/plugins/tezgah.js::SPAWN_DEADLINE_MS`,
|
|
226
|
+
`hosts/opencode/plugins/tezgah.js::collect`). Both fail open, because a core
|
|
227
227
|
that has crashed has refused nothing.
|
|
228
228
|
- **The root boundary.** Every hook is inert outside a configured root:
|
|
229
229
|
a linked `git worktree` counts as inside when its main checkout is, read from
|
|
@@ -6,43 +6,37 @@
|
|
|
6
6
|
"unjudged": 1
|
|
7
7
|
},
|
|
8
8
|
"docs/architecture.md": {
|
|
9
|
-
"unjudged":
|
|
9
|
+
"unjudged": 23
|
|
10
10
|
},
|
|
11
11
|
"docs/contract.md": {
|
|
12
|
-
"unjudged":
|
|
12
|
+
"unjudged": 3
|
|
13
13
|
},
|
|
14
14
|
"docs/environment.md": {
|
|
15
|
-
"unjudged":
|
|
15
|
+
"unjudged": 4
|
|
16
16
|
},
|
|
17
17
|
"docs/evidence.md": {
|
|
18
|
-
"unjudged":
|
|
19
|
-
},
|
|
20
|
-
"docs/feature-audit.md": {
|
|
21
|
-
"unjudged": 2
|
|
18
|
+
"unjudged": 14
|
|
22
19
|
},
|
|
23
20
|
"docs/gate.md": {
|
|
24
|
-
"unjudged":
|
|
21
|
+
"unjudged": 10
|
|
25
22
|
},
|
|
26
23
|
"docs/glossary.md": {
|
|
27
|
-
"unjudged":
|
|
24
|
+
"unjudged": 9
|
|
28
25
|
},
|
|
29
26
|
"docs/hosts.md": {
|
|
30
|
-
"unjudged":
|
|
27
|
+
"unjudged": 15
|
|
31
28
|
},
|
|
32
29
|
"docs/layers.md": {
|
|
33
|
-
"unjudged":
|
|
30
|
+
"unjudged": 7
|
|
34
31
|
},
|
|
35
32
|
"docs/operations.md": {
|
|
36
|
-
"unjudged":
|
|
33
|
+
"unjudged": 4
|
|
37
34
|
},
|
|
38
35
|
"docs/skills.md": {
|
|
39
|
-
"unjudged":
|
|
40
|
-
},
|
|
41
|
-
"docs/status-line.md": {
|
|
42
|
-
"unjudged": 9
|
|
36
|
+
"unjudged": 6
|
|
43
37
|
},
|
|
44
38
|
"docs/testing.md": {
|
|
45
|
-
"unjudged":
|
|
39
|
+
"unjudged": 21
|
|
46
40
|
},
|
|
47
41
|
"hooks/tezgah_gate.py": {
|
|
48
42
|
"unjudged": 1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"CHANGELOG.md": {
|
|
3
|
-
"long_sentences":
|
|
3
|
+
"long_sentences": 1,
|
|
4
4
|
"passive": 2,
|
|
5
5
|
"replace_words": 0,
|
|
6
6
|
"semicolons": 0
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"docs/environment.md": {
|
|
27
27
|
"long_sentences": 3,
|
|
28
|
-
"passive":
|
|
28
|
+
"passive": 1,
|
|
29
29
|
"replace_words": 0,
|
|
30
|
-
"semicolons":
|
|
30
|
+
"semicolons": 2
|
|
31
31
|
},
|
|
32
32
|
"docs/evidence.md": {
|
|
33
|
-
"long_sentences":
|
|
33
|
+
"long_sentences": 112,
|
|
34
34
|
"passive": 55,
|
|
35
35
|
"replace_words": 1,
|
|
36
36
|
"semicolons": 39
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"semicolons": 14
|
|
55
55
|
},
|
|
56
56
|
"docs/hosts.md": {
|
|
57
|
-
"long_sentences":
|
|
57
|
+
"long_sentences": 38,
|
|
58
58
|
"passive": 19,
|
|
59
59
|
"replace_words": 0,
|
|
60
60
|
"semicolons": 18
|
|
@@ -83,6 +83,12 @@
|
|
|
83
83
|
"replace_words": 3,
|
|
84
84
|
"semicolons": 42
|
|
85
85
|
},
|
|
86
|
+
"docs/orca.md": {
|
|
87
|
+
"long_sentences": 0,
|
|
88
|
+
"passive": 0,
|
|
89
|
+
"replace_words": 0,
|
|
90
|
+
"semicolons": 0
|
|
91
|
+
},
|
|
86
92
|
"docs/research.md": {
|
|
87
93
|
"long_sentences": 105,
|
|
88
94
|
"passive": 59,
|
|
@@ -91,7 +97,7 @@
|
|
|
91
97
|
},
|
|
92
98
|
"docs/skills.md": {
|
|
93
99
|
"long_sentences": 35,
|
|
94
|
-
"passive":
|
|
100
|
+
"passive": 17,
|
|
95
101
|
"replace_words": 0,
|
|
96
102
|
"semicolons": 16
|
|
97
103
|
},
|
package/docs/contract.md
CHANGED
|
@@ -88,7 +88,7 @@ to an adhd ask still opened on a diagnosis. Measured on this
|
|
|
88
88
|
machine: 6-15 ms warm, and 1.36 s for the one cold rebuild over 7 502 sections.
|
|
89
89
|
The line costs 187-201 bytes on omp, 264-287 on other hosts and 450-483 on
|
|
90
90
|
Claude, plus 231 for the `i-have-adhd` clause. It is not a judgement, so
|
|
91
|
-
`judge-off` leaves it on, and `reminder-off`
|
|
91
|
+
`judge-off` leaves it on, and `reminder-off` leaves it on too: that switch drops only the reminder line.
|
|
92
92
|
The always-on core also
|
|
93
93
|
sends every session to the same search by hand. Run `tezgah-skill <words>`
|
|
94
94
|
before working a topic a skill covers, then read only the returned range.
|
|
@@ -208,27 +208,31 @@ default, measured on two research lines with a written flip
|
|
|
208
208
|
one also gets an OCR review spec: OCR's file selection, its rule groups and a
|
|
209
209
|
refuter pass. The spec is input to the review, never a verdict
|
|
210
210
|
([operations](operations.md#opt-in-ocr-review-spec-ocr),
|
|
211
|
-
`bin/tezgah-task::print_ocr_spec`).
|
|
211
|
+
`bin/tezgah-task::print_ocr_spec`). A verdict comes only from a fresh
|
|
212
|
+
reviewer. A host that cannot start one says so and asks the owner. The author
|
|
213
|
+
contests a confirmed finding only with a file:line the reviewer could read. It
|
|
214
|
+
never lowers a severity (`hooks/tezgah_policy.py::EXEC`).
|
|
212
215
|
|
|
213
216
|
## Composition order of the always-on core
|
|
214
217
|
|
|
215
218
|
Paragraphs are concatenated in the order they appear in `CORE` and identified by
|
|
216
219
|
the bold label each starts with (`CORE_RULES`, `hooks/tezgah_context.py::CORE_RULES`).
|
|
217
|
-
That order,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
`**
|
|
221
|
-
`**
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
`**
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
`**
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
220
|
+
That order, read from `hooks/tezgah_policy.py::CORE` (the labels are the
|
|
221
|
+
anchors, so an edit above one moves nothing here):
|
|
222
|
+
`**{REPLY_LANG}, BLUF.**`, `**Ponytail (minimal code).**`, `**Output shape:
|
|
223
|
+
ADHD-friendly.**`, `**Deliver the whole ask; never the shortcut.**`,
|
|
224
|
+
`**Integrity: evidence, or a named blocker.**`, `**Loop discipline.**`,
|
|
225
|
+
`**Spec before building.**` *(conditional)*, `**Lessons ledger: stop
|
|
226
|
+
repeating mistakes.**`, `**Code discovery: graph first.**`
|
|
227
|
+
*(conditional)*, `**Consult before irreversible.**` *(conditional)*,
|
|
228
|
+
`**Research: route it to OpenResearch.**` *(conditional)*, `**Product
|
|
229
|
+
analysis: five axes, one evidence class per finding.**` *(conditional)*,
|
|
230
|
+
`**Design: UI work reads the design skills.**` *(conditional)*,
|
|
231
|
+
`**No AI attribution, ever, on any host.**`, `**Identifiers and messages
|
|
232
|
+
stay English.**`, `**Session scope: the user's repo, not tezgah.**`,
|
|
233
|
+
``**Workspace: `.tezgah/` only.**``, `**Parallel by default: fan out
|
|
234
|
+
independent items.**` *(conditional)*,
|
|
235
|
+
`**Kill switches:**`. The first label renders as `**Turkish, BLUF.**` under
|
|
232
236
|
`language` `tr`.
|
|
233
237
|
|
|
234
238
|
`always_on_core()` (`hooks/tezgah_context.py::always_on_core`) drops the seven
|
|
@@ -256,7 +260,7 @@ applied, and it also returns the names of the switches that fired.
|
|
|
256
260
|
- **Ponytail (minimal code).** Take the laziest rung that holds (YAGNI → reuse → stdlib → platform → installed dependency → one line), never simplify away validation, error handling or security. A non-default level rides the reminder (`hooks/tezgah_context.py::_pony_level_line`).
|
|
257
261
|
- **Output shape: ADHD-friendly.** The action or answer is the first line, multi-step work is a numbered list whose position is restated, an estimate is in concrete units. Two upstream rules were rewritten rather than imported verbatim because they collided with rules already in force: the state restatement points at the todo list instead of duplicating it, and a time estimate can no longer be read as a measurement.
|
|
258
262
|
- **Deliver the whole ask; never the shortcut.** The request is a floor: no cheaper stand-in, no silent scope cut, no token gesture reported as done.
|
|
259
|
-
- **Integrity: evidence, or a named blocker.** A done/tested claim holds only if the check ran in this session and its output was seen; "unverified" (tr: "doğrulanmadı") follows a check that ran and failed; leftover work is done, or stays as one of four blockers (DECISION, ACCESS, IRREVERSIBLE, ENV; tr: KARAR, YETKİ, GERİ ALINAMAZ, ORTAM) with its evidence. The mechanical half is enforced by [gate.md](gate.md), the residual half by the Stop rule's `residual work` class ([evidence.md](evidence.md)). Its **Ask policy** says what is asked at all. Work and process are never asked. An outward step runs on a grant. A never-default step waits for an answer. Every other question goes in one batch with a recommended default. The Stop rule's `needless ask` class refuses a reply that ends on a question the agent can decide, and the gate warns on an ask-tool question with no default ([gate.md](gate.md#ask-an-ask-tool-question-with-no-recommended-option)).
|
|
263
|
+
- **Integrity: evidence, or a named blocker.** A done/tested claim holds only if the check ran in this session and its output was seen; "unverified" (tr: "doğrulanmadı") follows a check that ran and failed; leftover work is done, or stays as one of four blockers (DECISION, ACCESS, IRREVERSIBLE, ENV; tr: KARAR, YETKİ, GERİ ALINAMAZ, ORTAM) with its evidence. The mechanical half is enforced by [gate.md](gate.md), the residual half by the Stop rule's `residual work` class ([evidence.md](evidence.md)). Its **Ask policy** says what is asked at all. Work and process are never asked. An outward step runs on a grant. A never-default step waits for an answer. Plan 136 added three to that list after a session ran another session's research line under a hidden dir and wrote a `chosen:` variant the owner never picked: choosing a variant or option a research, analysis or review recommends; a way around a tezgah refusal (another folder, a hidden dir, a hatch the owner did not grant); deciding about another session's work (its line, plan or branch). A taste or intent fork still goes in the batch with a default taken this turn; these do not. A subagent's question of that kind is relayed to the user, never answered by the orchestrator or escalated to a stronger model. Every other question goes in one batch with a recommended default. The Stop rule's `needless ask` class refuses a reply that ends on a question the agent can decide, and passes one that asks the owner to pick a variant or to decide one of those steps (`hooks/tezgah_integrity.py::OWNER_CHOICE`); the gate warns on an ask-tool question with no default ([gate.md](gate.md#ask-an-ask-tool-question-with-no-recommended-option)).
|
|
260
264
|
- **Loop discipline.** Never repeat an identical failing command; three attempts is the ceiling, then report what is still unknown.
|
|
261
265
|
- **Lessons ledger: stop repeating mistakes.** `.tezgah/lessons.md` lines are standing constraints; the recent ones are injected at session start, and up to three older ones a prompt shares words with ride that turn, each once per session when the host sends a session id (a compaction resets that, because the compacted context no longer holds them; without an id every matching turn carries them). Write a line rule first, `<rule> - <incident>` (`LESSON_SEPARATOR`, `hooks/tezgah_context.py::LESSON_SEPARATOR`). The session block counts the shown lines that do not open with their rule. A line ending `|| enforced_by: <rule|test>` leaves both blocks while that gate rule or test is on (`hooks/tezgah_lessons.py::lines`). That one reader serves the context, the gate and the CLI. It cuts that clause, a `|| check: ...` clause and an `@<sha> <path>` stamp off each line (`hooks/tezgah_lessons.py::parse`). None of them changes the key, the per-turn digest, the cut or the ranking. The gate records a line written after untrusted text in the same turn as a `lesson_tainted` row ([evidence.md](evidence.md)). That line still rides both blocks, behind a per-line data label (`hooks/tezgah_context.py::LESSON_TAINTED`). ADR 010 makes it a row, never a refusal. `bin/tezgah-lessons` proposes rewrites, merges and retirements, and never writes the file.
|
|
262
266
|
- **No AI attribution, ever, on any host.** Nothing persisted or published may name a model, vendor or "AI" as author, co-author, generator or helper; one already in pushed history is reported.
|
|
@@ -416,9 +420,12 @@ with no transcript pays nothing.
|
|
|
416
420
|
## How a rule is disarmed
|
|
417
421
|
|
|
418
422
|
A kill switch removes the rule's text, not just a status mark
|
|
419
|
-
(`hooks/tezgah_context.py::core_split`). `off()` checks
|
|
420
|
-
legacy `~/.claude` (`hooks/tezgah_paths.py::OFF_DIRS`, `hooks/tezgah_paths.py::off`)
|
|
421
|
-
|
|
423
|
+
(`hooks/tezgah_context.py::core_split`). `off()` checks tezgah's config dir and
|
|
424
|
+
the legacy `~/.claude` (`hooks/tezgah_paths.py::OFF_DIRS`, `hooks/tezgah_paths.py::off`).
|
|
425
|
+
The config dir is `~/.config/tezgah`, or `$XDG_CONFIG_HOME/tezgah` when
|
|
426
|
+
`XDG_CONFIG_HOME` is set (`hooks/tezgah_paths.py::CONFIG_DIR`). The core and the
|
|
427
|
+
per-turn reminder name the same dir (`hooks/tezgah_policy.py::SWITCH_DIR`). The
|
|
428
|
+
drop itself happens in `core_split()`.
|
|
422
429
|
|
|
423
430
|
The session latches a switch (`hooks/tezgah_paths.py::latch`). A hook that knows
|
|
424
431
|
its session binds the session's ledger first
|
|
@@ -435,8 +442,8 @@ three cases:
|
|
|
435
442
|
(`hooks/tezgah_integrity.py::_in_flight`). A host hands its prompt hook a
|
|
436
443
|
prompt between calls. An unanswered call older than ten minutes no longer
|
|
437
444
|
counts, since a host writes no answer for a call the user interrupted.
|
|
438
|
-
- it is the stand-down `tezgah-setup --uninstall
|
|
439
|
-
`pretooluse-off` (`hooks/tezgah_paths.py::STAND_DOWN`).
|
|
445
|
+
- it is the stand-down a full `tezgah-setup --uninstall` (one covering every
|
|
446
|
+
armed host) writes into `pretooluse-off` (`hooks/tezgah_paths.py::STAND_DOWN`).
|
|
440
447
|
- it appeared within the first row's second, because the row's `ts` holds whole
|
|
441
448
|
seconds.
|
|
442
449
|
|
|
@@ -445,6 +452,18 @@ a hook with no session id bind nothing and read the file alone, as before. The
|
|
|
445
452
|
opencode plugin answers the same way (`off(name, sessionID)`). A prompt match is
|
|
446
453
|
a keyword match, not intent: "don't touch `verify-off`" names the switch too.
|
|
447
454
|
|
|
455
|
+
A subagent session is no next session. When the payload names the session that
|
|
456
|
+
spawned it (`parent`), the hook binds the parent's ledger too
|
|
457
|
+
(`hooks/tezgah_integrity.py::bind_session`). The subagent then latches on the
|
|
458
|
+
earlier of its own and its parent's first row. A switch the parent made
|
|
459
|
+
mid-session does not count in a subagent it spawns afterwards. A switch the
|
|
460
|
+
user's prompt to the parent named counts there too. The subagent's own prompt
|
|
461
|
+
is its parent's brief and authorizes nothing. The omp and Amp bridges send
|
|
462
|
+
`parent` on a subagent's events. The opencode plugin keeps the parent opencode
|
|
463
|
+
names on the child's `session.created` (`hosts/opencode/plugins/tezgah.js::PARENTS`)
|
|
464
|
+
and hands it to the core it asks (`bin/tezgah-gate`). The parent always comes
|
|
465
|
+
from the host, never from a ledger row an agent could write.
|
|
466
|
+
|
|
448
467
|
| Switch file | Rule it removes | Where the drop is implemented |
|
|
449
468
|
|---|---|---|
|
|
450
469
|
| `exec-mode.off` | `**{REPLY_LANG}, BLUF.**` | `hooks/tezgah_context.py::switches` |
|
|
@@ -454,27 +473,43 @@ a keyword match, not intent: "don't touch `verify-off`" names the switch too.
|
|
|
454
473
|
| `design-off` | `**Design: UI work reads the design skills.**` | `hooks/tezgah_context.py::switches` |
|
|
455
474
|
| `verify-off` | `**Integrity: evidence…**`, and the per-turn evidence-scope line with it | `hooks/tezgah_context.py::switches`, `hooks/tezgah_context.py::context_for` |
|
|
456
475
|
| `consult-off` | `**Consult before irreversible.**` | `hooks/tezgah_context.py::switches` |
|
|
457
|
-
| `research-off` | `**Research: route it to OpenResearch.**` | `hooks/tezgah_context.py::switches` |
|
|
476
|
+
| `research-off` | `**Research: route it to OpenResearch.**` and `**Product analysis: five axes, one evidence class per finding.**` | `hooks/tezgah_context.py::switches` |
|
|
458
477
|
| `orchestrate-off` | `**Parallel by default: fan out independent items.**`, and the orchestration section of the on-demand skill | `hooks/tezgah_context.py::switches` drops the paragraph, `hooks/tezgah_context.py::context_for` injects "Orchestration is off" and drops the specialists line, and the skill-ignore note is `hooks/tezgah_context.py::context_for` |
|
|
459
|
-
| `reminder-off` | the per-turn reminder | `hooks/tezgah_context.py::context_for`
|
|
478
|
+
| `reminder-off` | the per-turn reminder line alone; the armed paragraphs, the gate notice, the off-note and the other per-turn parts stay | `hooks/tezgah_context.py::context_for` leaves the `reminder` part out |
|
|
460
479
|
| `judge-off` | the judgement seam: the snapshot triage, the docs page fallback and the skill hint | `hooks/tezgah_judge.py::available` — `available()` is asked before any call, so an armed switch makes no request at all |
|
|
461
480
|
| `triage-off` | the snapshot triage alone (`bin/tezgah-triage`), leaving the docs fallback and the skill hint armed | `bin/tezgah-triage::off_reason` — `off_reason()` answers this switch before the seam's, so the analyze-app loop reads the tree instead of paying for a judgement |
|
|
462
481
|
| `docs-judge-off` | the docs page fallback alone (`bin/tezgah-docs`), leaving the triage and the skill hint armed | `bin/tezgah-docs::off` — `off()` answers this switch first, so a query the index cannot place is ranked by shared words instead (`ranked`), and exits 1 only when no page shares one |
|
|
463
482
|
| `lang-off` | `**Identifiers and messages stay English.**` | `hooks/tezgah_context.py::switches` drops the paragraph; the gate's own check reads the same switch (`hooks/tezgah_gate.py::decision`) |
|
|
483
|
+
| `workspace-off` | ``**Workspace: `.tezgah/` only.**``, and the gate's refusal of a root `plans/`, `research/` or `analysis/` write | `hooks/tezgah_context.py::switches` drops the paragraph, and the gate reads the same switch (`hooks/tezgah_gate.py::DENY_RULES`, [gate.md](gate.md#workspace-tezgah-state-outside-tezgah)) |
|
|
484
|
+
| `task-off` | the gate's task rule: the active plan's phase, its path allowlist, the plan record and a shell write | `hooks/tezgah_gate.py::decision` ([gate.md](gate.md#task-the-active-plans-phase-and-path-allowlist)) |
|
|
464
485
|
| `pretooluse-off` | the gate's denials, not a rule | [gate.md](gate.md) |
|
|
465
486
|
| `.no-ponytail` | `**Ponytail (minimal code).**` | `hooks/tezgah_context.py::switches` |
|
|
466
487
|
| `.no-adhd` | `**Output shape: ADHD-friendly.**` | `hooks/tezgah_context.py::switches` |
|
|
467
488
|
| `.no-graph` | `**Code discovery: graph first.**` | `hooks/tezgah_context.py::switches` |
|
|
468
489
|
| `.no-lessons` | `**Lessons ledger: stop repeating mistakes.**` | `hooks/tezgah_context.py::switches`, and neither the session's lessons block (`hooks/tezgah_context.py::lessons`) nor the per-turn one (`relevant_lessons`) is injected |
|
|
490
|
+
| `.no-plan-gate` | the gate's plan rule in that repository: a turn's third product file on a branch no plan binds | `hooks/tezgah_gate.py::plan_reason` ([gate.md](gate.md#plan-a-turns-third-product-file-on-a-branch-no-plan-binds)) |
|
|
491
|
+
| `.no-taste` | the opt-in taste capture in that repository | `hooks/tezgah_taste.py::MARK` ([operations](operations.md#opt-in-taste-capture-learn-apply)) |
|
|
469
492
|
|
|
470
|
-
The last
|
|
493
|
+
The last six are per-repo [marks](glossary.md#per-repo-mark), read by
|
|
471
494
|
`repo_marks()`, walking up to the enclosing [root](glossary.md#root)
|
|
472
495
|
(`hooks/tezgah_context.py::repo_marks`). Every switch that fired is named back to the
|
|
473
|
-
session at start (`hooks/tezgah_context.py::context_for`)
|
|
496
|
+
session at start (`hooks/tezgah_context.py::context_for`), with the instruction to
|
|
474
497
|
ignore the matching section in `tezgah-contract` — that skill is loaded
|
|
475
|
-
separately and would otherwise re-arm the rule
|
|
498
|
+
separately and would otherwise re-arm the rule — and in Claude's static `tezgah`
|
|
499
|
+
output style, which no switch re-renders. The per-turn note names the switches
|
|
500
|
+
again and the output style alone. Both notes are the budget's `offnote` block.
|
|
501
|
+
A turn over its byte budget drops it like the other droppable blocks
|
|
502
|
+
([the budget](#when-the-injected-text-grows-too-large)), so "per turn" holds
|
|
503
|
+
while the turn fits. `tezgah-adhd off` writes the same
|
|
476
504
|
channel as the file (`bin/tezgah-adhd::SWITCH`); the ponytail *level* is not a switch.
|
|
477
505
|
|
|
506
|
+
`off()` and `armed()` also read five feature switches, not rule switches.
|
|
507
|
+
ADR 007 leaves them unclassified (`hooks/tezgah_paths.py::SWITCHES`): `agents-off`, `update-check-off`, `slices-off`, `taste-on`, `skill-suggest-on`.
|
|
508
|
+
|
|
509
|
+
One environment variable disarms a refusal too: `TEZGAH_REPO_RULE=0` skips a
|
|
510
|
+
repository's own `.tezgah/gate.py` (`hooks/tezgah_gate.py::REPO_RULE_VALVE`;
|
|
511
|
+
[gate.md](gate.md#a-repositorys-own-rule), [environment](environment.md)).
|
|
512
|
+
|
|
478
513
|
One more file in a repository's own tree is not a rule switch either. A
|
|
479
514
|
`tezgah.owner` at the repository's top says who owns the workspace, and its two
|
|
480
515
|
settings turn seams off rather than dropping a paragraph. `tasks: off` stops the
|
|
@@ -542,8 +577,8 @@ brief carries the same caller-list floor (`hooks/tezgah_agents.py`), and
|
|
|
542
577
|
|
|
543
578
|
## When the injected text grows too large
|
|
544
579
|
|
|
545
|
-
Each event has a byte budget: `session_start` and `post_compact`
|
|
546
|
-
`user_prompt` 7000, `subagent_start`
|
|
580
|
+
Each event has a byte budget: `session_start` and `post_compact` 16200,
|
|
581
|
+
`user_prompt` 7000, `subagent_start` 6100, anything else 13000
|
|
547
582
|
(`hooks/tezgah_context.py::CONTEXT_BUDGET`). The rationale and the measured
|
|
548
583
|
sizes sit beside it. In an empty fixture repo, `session_start` with the core
|
|
549
584
|
builds 9842 B before the ponytail and ADHD rules went inline and 10884 B after
|
|
@@ -551,8 +586,9 @@ builds 9842 B before the ponytail and ADHD rules went inline and 10884 B after
|
|
|
551
586
|
113 B. The healthy fixture with a lesson and a plan then built 12059 B. At the
|
|
552
587
|
old 12000 B budget it lost its lessons and sibling checkouts to pay for core
|
|
553
588
|
rules, so the budget moved to 13000 B. The residual rule (plan 080) added
|
|
554
|
-
1473 B to the core and 151 B to the reminder, so the always-on band
|
|
555
|
-
11972 B
|
|
589
|
+
1473 B to the core and 151 B to the reminder, so the always-on band reached
|
|
590
|
+
11972 B. `tests/test_setup.py::VersionPrefixIsNotContract` pins today's band.
|
|
591
|
+
At 13000 B the healthy fixture gave up its
|
|
556
592
|
lessons, plans and steer blocks. At 6000 B the busiest prompt turn gave up its
|
|
557
593
|
active-task line. The session budgets moved to 14500 B, the prompt budget to 6500 B.
|
|
558
594
|
The Ask policy (plan 086, S3) added 913 B to the core. At 14500 B the healthy
|
|
@@ -560,7 +596,10 @@ fixture then gave up a lessons, plans or knowledge block. The session budgets mo
|
|
|
560
596
|
The subagent brief stays the same size.
|
|
561
597
|
A research ask arms the Research and Product paragraphs: 6239 B on Claude
|
|
562
598
|
(S4Remeasure p08). At 6500 B the skill hint naming the research skill was the
|
|
563
|
-
block given up. The prompt budget moved to 7000 B (2026-10-22).
|
|
599
|
+
block given up. The prompt budget moved to 7000 B (2026-10-22). A longer
|
|
600
|
+
subagent pointer (plan 136) moved `subagent_start` to 6100 B. The output-shape
|
|
601
|
+
paragraph's plan-mode clause (plan 142, +168 B) put the worktree fixture's
|
|
602
|
+
`session_start` over 16000 B again. The session budgets moved to 16200 B.
|
|
564
603
|
`SkillRulesInForceAtSessionStart` (`tests/test_context.py`) pins the rules
|
|
565
604
|
themselves, not the size. A
|
|
566
605
|
`user_prompt` that arms all seven conditional rules
|
|
@@ -575,7 +614,17 @@ table first, then the Orca line, the tooling-availability lines and the live gra
|
|
|
575
614
|
glance, then the index line and the resume state (it outlives those because it
|
|
576
615
|
is the only one that says what this session was doing, and it still yields to a
|
|
577
616
|
rule), then the evidence-scope warning, the skill hint, the task phase, the
|
|
578
|
-
delta, and the skill pointer last (`hooks/tezgah_context.py::DROP_ORDER`).
|
|
617
|
+
delta, and the skill pointer last (`hooks/tezgah_context.py::DROP_ORDER`). The
|
|
618
|
+
whole tuple, in this order:
|
|
619
|
+
|
|
620
|
+
```
|
|
621
|
+
knowledge worktrees lessons lessons_turn taste plans subagents steer orca
|
|
622
|
+
consult research research_broken graph offnote orchestrate index resume
|
|
623
|
+
slices context scratch skill task delta pointer
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
`offnote` is the note naming the kill switches that fired, so a turn over budget
|
|
627
|
+
can lose it before the index line.
|
|
579
628
|
The skill hint moved from near the front to after `lessons_turn` and `index`.
|
|
580
629
|
It names the skill this ask needs, and no other block can work that out.
|
|
581
630
|
It was the first block given up in 32 logged live drops (plan 126). Any key absent from that tuple is
|