strom-research 1.13.2-beta.5 → 1.13.2-beta.6

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 (51) hide show
  1. package/assets/lang/cs.json +63 -1
  2. package/assets/lang/de.json +63 -1
  3. package/assets/method/core.md +13 -3
  4. package/assets/method/reading.md +12 -11
  5. package/assets/plugins/gates/README.md +28 -1
  6. package/assets/plugins/gates/claude-usage/gate.json +1 -1
  7. package/assets/plugins/gates/claude-usage/gate.ts +100 -22
  8. package/dist/agents/files.js +5 -3
  9. package/dist/agents/profiles.js +12 -8
  10. package/dist/agents/scanreader.js +16 -9
  11. package/dist/brief/brief.js +226 -64
  12. package/dist/brief/sheet.js +2 -0
  13. package/dist/cli/help.js +1 -1
  14. package/dist/cli/main.js +4 -3
  15. package/dist/cli/menu-settings.js +19 -1
  16. package/dist/cli/menu.js +7 -0
  17. package/dist/cli/ui.js +49 -1
  18. package/dist/commands/analysis.js +21 -11
  19. package/dist/commands/calibrate.js +203 -0
  20. package/dist/commands/connectors.js +69 -6
  21. package/dist/commands/gates.js +8 -4
  22. package/dist/commands/guide.js +5 -3
  23. package/dist/commands/index.js +1 -0
  24. package/dist/commands/media.js +18 -12
  25. package/dist/commands/meta.js +8 -2
  26. package/dist/commands/read.js +9 -4
  27. package/dist/commands/readers.js +11 -6
  28. package/dist/commands/session.js +46 -8
  29. package/dist/commands/setup.js +23 -5
  30. package/dist/commands/tasks.js +39 -7
  31. package/dist/core/assets.js +11 -4
  32. package/dist/core/changelog.js +105 -14
  33. package/dist/core/clock.js +37 -2
  34. package/dist/core/config.js +5 -1
  35. package/dist/core/connector.js +49 -0
  36. package/dist/core/edge.js +8 -2
  37. package/dist/core/evidence.js +7 -0
  38. package/dist/core/gate.js +42 -7
  39. package/dist/core/hypolinks.js +121 -6
  40. package/dist/core/live.js +22 -7
  41. package/dist/core/mediaindex.js +24 -2
  42. package/dist/core/phrases.js +15 -0
  43. package/dist/core/session.js +2 -2
  44. package/dist/core/tree.js +1 -1
  45. package/dist/core/viewsample.js +366 -0
  46. package/dist/core/viewsizes.js +78 -0
  47. package/dist/gedcom/export.js +24 -4
  48. package/dist/gedcom/validate.js +7 -4
  49. package/dist/runners/claude.js +46 -5
  50. package/dist/runners/runner.js +9 -0
  51. package/package.json +1 -1
@@ -137,6 +137,37 @@
137
137
  "ui.chat.app.model.chosen": "V aplikaci {app} zvolit pro výzkum model {model} (zvolený v nastavení).",
138
138
  "ui.settings.model": "Model výzkumu ({agent}): {model}",
139
139
  "ui.settings.model.own": "vlastní model agenta",
140
+ "ui.views.title": "Ladění čtení snímků · {agent}: snímků {n}, knih {books}, velikosti {sizes} px",
141
+ "ui.views.find": "Nalezení zápisu na celém snímku:",
142
+ "ui.views.find.row": " {size} px na místě {located} z {n} · na snímku bez něj {wrong} z {neg} · {cost}",
143
+ "ui.views.read": "Přečtení zápisu z poloviny nebo strany:",
144
+ "ui.views.read.row": " {size} px přečteno {keys} z {total} · nejistých míst {unsure} · {cost}",
145
+ "ui.views.rule": "Menší velikost se uloží jen při jasném výsledku: každý zápis nalezený na místě jako u největší velikosti a žádný navíc na snímku bez něj; přečteno celkem aspoň tolik, žádný zápis o víc než jeden údaj méně, nejistých míst ne víc.",
146
+ "ui.views.stored": "Uloženo pro {agent} ({date}): hledání {find} px · čtení {read} px — řídí se tím strom media view a strom read; zpět na výchozí: strom media calibrate --reset",
147
+ "ui.views.kept": "Bez jasného výsledku: nic se neuložilo, velikosti zůstávají, jak byly.",
148
+ "ui.views.unclear.find": "Hledání: bez jasného výsledku — zůstává výchozí ({size} px).",
149
+ "ui.views.unclear.read": "Čtení: bez jasného výsledku — zůstává výchozí ({size} px).",
150
+ "ui.views.failed": "Čtení, která nedoběhla: {failed} — nic se neuložilo, velikosti zůstávají, jak byly.",
151
+ "ui.views.few": "Na vyladění čtení snímků je málo snímků se známou pravdou: {have} z potřebných {need}. Takový snímek je sken záznamu, který cituje doložený údaj, s jeho slovy (přepisem) a už na tomto počítači; chybí ještě {more} — vzniknou běžnou prací agenta, zkusit znovu po několika sezeních. Do té doby platí výchozí velikosti.",
152
+ "ui.views.ask": "Vyladit čtení snímků pro {agent}: {readers} placených čtení {n} snímků tohoto výzkumu ve velikostech {sizes} px, asi {cost} (typický odhad; ceny agenta se mohou lišit). Spustit?",
153
+ "ui.views.no": "Nic se nespustilo; velikosti zůstávají, jak byly.",
154
+ "ui.views.reset": "Vyladění pro {agent} zapomenuto: platí výchozí velikosti (hledání {find} px · čtení {read} px).",
155
+ "ui.views.reset.none": "Pro {agent} nic vyladěno není: platí výchozí velikosti (hledání {find} px · čtení {read} px).",
156
+ "ui.views.estimate": "Snímků {n}, knih {books}, {readers} čtení ve velikostech {sizes} px, asi {cost} — spouští člověk: strom media calibrate",
157
+ "ui.views.offer": "čtení snímků bylo vyladěno pro {before}, pro {now} zatím ne: strom media calibrate (spouští člověk; placená práce modelu)",
158
+ "ui.views.progress": "▶ {what} · {size} px · snímky: {n}",
159
+ "ui.views.what.find": "hledání",
160
+ "ui.views.what.read": "čtení",
161
+ "ui.views.cost.unknown": "cena neznámá",
162
+ "ui.views.spent": "Čtení stála {cost}.",
163
+ "ui.o.views": "snímky",
164
+ "ui.settings.views": "Vyladit čtení snímků ({state})",
165
+ "ui.settings.views.default": "výchozí velikosti",
166
+ "ui.settings.views.done": "vyladěno {date}",
167
+ "ui.settings.views.other": "zatím vyladěno pro jiný model",
168
+ "ui.doc.views": "čtení snímků",
169
+ "ui.doc.views.default": "výchozí velikosti: hledání {find} px · čtení {read} px",
170
+ "ui.doc.views.done": "vyladěno {date}: hledání {find} px · čtení {read} px",
140
171
  "ui.setup.level": "Co smí agent dělat bez ptaní?",
141
172
  "ui.setup.level.ask": "Ptát se mě na všechno mimo výzkum",
142
173
  "ui.setup.level.auto": "Pracovat samostatně – ptát se jen u riskantních kroků (doporučeno)",
@@ -662,6 +693,7 @@
662
693
  "ui.help.cmd.pack": "Zabalit výzkum do jednoho souboru ZIP, aby v něm mohl pokračovat někdo jiný",
663
694
  "ui.help.cmd.unpack": "Rozbalit rodokmen, který někdo poslal",
664
695
  "ui.help.cmd.tidy": "Uvolnit místo, které si strom drží vedle výzkumu (nejdřív ukáže, pak se zeptá)",
696
+ "ui.help.cmd.media.calibrate": "Vyladit velikost snímků pro agenta a model výzkumu na jeho vlastních doložených záznamech (placená práce modelu; cena se řekne předem)",
665
697
  "ui.help.cmd.check": "Zkontrolovat výzkum: vše v pořádku, nic změněné mimo strom",
666
698
  "ui.help.cmd.config.get": "Přečíst nastavení",
667
699
  "ui.help.cmd.config.set": "Změnit nastavení",
@@ -978,7 +1010,7 @@
978
1010
  "ui.run.which.bad": "Čísla ze seznamu, 1 až {n}: např. 2 nebo 1,4 nebo 2-5.",
979
1011
  "ui.run.limit": "Na jeden úkol má agent nejvýš {minutes} minut; pak ho strom zastaví a úkol vrátí do fronty (nastavení run.minutes).",
980
1012
  "ui.run.empty": "Fronta je prázdná – co hledat, stačí agentovi říct v rozhovoru.",
981
- "ui.run.browser": "· {name}: snímky přes prohlížeč – agent dostane nástroje prohlížeče pro {hosts}; musí běžet Chrome s rozšířením Claude",
1013
+ "ui.run.browser": "· {name}: snímky přes prohlížeč – nástroje prohlížeče pro {hosts} v sezeních, jejichž úkol je může potřebovat; musí běžet Chrome s rozšířením Claude",
982
1014
  "ui.run.browser.model": " pozor: nástroje prohlížeče potřebují model, který své kroky zkontroluje – Sonnet nebo Opus, ne {model}: strom config set model.lead sonnet",
983
1015
  "ui.run.full": "· oprávnění: plná – agent smí vše kromě toho, co oprávnění rodokmenu zakazují (zpět: strom config set agent.permissions auto)",
984
1016
  "ui.menu.working.more": "Samostatně teď pracují agenti: {n}.",
@@ -994,6 +1026,11 @@
994
1026
  "ui.run.gate.no": "ne",
995
1027
  "ui.run.gate.noanswer": "neodpověděla, jak má (strom gate test)",
996
1028
  "ui.run.stop.gate.declined": "nespuštěno — podmínka „{name}“: {reason}",
1029
+ "ui.run.gate.cap": "· {name}: nastavený strop – kontroluje se před každým sezením; žádné „přesto začít“ ho nepřekročí",
1030
+ "ui.run.stop.gate.cap": "strop podmínky „{name}“ – {reason} (pevná hranice z run.gate; „přesto začít“ ji nepřekročí)",
1031
+ "ui.run.cap.finish": "⏳ {session}: limit agenta na {used} % ({kind}) – sezení dostalo žádost zapsat, co našlo, a skončit; za stropem další sezení nezačne",
1032
+ "ui.run.limit.five_hour": "pětihodinové okno",
1033
+ "ui.run.limit.seven_day": "týden",
997
1034
  "ui.run.loop": "Nechat ho pracovat, dokud je co dělat a dovolí to podmínka „{name}“",
998
1035
  "ui.consent.gate.set": "Nechat podmínku „{name}“ rozhodovat, kdy agent pracující sám pokračuje?",
999
1036
  "ui.consent.gate.unset": "Odebrat podmínku „{name}“ — agent pracující sám se jí už nebude ptát?",
@@ -1318,6 +1355,24 @@
1318
1355
  "log.research.done": "Směr ukončen: {name}",
1319
1356
  "log.mode.archive": "Výzkum je teď archiv",
1320
1357
  "log.mode.research": "Výzkum je znovu zapnutý",
1358
+ "log.reading.loose": "Pročteno snímků: {n}",
1359
+ "log.clips": "Zápisy vyznačené na snímcích: {n} z {total}",
1360
+ "log.transcripts": "Zápisy přepsané z výřezů: {n} z {total}",
1361
+ "log.tree.create": "Výzkum založen: {name}",
1362
+ "log.repair": "Data vrácena do posledního zapečetěného stavu",
1363
+ "log.chat.saved": "Uloženo po rozhovoru s agentem",
1364
+ "log.migrate": "Data rodokmenu převedena pro novější strom",
1365
+ "log.setting": "Změněno nastavení výzkumu: {key}",
1366
+ "log.image": "{name}, obr. {image}",
1367
+ "log.media.edit": "Upravený snímek: {name}",
1368
+ "log.media.retract": "Odvolaný snímek: {name}",
1369
+ "log.input.edit": "Materiál doplněn: {name}",
1370
+ "log.input.skip": "Materiál odložen jako nepoužitelný: {name}",
1371
+ "log.input.sort": "Materiál roztříděn: {name}",
1372
+ "log.record.edit": "Upraveno: {name}",
1373
+ "ui.gate.timeout": "neodpověděla do {s} s",
1374
+ "ui.gate.signal": "ukončena signálem {signal}",
1375
+ "ui.gate.status": "skončila s kódem {status}",
1321
1376
  "ui.waiting.title": "Agent potřebuje ({n}):",
1322
1377
  "ui.waiting.do": "Co udělat: {what}",
1323
1378
  "ui.waiting.ask": "agent to řekne v rozhovoru",
@@ -1478,6 +1533,13 @@
1478
1533
  "ui.gate.asked": "před každým sezením strom run se ptá: {gate} (strom config unset run.gate: žádná)",
1479
1534
  "ui.gate.unset": "žádná se neptá: strom config set run.gate <název> (jen uživatel)",
1480
1535
  "ui.gate.folder": "složka: {folder} – složka podmínky nakopírovaná sem je nainstalovaná (rozhraní: README.md tamtéž)",
1536
+ "ui.gate.cap.week": "strop nastaven: ptá se před každým sezením každého běhu; sezení v práci je požádáno o dokončení při {pct} % týdne",
1537
+ "ui.gate.cap.window": "strop nastaven: ptá se před každým sezením každého běhu; sezení v práci je požádáno o dokončení při {pct} % pětihodinového okna",
1538
+ "ui.gate.test.go": "pokračovat",
1539
+ "ui.gate.test.wait": "počkat do {at}",
1540
+ "ui.gate.test.stop": "zastavit",
1541
+ "ui.gate.test.error": "chyba – běh by se zastavil",
1542
+ "ui.gate.test.hard": "(strop: pevné zastavení, žádné „přesto začít“)",
1481
1543
  "ui.hook.none": "žádné hooky",
1482
1544
  "ui.hook.on": "zapnuté: {hooks} (strom hook off <název>)",
1483
1545
  "ui.hook.unset": "žádný není zapnutý: strom hook on <název> (jen uživatel)",
@@ -137,6 +137,37 @@
137
137
  "ui.chat.app.model.chosen": "In {app} für die Forschung das Modell {model} wählen (das in den Einstellungen gewählte).",
138
138
  "ui.settings.model": "Modell der Forschung ({agent}): {model}",
139
139
  "ui.settings.model.own": "das eigene des Agenten",
140
+ "ui.views.title": "Abstimmung des Lesens der Scans · {agent}: {n} Bilder aus {books} Büchern, Größen {sizes} px",
141
+ "ui.views.find": "Finden eines Eintrags auf dem ganzen Bild:",
142
+ "ui.views.find.row": " {size} px an der Stelle {located} von {n} · auf einem Bild ohne ihn {wrong} von {neg} · {cost}",
143
+ "ui.views.read": "Lesen eines Eintrags aus einer Hälfte oder einer Seite:",
144
+ "ui.views.read.row": " {size} px gelesen {keys} von {total} · unsichere Stellen {unsure} · {cost}",
145
+ "ui.views.rule": "Eine kleinere Größe wird nur bei klarem Ergebnis gespeichert: jeder Eintrag an der Stelle gefunden wie bei der größten Größe und keiner mehr auf einem Bild ohne ihn; insgesamt mindestens so viel gelesen, kein Eintrag um mehr als eine Angabe weniger, nicht mehr unsichere Stellen.",
146
+ "ui.views.stored": "Gespeichert für {agent} ({date}): Suchen {find} px · Lesen {read} px — danach richten sich strom media view und strom read; zurück zu den Vorgaben: strom media calibrate --reset",
147
+ "ui.views.kept": "Kein klares Ergebnis: nichts gespeichert, die Größen bleiben, wie sie waren.",
148
+ "ui.views.unclear.find": "Suchen: kein klares Ergebnis — die Vorgabe bleibt ({size} px).",
149
+ "ui.views.unclear.read": "Lesen: kein klares Ergebnis — die Vorgabe bleibt ({size} px).",
150
+ "ui.views.failed": "Nicht beendete Lesungen: {failed} — nichts gespeichert, die Größen bleiben, wie sie waren.",
151
+ "ui.views.few": "Zu wenige Bilder mit bekannter Wahrheit, um das Lesen der Scans abzustimmen: {have} von {need} nötigen. Ein solches Bild ist der Scan eines Eintrags, den eine belegte Angabe zitiert, mit seinem Wortlaut (einer Abschrift), schon auf diesem Computer; {more} weitere entstehen durch die gewöhnliche Arbeit des Agenten — nach einigen Sitzungen erneut versuchen. Bis dahin gelten die vorgegebenen Größen.",
152
+ "ui.views.ask": "Das Lesen der Scans für {agent} abstimmen: {readers} bezahlte Lesungen von {n} Bildern dieser Forschung in {sizes} px, etwa {cost} (ein typischer Wert; die Preise des Agenten können abweichen). Starten?",
153
+ "ui.views.no": "Nichts gestartet; die Größen bleiben, wie sie waren.",
154
+ "ui.views.reset": "Die Abstimmung für {agent} ist vergessen: es gelten die vorgegebenen Größen (Suchen {find} px · Lesen {read} px).",
155
+ "ui.views.reset.none": "Für {agent} ist nichts abgestimmt: es gelten die vorgegebenen Größen (Suchen {find} px · Lesen {read} px).",
156
+ "ui.views.estimate": "{n} Bilder aus {books} Büchern, {readers} Lesungen in {sizes} px, etwa {cost} — startet ein Mensch: strom media calibrate",
157
+ "ui.views.offer": "das Lesen der Scans wurde für {before} abgestimmt, für {now} noch nicht: strom media calibrate (startet ein Mensch; bezahlte Arbeit des Modells)",
158
+ "ui.views.progress": "▶ {what} · {size} px · Bilder: {n}",
159
+ "ui.views.what.find": "Suchen",
160
+ "ui.views.what.read": "Lesen",
161
+ "ui.views.cost.unknown": "Kosten unbekannt",
162
+ "ui.views.spent": "Die Lesungen kosteten {cost}.",
163
+ "ui.o.views": "Scans",
164
+ "ui.settings.views": "Das Lesen der Scans abstimmen ({state})",
165
+ "ui.settings.views.default": "die vorgegebenen Größen",
166
+ "ui.settings.views.done": "abgestimmt {date}",
167
+ "ui.settings.views.other": "bisher für ein anderes Modell abgestimmt",
168
+ "ui.doc.views": "Lesen der Scans",
169
+ "ui.doc.views.default": "die vorgegebenen Größen: Suchen {find} px · Lesen {read} px",
170
+ "ui.doc.views.done": "abgestimmt {date}: Suchen {find} px · Lesen {read} px",
140
171
  "ui.setup.level": "Was darf der Agent tun, ohne nachzufragen?",
141
172
  "ui.setup.level.ask": "Mich bei allem außerhalb der Forschung fragen",
142
173
  "ui.setup.level.auto": "Selbstständig arbeiten – nur bei riskanten Schritten fragen (empfohlen)",
@@ -662,6 +693,7 @@
662
693
  "ui.help.cmd.pack": "Die Forschung in eine ZIP-Datei packen, damit jemand anderes weitermachen kann",
663
694
  "ui.help.cmd.unpack": "Einen zugeschickten Stammbaum entpacken",
664
695
  "ui.help.cmd.tidy": "Platz freigeben, den strom neben der Forschung belegt (erst gezeigt, nach Zustimmung)",
696
+ "ui.help.cmd.media.calibrate": "Die Größe der Scan-Ansichten für Agent und Modell der Forschung an ihren eigenen belegten Einträgen abstimmen (bezahlte Arbeit des Modells; die Kosten werden vorher genannt)",
665
697
  "ui.help.cmd.check": "Die Forschung prüfen: alles in Ordnung, nichts an strom vorbei geändert",
666
698
  "ui.help.cmd.config.get": "Eine Einstellung lesen",
667
699
  "ui.help.cmd.config.set": "Eine Einstellung ändern",
@@ -978,7 +1010,7 @@
978
1010
  "ui.run.which.bad": "Nummern aus der Liste, 1 bis {n}: z. B. 2 oder 1,4 oder 2-5.",
979
1011
  "ui.run.limit": "Für eine Aufgabe hat der Agent höchstens {minutes} Minuten; dann hält strom ihn an und die Aufgabe kommt zurück in die Warteschlange (Einstellung run.minutes).",
980
1012
  "ui.run.empty": "Die Warteschlange ist leer – dem Agenten im Gespräch sagen, was er suchen soll.",
981
- "ui.run.browser": "· {name}: Bilder über den eigenen Browser – der Agent bekommt Browser-Werkzeuge für {hosts}; Chrome mit der Claude-Erweiterung muss laufen",
1013
+ "ui.run.browser": "· {name}: Bilder über den eigenen Browser – Browser-Werkzeuge für {hosts} in den Sitzungen, deren Aufgabe sie brauchen kann; Chrome mit der Claude-Erweiterung muss laufen",
982
1014
  "ui.run.browser.model": " Hinweis: Browser-Werkzeuge brauchen ein Modell, das seine Schritte prüft – Sonnet oder Opus, nicht {model}: strom config set model.lead sonnet",
983
1015
  "ui.run.full": "· Berechtigungen: voll – der Agent darf alles außer dem, was die Berechtigungen des Stammbaums verbieten (zurück: strom config set agent.permissions auto)",
984
1016
  "ui.menu.working.more": "Gerade arbeiten Agenten selbstständig: {n}.",
@@ -994,6 +1026,11 @@
994
1026
  "ui.run.gate.no": "nein",
995
1027
  "ui.run.gate.noanswer": "keine gültige Antwort (strom gate test)",
996
1028
  "ui.run.stop.gate.declined": "nicht gestartet — die Bedingung „{name}“: {reason}",
1029
+ "ui.run.gate.cap": "· {name}: eine Obergrenze ist gesetzt – vor jeder Sitzung geprüft; kein „trotzdem starten“ geht darüber hinaus",
1030
+ "ui.run.stop.gate.cap": "die Obergrenze der Bedingung „{name}“ – {reason} (eine feste Grenze aus run.gate; kein „trotzdem starten“ geht darüber hinaus)",
1031
+ "ui.run.cap.finish": "⏳ {session}: das Limit des Agenten bei {used} % ({kind}) – die Sitzung ist gebeten aufzuschreiben, was gefunden wurde, und zu schließen; über der Obergrenze beginnt keine nächste Sitzung",
1032
+ "ui.run.limit.five_hour": "Fünf-Stunden-Fenster",
1033
+ "ui.run.limit.seven_day": "Woche",
997
1034
  "ui.run.loop": "Weiterarbeiten lassen, solange es Arbeit gibt und die Bedingung „{name}“ es erlaubt",
998
1035
  "ui.consent.gate.set": "Die Bedingung „{name}“ entscheiden lassen, wann der allein arbeitende Agent weitermacht?",
999
1036
  "ui.consent.gate.unset": "Die Bedingung „{name}“ entfernen — der allein arbeitende Agent fragt sie nicht mehr?",
@@ -1318,6 +1355,24 @@
1318
1355
  "log.research.done": "Richtung beendet: {name}",
1319
1356
  "log.mode.archive": "Die Forschung ist jetzt ein Archiv",
1320
1357
  "log.mode.research": "Die Forschung ist wieder eingeschaltet",
1358
+ "log.reading.loose": "Durchgelesene Bilder: {n}",
1359
+ "log.clips": "Einträge auf ihren Scans markiert: {n} von {total}",
1360
+ "log.transcripts": "Einträge aus ihren Ausschnitten abgeschrieben: {n} von {total}",
1361
+ "log.tree.create": "Forschung begonnen: {name}",
1362
+ "log.repair": "Die Daten auf den zuletzt versiegelten Stand zurückgesetzt",
1363
+ "log.chat.saved": "Nach einem Gespräch mit dem Agenten gespeichert",
1364
+ "log.migrate": "Die Daten des Stammbaums für ein neueres strom aktualisiert",
1365
+ "log.setting": "Einstellung der Forschung geändert: {key}",
1366
+ "log.image": "{name}, Bild {image}",
1367
+ "log.media.edit": "Bild geändert: {name}",
1368
+ "log.media.retract": "Bild zurückgezogen: {name}",
1369
+ "log.input.edit": "Material ergänzt: {name}",
1370
+ "log.input.skip": "Material als unbrauchbar beiseitegelegt: {name}",
1371
+ "log.input.sort": "Material sortiert: {name}",
1372
+ "log.record.edit": "Geändert: {name}",
1373
+ "ui.gate.timeout": "keine Antwort innerhalb von {s} s",
1374
+ "ui.gate.signal": "durch {signal} beendet",
1375
+ "ui.gate.status": "mit Exit-Status {status} beendet",
1321
1376
  "ui.waiting.title": "Der Agent braucht eine Antwort ({n}):",
1322
1377
  "ui.waiting.do": "Was zu tun ist: {what}",
1323
1378
  "ui.waiting.ask": "der Agent sagt es im Gespräch",
@@ -1478,6 +1533,13 @@
1478
1533
  "ui.gate.asked": "vor jeder Sitzung von strom run gefragt: {gate} (strom config unset run.gate: keine)",
1479
1534
  "ui.gate.unset": "keine wird gefragt: strom config set run.gate <Name> (nur der Benutzer)",
1480
1535
  "ui.gate.folder": "Ordner: {folder} – der hineinkopierte Ordner einer Bedingung ist installiert (die Schnittstelle: README.md dort)",
1536
+ "ui.gate.cap.week": "Obergrenze gesetzt: vor jeder Sitzung jedes Laufs gefragt; eine laufende Sitzung wird bei {pct} % der Woche um den Abschluss gebeten",
1537
+ "ui.gate.cap.window": "Obergrenze gesetzt: vor jeder Sitzung jedes Laufs gefragt; eine laufende Sitzung wird bei {pct} % des Fünf-Stunden-Fensters um den Abschluss gebeten",
1538
+ "ui.gate.test.go": "weiter",
1539
+ "ui.gate.test.wait": "warten bis {at}",
1540
+ "ui.gate.test.stop": "anhalten",
1541
+ "ui.gate.test.error": "Fehler – ein Lauf würde anhalten",
1542
+ "ui.gate.test.hard": "(Obergrenze: ein fester Halt, kein „trotzdem starten“)",
1481
1543
  "ui.hook.none": "keine Hooks",
1482
1544
  "ui.hook.on": "eingeschaltet: {hooks} (strom hook off <Name>)",
1483
1545
  "ui.hook.unset": "keiner ist eingeschaltet: strom hook on <Name> (nur der Benutzer)",
@@ -4,14 +4,14 @@ You work to the Genealogical Proof Standard: search thoroughly, cite every
4
4
  fact, analyse and correlate the evidence, resolve conflicts, and write the
5
5
  conclusion so the next researcher can follow it.
6
6
 
7
- <!-- for link verify enrich intake locate narrate -->
7
+ <!-- for link verify enrich intake locate narrate links -->
8
8
  - **Certainty is explicit.** `proven` — you read the original record yourself
9
9
  and it states the fact directly. `probable` — good evidence, but indirect or a
10
10
  single reading of hard handwriting. `possible` — weak evidence. `lead` — a
11
11
  family story, a family tree, an index or a guess: something to check, never a
12
12
  fact. Family trees and memories are leads, always.
13
13
  <!-- end -->
14
- <!-- for link verify enrich intake locate -->
14
+ <!-- for link verify enrich intake locate links -->
15
15
  - **A namesake is not your person.** Identify by year, place, house, occupation,
16
16
  spouse and parents — the mother's maiden name decides most cases. Two entries
17
17
  that give one name different parents (another mother) are **two people** —
@@ -65,7 +65,7 @@ conclusion so the next researcher can follow it.
65
65
  (`strom task list --off-tree`); they come back by themselves once the link
66
66
  is recorded.
67
67
  <!-- end -->
68
- <!-- for link verify enrich intake -->
68
+ <!-- for link verify enrich intake links -->
69
69
  - **Say what a hypothesis would connect.** A hypothesis about a connection —
70
70
  whose child, the same person, a couple, siblings — gets each variant's links
71
71
  when you record or argue it: `strom hypothesis link H… B --child P… --of F…`
@@ -80,6 +80,16 @@ conclusion so the next researcher can follow it.
80
80
  links names the variant it is decided for:
81
81
  `strom hypothesis decide H… --variant B --decision "…"`.
82
82
  <!-- end -->
83
+ <!-- for links -->
84
+ Read each variant whole (`strom hypothesis show H…`) and the people it
85
+ names (`strom person show P…`, `strom family show F…`); link only what its
86
+ words say beyond doubt — a namesake stays out. A link its claim does not say
87
+ comes off with `strom hypothesis link H… B --remove`; a variant that
88
+ connects nothing clear keeps none, and one that says what the tree records
89
+ already (marked so) has no link to make — the hypothesis stays open until
90
+ the records decide it. You read no records here: what would
91
+ decide a hypothesis is a task (`strom task add … --about H…`), not a search now.
92
+ <!-- end -->
83
93
  - **Stay within the task.** New questions become new tasks (`strom task add`,
84
94
  with where and done-when), not detours.
85
95
  <!-- for link verify enrich intake locate -->
@@ -7,9 +7,9 @@ search depends on** (a surname, a birthplace, a parish) is read again on a
7
7
  crop at full resolution before it is recorded; what stays unsure is recorded
8
8
  as unsure and said so.
9
9
 
10
- Every image you open stays in your context to the end of the session: look at
11
- as few pixels as the question needs, write down what you saw at once, and after
12
- about 80 views write down what you found before you open more.
10
+ Look at as few pixels as the question needs and write down what you saw at
11
+ once: after about 30 views write down what you found before you open more, and
12
+ never open again a view cleared from your context — your notes hold it.
13
13
 
14
14
  - **Look only through views**: `strom media view B0001:57` (record set and
15
15
  image number) makes a file in `.strom/views/` — open that file. Whole images
@@ -24,18 +24,19 @@ about 80 views write down what you found before you open more.
24
24
  page, where they are sharper than one view of it), `--crop … --crop …`
25
25
  (several entries of one image), `--split 2x2` (a page in overlapping parts),
26
26
  `strom media view B0001 --page 112 113`. Each file comes with its image, page
27
- and `--clip`. At most 12 images and 24 views in one call.
27
+ and `--clip`. At most 12 images and 24 views in one call: with 4 views an
28
+ image (halves and crops), 6 images a call.
28
29
  - **Find, then crop.** `--grid` overlays tenths with labels; read off where the
29
30
  entry is and ask for exactly that part: `--crop 0.05,0.40,0.45,0.18` (x, y,
30
31
  width, height as fractions) or `--half left|right` for one page of a spread.
31
32
  A crop comes at full resolution (small ones enlarged). `--contrast` for faded
32
33
  ink, `--rotate 90` for sideways pages.
33
34
  <!-- for link verify enrich part -->
34
- - **Too small to read?** When a crop says it is enlarged, the scan has no more
35
- detail there. A connector that can fetch a part of an image sharper says so
36
- in that line: `strom fetch <connector> --recordset B0001 --images 57 --crop
37
- …` (one request). Then view the same crop again: it comes from the sharper
38
- part by itself.
35
+ - **Too small to read?** A crop said enlarged: the scan has no more detail.
36
+ A connector that fetches a part sharper says so in that line: `strom fetch
37
+ <connector> --recordset B0001 --images 57 --crop …`; the same crop viewed
38
+ again comes from it. Whole images first, a part only where entries need
39
+ it: an archive's hourly cap stops the rest.
39
40
  <!-- end -->
40
41
  - **Browsing a book is a reader's job**: `strom read B0001 --images 40-69
41
42
  --question "…"` — readers in batches of ten, each with the full question.
@@ -51,8 +52,8 @@ about 80 views write down what you found before you open more.
51
52
  foreground and let it finish — your session ends with your turn, and
52
53
  whatever is left running in the background ends with it.
53
54
  (A scan-reader subagent where your agent has one, strom-scan-reader, or your
54
- own subagents — on your own model, never a faster one — read too, in batches
55
- of at most twelve with the whole question; what they report is lost with
55
+ own subagents — on your own model, never a faster one — read too, about six scans
56
+ each with the whole question; what they report is lost with
56
57
  your session unless you write it down: record each report as it comes back,
57
58
  before you send the next readers.) Only the entries
58
59
  that will be cited need your own eyes, at full resolution.
@@ -49,6 +49,17 @@ One line of JSON on stdout (the last line) may say more:
49
49
  - `reason`: why, for the user (in their language: `STROM_LANG`).
50
50
  - `wait` (seconds) or `until` (a time): when to ask again. Without them: in
51
51
  15 minutes; never sooner than a minute.
52
+ - `hard` (`true`, with status 1 or 2): this answer is the user's own hard
53
+ limit — a cap set in `run.gate`. The run ends, saying the reason; no
54
+ "start anyway" goes past it.
55
+ - `watch` (`{"kind": "seven_day", "finish": 0.99}`): the gate holds a cap on
56
+ that window of the agent's plan (`five_hour` or `seven_day`). strom then asks
57
+ it before **every** session, also of the runs you started yourself (there
58
+ only its hard stop counts), and asks a session at work to finish — write
59
+ down what it found and close — once the agent says the window's use reached
60
+ `finish` (0–1). A gate that never says `watch` is asked as before.
61
+
62
+ Both are optional; an older strom ignores them.
52
63
 
53
64
  Plain text instead of JSON is the reason.
54
65
 
@@ -66,9 +77,13 @@ Environment variables, besides the user's own:
66
77
  | `STROM_SESSIONS` | sessions this run has had |
67
78
  | `STROM_COST_USD` | what this run has cost so far (as the agent reported it) |
68
79
  | `STROM_NEXT_TASK` | the task the next session would take |
80
+ | `STROM_AGENT_LIMITS` | what the agent said of its plan's limits in this run, when it said any (Claude Code): JSON `[{"kind": "five_hour" \| "seven_day", "used": 0.97, "resetsAt": "<ISO time>", "at": "<when it said it>"}]` — absent otherwise; an older gate ignores it |
69
81
 
70
82
  A session already at work is never stopped by a gate: it is asked between
71
- sessions only (a session's own time limit is `run.minutes`).
83
+ sessions only (a session's own time limit is `run.minutes`). Under a cap
84
+ (`watch`) the session is asked to finish, as `strom session finish` does: its
85
+ agent hears it from its next strom command and starts no new reader; work it
86
+ delegated inside itself (a subagent) strom cannot stop half-way.
72
87
 
73
88
  The gate holds the runs that go on by themselves: `strom run --loop` and
74
89
  `--until`. Tasks you start yourself (one, `--max 3`, `--task T0007`, "work
@@ -91,5 +106,17 @@ Not enough in hand: it waits until the week has caught up (past the reset: the
91
106
  new week's share). A used-up session: until it resets. Another agent than
92
107
  Claude Code: it lets the work go on.
93
108
 
109
+ **A cap** — your own hard stop for the week:
110
+
111
+ strom config set run.gate "claude-usage 10 --cap 95"
112
+
113
+ At 95 % of the week used no session starts: in every run, `--max` and
114
+ `--task` and the menu's too, asked before each session, and no "start anyway"
115
+ goes past it — the run ends saying the use and when the week resets. A session
116
+ at work is asked to finish when Claude Code says the week is at 99 %. What
117
+ Claude Code said in the run (`STROM_AGENT_LIMITS`, at most 15 minutes old) is
118
+ read instead of asking `claude -p /usage`. `--cap` alone: the cap without the
119
+ pace (`claude-usage --cap 95`).
120
+
94
121
  A gate is a program on this computer, put here by you (or by strom); the
95
122
  `.gitignore` of the plugins folder keeps it out of any repository.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "interface": 1,
3
3
  "title": "Claude usage",
4
- "description": "Keeps working alone to the daily ration of your Claude subscription: a session starts only while the week's usage is at least n points behind the share of the week gone (a day ≈ 14.3): strom config set run.gate \"claude-usage 10\" (without a number: 0).",
4
+ "description": "Keeps working alone to the daily ration of your Claude subscription: a session starts only while the week's usage is at least n points behind the share of the week gone (a day ≈ 14.3): strom config set run.gate \"claude-usage 10\" (without a number: 0). A cap: \"claude-usage 10 --cap 95\" — at 95 % of the week no session starts, in any run, and no \"start anyway\" goes past it.",
5
5
  "command": [
6
6
  "node",
7
7
  "gate.ts"
@@ -11,11 +11,22 @@
11
11
  // Without a number: 0 — no faster than the week goes. Else it waits until the
12
12
  // week has caught up (or past the reset); a full session: until it resets.
13
13
  //
14
+ // A cap (strom config set run.gate "claude-usage 15 --cap 95"): at 95 % of the
15
+ // week used no session starts — the user's own hard stop, asked before every
16
+ // session of every run, and no "start anyway" goes past it; a session at work
17
+ // is asked to finish when the week reaches 99 %. What the agent said of its
18
+ // limits in this run (STROM_AGENT_LIMITS, at most 15 minutes old) is read
19
+ // instead of asking `claude -p /usage`.
20
+ //
14
21
  // strom writes this file; a copy of your own goes into a folder of its own name.
15
22
 
16
23
  import { spawnSync } from "node:child_process";
17
24
 
18
25
  const DAY = 86_400_000;
26
+ /** What the agent said of its limits counts for this long; older: `claude -p /usage` is asked. */
27
+ const FRESH_MS = 15 * 60_000;
28
+ /** Under a cap, a session at work is asked to finish at this much of the week. */
29
+ const FINISH_AT = 0.99;
19
30
  const WEEK = 7 * DAY;
20
31
  const lang = (process.env.STROM_LANG ?? "en").slice(0, 2);
21
32
 
@@ -27,7 +38,11 @@ const T: Record<string, Record<string, string>> = {
27
38
  session: "the session is used up — until it resets",
28
39
  week: "week {used} % used, {gone} % gone, {behind} in hand (at least {min} needed) — until the week catches up",
29
40
  bad: "the number must be 0 to 99, not \"{arg}\"",
41
+ badcap: "the cap must be 1 to 100 (\"--cap 95\"), not \"{arg}\"",
42
+ cap: "week {used} % used — the cap of {cap} % reached; it resets {resets}",
30
43
  unread: "cannot read `claude -p /usage`: {detail}",
44
+ noweek: "no line \"Current week … resets …\"",
45
+ exit: "it ended with exit status {status}",
31
46
  },
32
47
  cs: {
33
48
  other: "agent není Claude Code — není co hlídat",
@@ -36,7 +51,11 @@ const T: Record<string, Record<string, string>> = {
36
51
  session: "sezení je vyčerpané — do jeho obnovení",
37
52
  week: "týden: využito {used} %, uplynulo {gone} %, náskok {behind} (potřeba aspoň {min}) — dokud čas nedožene",
38
53
  bad: "číslo musí být 0 až 99, ne \"{arg}\"",
54
+ badcap: "strop musí být 1 až 100 (\"--cap 95\"), ne \"{arg}\"",
55
+ cap: "týden: využito {used} % – strop {cap} % dosažen; obnoví se {resets}",
39
56
  unread: "nelze přečíst `claude -p /usage`: {detail}",
57
+ noweek: "chybí řádek „Current week … resets …“",
58
+ exit: "skončilo s kódem {status}",
40
59
  },
41
60
  de: {
42
61
  other: "der Agent ist nicht Claude Code — nichts zu prüfen",
@@ -45,50 +64,82 @@ const T: Record<string, Record<string, string>> = {
45
64
  session: "die Sitzung ist aufgebraucht — bis sie zurückgesetzt wird",
46
65
  week: "Woche: {used} % genutzt, {gone} % vergangen, Vorsprung {behind} (mindestens {min} nötig) — bis die Zeit aufholt",
47
66
  bad: "die Zahl muss 0 bis 99 sein, nicht \"{arg}\"",
67
+ badcap: "die Obergrenze muss 1 bis 100 sein (\"--cap 95\"), nicht \"{arg}\"",
68
+ cap: "Woche: {used} % genutzt – Obergrenze {cap} % erreicht; zurückgesetzt {resets}",
48
69
  unread: "`claude -p /usage` nicht lesbar: {detail}",
70
+ noweek: "keine Zeile „Current week … resets …“",
71
+ exit: "mit Exit-Status {status} beendet",
49
72
  },
50
73
  };
51
74
  function say(key: string, v: Record<string, string | number> = {}): string {
52
75
  const s = (T[lang] ?? T.en!)[key] ?? T.en![key]!;
53
76
  return s.replace(/\{(\w+)\}/g, (_, k: string) => String(v[k] ?? ""));
54
77
  }
55
- function answer(code: 0 | 1 | 2, reason: string, until?: Date): never {
56
- console.log(JSON.stringify({ reason, ...(until ? { until: until.toISOString() } : {}) }));
78
+ function answer(code: 0 | 1 | 2, reason: string, until?: Date, hard?: boolean): never {
79
+ // under a cap: strom asks before every session and asks a session at work to finish near the week's end
80
+ const watch = cap !== undefined ? { kind: "seven_day", finish: FINISH_AT } : undefined;
81
+ console.log(JSON.stringify({ reason, ...(until ? { until: until.toISOString() } : {}), ...(hard ? { hard: true } : {}), ...(watch ? { watch } : {}) }));
57
82
  process.exit(code);
58
83
  }
59
84
 
60
- // ── your number: how many points usage must be behind the week gone ─────────
61
- const arg = process.argv[2] ?? "0";
85
+ // ── your number: how many points usage must be behind the week gone; --cap: the week's hard stop ─
86
+ const argv = process.argv.slice(2);
87
+ let cap: number | undefined;
88
+ let arg = "0";
89
+ for (let i = 0; i < argv.length; i++) {
90
+ const a = argv[i]!;
91
+ if (a === "--cap" || a.startsWith("--cap=")) {
92
+ const v = a === "--cap" ? (argv[++i] ?? "") : a.slice(6);
93
+ if (!/^\d{1,3}$/.test(v) || Number(v) < 1 || Number(v) > 100) answer(2, say("badcap", { arg: v }));
94
+ cap = Number(v);
95
+ } else arg = a;
96
+ }
62
97
  const min = Number(arg);
63
98
  if (!/^\d{1,2}$/.test(arg)) answer(2, say("bad", { arg }));
64
99
 
65
- if ((process.env.STROM_AGENT ?? "claude") !== "claude") answer(0, say("other"));
100
+ if ((process.env.STROM_AGENT ?? "claude") !== "claude") {
101
+ cap = undefined; // another agent: no limits of Claude's to hold
102
+ answer(0, say("other"));
103
+ }
66
104
 
67
- // ── what Claude Code says ───────────────────────────────────────────────────
68
- const r = spawnSync("claude", ["-p", "/usage"], { encoding: "utf8", timeout: 90_000, shell: process.platform === "win32", windowsHide: true });
69
- if (r.error || r.status !== 0) answer(2, say("unread", { detail: r.error?.message ?? (r.stderr || r.stdout || `exit ${r.status}`).trim().split("\n")[0] ?? "" }));
70
- const text = r.stdout;
71
- if (/API key/i.test(text) && !/Current week/i.test(text)) answer(0, say("api"));
105
+ type Use = { used: number; resets?: Date };
106
+ let session: Use | undefined;
107
+ let week: Use | undefined;
72
108
 
73
- const LINE = /^Current (session|week)(?: \(([^)]+)\))?:\s*(\d+)%\s*used(?:\s*·\s*resets\s*(.+))?$/i;
74
- let session: { used: number; resets?: Date } | undefined;
75
- let week: { used: number; resets?: Date } | undefined;
76
- for (const raw of text.split(/\r?\n/)) {
77
- const m = LINE.exec(raw.trim());
78
- if (!m) continue;
79
- const item = { used: Number(m[3]), ...(m[4] ? { resets: resetAt(m[4]) } : {}) };
80
- if (m[1]!.toLowerCase() === "session") session = item;
81
- // the limit of all models is the one that stops the work; a model's own week only if there is no other
82
- else if (!week || /all models/i.test(m[2] ?? "")) week = item;
109
+ // ── what the agent said in this run, when it is fresh ───────────────────────
110
+ const said = fromAgent(process.env.STROM_AGENT_LIMITS);
111
+ if (said) ({ session, week } = said);
112
+ else {
113
+ // ── what Claude Code says ─────────────────────────────────────────────────
114
+ const r = spawnSync("claude", ["-p", "/usage"], { encoding: "utf8", timeout: 90_000, shell: process.platform === "win32", windowsHide: true });
115
+ // what Claude Code or the system said is said as it is; the gate's own words in the research language (STROM_LANG)
116
+ if (r.error || r.status !== 0) answer(2, say("unread", { detail: r.error?.message ?? ((r.stderr || r.stdout || "").trim().split("\n")[0] || say("exit", { status: String(r.status) })) }));
117
+ const text = r.stdout;
118
+ if (/API key/i.test(text) && !/Current week/i.test(text)) {
119
+ cap = undefined;
120
+ answer(0, say("api"));
121
+ }
122
+ const LINE = /^Current (session|week)(?: \(([^)]+)\))?:\s*(\d+)%\s*used(?:\s*·\s*resets\s*(.+))?$/i;
123
+ for (const raw of text.split(/\r?\n/)) {
124
+ const m = LINE.exec(raw.trim());
125
+ if (!m) continue;
126
+ const item = { used: Number(m[3]), ...(m[4] ? { resets: resetAt(m[4]) } : {}) };
127
+ if (m[1]!.toLowerCase() === "session") session = item;
128
+ // the limit of all models is the one that stops the work; a model's own week only if there is no other
129
+ else if (!week || /all models/i.test(m[2] ?? "")) week = item;
130
+ }
83
131
  }
84
- if (!week?.resets) answer(2, say("unread", { detail: "no line \"Current week … resets …\"" }));
132
+ if (!week?.resets) answer(2, say("unread", { detail: say("noweek") }));
133
+ // the cap first: the user's own hard stop, whatever the pace
134
+ if (cap !== undefined && week.used >= cap)
135
+ answer(2, say("cap", { used: Math.floor(week.used), cap, resets: week.resets.toLocaleString(lang, { weekday: "short", day: "numeric", month: "numeric", hour: "2-digit", minute: "2-digit" }) }), undefined, true);
85
136
 
86
137
  const now = Date.now();
87
138
  const start = week.resets.getTime() - WEEK;
88
139
  const gone = Math.max(0, Math.min(100, ((now - start) / WEEK) * 100));
89
140
  const behind = gone - week.used;
90
141
  // shown rounded down: never "15 in hand (at least 15 needed)" for 14.6 — and gone − used stays what it says
91
- const v = { used: week.used, gone: Math.floor(gone), behind: Math.floor(behind), min };
142
+ const v = { used: Math.floor(week.used), gone: Math.floor(gone), behind: Math.floor(behind), min };
92
143
  if (session && session.used >= 100) answer(1, say("session"), session.resets ? new Date(session.resets.getTime() + 60_000) : undefined);
93
144
  if (behind < min) {
94
145
  // when the week gone reaches usage + the number; past the reset, the new week's number
@@ -98,6 +149,33 @@ if (behind < min) {
98
149
  }
99
150
  answer(0, say("go", v));
100
151
 
152
+ /**
153
+ * The limits Claude Code said in this run (strom passes them: [{kind, used 0–1, resetsAt, at}]), when the week's is
154
+ * at most FRESH_MS old and not past its reset; else nothing — `claude -p /usage` is asked.
155
+ */
156
+ function fromAgent(json: string | undefined): { session?: Use; week: Use } | undefined {
157
+ if (!json) return undefined;
158
+ let list: unknown;
159
+ try {
160
+ list = JSON.parse(json);
161
+ } catch {
162
+ return undefined;
163
+ }
164
+ if (!Array.isArray(list)) return undefined;
165
+ const of = (kind: string): Use | undefined => {
166
+ const l = list.find((x) => x && typeof x === "object" && (x as { kind?: unknown }).kind === kind) as { used?: unknown; resetsAt?: unknown; at?: unknown } | undefined;
167
+ if (!l || typeof l.used !== "number" || !Number.isFinite(l.used) || typeof l.at !== "string") return undefined;
168
+ const at = Date.parse(l.at);
169
+ const resets = typeof l.resetsAt === "string" ? new Date(l.resetsAt) : undefined;
170
+ if (Number.isNaN(at) || Date.now() - at > FRESH_MS || !resets || Number.isNaN(resets.getTime()) || resets.getTime() <= Date.now()) return undefined;
171
+ return { used: l.used * 100, resets };
172
+ };
173
+ const week = of("seven_day");
174
+ if (!week) return undefined;
175
+ const session = of("five_hour");
176
+ return { week, ...(session ? { session } : {}) };
177
+ }
178
+
101
179
  /** "Sep 30 at 2pm (Europe/Prague)", "Oct 2 at 11:30am (UTC)" → the moment. */
102
180
  function resetAt(s: string): Date | undefined {
103
181
  const m = /^(\w{3})\w*\s+(\d{1,2})\s+at\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)\s*\(([^)]+)\)/i.exec(s.trim());
@@ -74,9 +74,11 @@ they ask.
74
74
  - the agent working on its own: they start it from strom's menu ("Let the
75
75
  agent work on its own"); it works the task queue and tells them the result;
76
76
  with many tasks in the queue, suggest it — every task gets a fresh session;
77
- - one task, one fresh context: after a session closes, strom says how the
78
- user clears your context (Claude Code: /clear) — nothing is lost, strom
79
- keeps it all; suggest it in a sentence, go on here if they prefer;
77
+ - one task, one fresh context — in a conversation: after a session closes
78
+ there, strom says how the user clears your context (Claude Code: /clear)
79
+ — nothing is lost, strom keeps it all; suggest it in a sentence, go on
80
+ here if they prefer. Working alone (strom run) each task starts fresh by
81
+ itself and nobody reads a closing message: no such advice there;
80
82
  - what only they can do: when strom needs their consent it opens a window
81
83
  on their screen — tell them to answer it, you cannot; images a portal gives
82
84
  only by hand — strom says which ones and where to save them.
@@ -12,11 +12,14 @@
12
12
  export const TIERS = ["lead", "vision", "text", "cheap"];
13
13
  const DELEGATION_RULES = `- Browsing a book, an index or a range of images ("is our surname on this page?")
14
14
  is delegated; so is anything self-contained that returns little.
15
- - About ten scans (images B…:n) per delegate, never more than twelve; it opens
16
- as many halves and crops of them as reading needs, but tell it to stop at
17
- about 80 views and return what it has: every view stays in its context to
18
- the end. It asks for the views of a scan (or of a few) in one call —
15
+ - About six scans (images B…:n) per delegate, four views each (halves and
16
+ crops); tell it to write down what each call gave before the next, to stop
17
+ at about 30 views and return what it has, and never to open again a view
18
+ cleared from its context (its notes hold it). It asks for the
19
+ views of a scan (or of a few) in one call —
19
20
  \`strom media view B0001:57-60 --half both\` — and opens them together.
21
+ - Fetch the images before you delegate: a delegate never fetches, nor waits
22
+ for an archive — it reports the images missing or too small, and you fetch them.
20
23
  - Every delegate gets the full question (what counts as a find, which years,
21
24
  which names) and returns for each image: image and page, find or nothing,
22
25
  what was illegible, the hand, and certainty per name — written as it goes.
@@ -28,11 +31,12 @@ export const SELF_READING = `## Reading scans (Codex, Antigravity, OpenCode, Gro
28
31
 
29
32
  Read the images yourself, with your strongest model — never hand old
30
33
  handwriting to a faster or cheaper model, subagent or pass. Read them
31
- in batches of at most ten: open a batch (one call gives its views —
32
- \`strom media view B0001:57-66 --half both\` — open them together), write
34
+ in batches of about six: open a batch (one call gives its views —
35
+ \`strom media view B0001:57-62 --half both\` — open them together), write
33
36
  down what it gave (strom search add … for what was not found, facts for what
34
- was), then open the next. Every image and view stays in your context to the end: after about 80
35
- views, write down what you found and go on. A name or place the next search depends on:
37
+ was), then open the next. After about 30 views, write down what you found
38
+ and go on; a view cleared from your context is not opened again — your
39
+ notes hold it. A name or place the next search depends on:
36
40
  read it again on a crop at full resolution (\`strom media view … --crop\`)
37
41
  before you record it.
38
42
  OpenCode: this tree's subagent strom-scan-reader (strom and the file reader