@@ -23,17 +23,19 @@ Code/Insiders/VSCodium variants, or `--vscode-dir` — from WSL, pointed at the
2323store — ` VscodeStore ` ),
2424** pi-agent** sessions (` ~/.pi/agent/sessions/**/*.jsonl ` or ` $PI_AGENT_DIR ` , ` PiStore ` ),
2525** OpenClaw** gateway sessions (` ~/.openclaw/agents/**/sessions/*.jsonl ` or ` $OPENCLAW_DIR ` ,
26- ` OpenClawStore ` ), and a ** JSONL/NDJSON of logged API requests** (the per-line twin of the
26+ ` OpenClawStore ` ), ** Zaly** sessions
27+ (` ~/.local/share/zaly/sessions/*/*/session.jsonl ` or ` $ZALY_DATA ` /` $ZALY_ROOT ` ,
28+ ` ZalyStore ` ), and a ** JSONL/NDJSON of logged API requests** (the per-line twin of the
2729CSV source; ` --jsonl ` , default ` ~/.config/opentab/requests.jsonl ` , ` JsonlStore ` ).
2830` CombinedStore ` merges them. Pick with
29- ` --source {auto,opencode,claude,codex,hermes,csv,jsonl,copilot,vscode,pi,openclaw,all} ` or
30- switch live with ** ` c ` ** .
31+ ` --source {auto,opencode,claude,codex,hermes,csv,jsonl,copilot,vscode,pi,openclaw,zaly, all} `
32+ or switch live with ** ` c ` ** .
3133
3234Cost model: Claude Code, Codex, and Copilot (CLI and VS Code) record ** no per-message
3335cost** , so they behave like an OpenCode * subscription* session — ** $0 in normal mode** , a
34- list-price estimate (tokens × API price) only under ** ` $ ` ** . Hermes, CSV/JSONL, pi, and
35- OpenClaw are ** mixed** : subscription/OAuth routes stay $0/estimated, metered routes record
36- real spend. See each backend's note under Architecture.
36+ list-price estimate (tokens × API price) only under ** ` $ ` ** . Hermes, CSV/JSONL, pi,
37+ OpenClaw, and Zaly are ** mixed** : subscription/OAuth routes stay $0/estimated, metered
38+ routes record real spend. See each backend's note under Architecture.
3739
3840## Commands
3941
@@ -118,7 +120,7 @@ src/opentab/
118120 sources.py make_store/resolve_source/available_sources/source_cycle + path routing
119121 state.py load_state/save_state/apply_state
120122 themes.py THEMES palettes (single source for the web browser + the TUI) + hex math
121- stores/ opencode, claude, codex, hermes, csv_source, jsonl_source, copilot, vscode, pi, openclaw, combined, cached
123+ stores/ opencode, claude, codex, hermes, csv_source, jsonl_source, copilot, vscode, pi, openclaw, zaly, combined, cached
122124 tui/ renderer (Renderer), app (App)
123125 web.py build_payload/session_extras + html_command/serve_command (ReportServer)
124126 webpage.py render_html: the self-contained browser page (inline CSS/JS strings)
@@ -157,7 +159,7 @@ Three logical layers (the class names below live in the files above — `Store`
157159 ` getattr ` , each gated by ` supports_*(workflow_id) ` so the merged view hides an
158160 unsupported tab rather than showing it empty (` CombinedStore ` routes by owning backend).
159161 Turns is implemented by every backend except Hermes; Tools by OpenCode, Claude, Codex,
160- pi, and CSV/JSONL (the others record no per-step tool calls with usage). Records
162+ pi, Zaly, and CSV/JSONL (the others record no per-step tool calls with usage). Records
161163 ** no per-message cost** → a * subscription* backend: ` model_breakdown ` reports ` cost=0 `
162164 with tokens in the ` unpriced_* ` /` root_unpriced_* ` splits, so the normal ` $ ` machinery
163165 gives ** $0 / list-price estimate** with no special-casing. ` records_cost=False ` drives
@@ -297,7 +299,31 @@ grouping and the regenerate/append dedup) and **Tools** (the optional `tool` col
297299 OpenClaw's generic cwd); messages dedupe by record ` id ` across live + archived
298300 (` .jsonl.reset. ` /` .jsonl.deleted. ` ). No subagent tree; usage-less sessions dropped.
299301 Implements ** Turns** exactly like pi (epoch-seconds timestamps).
300- - ** ` JsonlStore ` ** — ninth backend over a ** JSONL/NDJSON of logged API requests** (one JSON
302+ - ** ` ZalyStore ` ** — ninth backend over ** Zaly** session NDJSON
303+ (` <data>/sessions/<encoded-workspace>/<uuid>/session.jsonl ` ; data resolved like zaly's
304+ own envPaths — ` $ZALY_DATA ` / ` $ZALY_ROOT/data ` / ` $XDG_DATA_HOME/zaly ` , default
305+ ` ~/.local/share/zaly ` , or ` --zaly-dir ` ), same methods. Each session is one append-only
306+ JSONL ** DAG** (` session-settings ` snapshots ` {sessionId, cwd/workspace, modelId} ` ;
307+ resume/fork append to the * same* file, so no cross-file dedup — assistant messages
308+ still dedupe by ` message.id ` , and abandoned regenerated branches count: each was a
309+ real API call). Usage lives on ` message.meta.usage ` (model on ` meta.modelId ` , already
310+ provider-qualified — ` openai-codex/gpt-5.6-sol ` — used verbatim): ** Anthropic-normalized**
311+ tokens (` input ` already uncached — zaly's OpenAI adapter subtracts ` cached_tokens `
312+ itself; cacheRead/cacheWrite separate) with ** ` reasoning ` a subset of ` output ` **
313+ (OpenAI's reasoning_tokens detail) → reported as 0 like Codex/Copilot, since opentab's
314+ reasoning column is additive and counting it would double-bill under ` $ ` . The
315+ per-message ` usage.cost ` is a ** per-component USD object** ({input, output, cacheRead,
316+ …}, no ` .total ` — summed) computed from zaly's catalog for ** every** route, so the
317+ pi/OpenClaw ** metered-vs-subscription split** : subscription when the ` meta.modelId `
318+ provider prefix is an OAuth login in zaly's ` <state>/auth.json `
319+ (` {provider: {type: "oauth"|"api-key"}} ` , ` $ZALY_STATE ` -resolved, read-only) or matches
320+ ` _SUBSCRIPTION_MARKERS ` (codex/copilot/ollama/lm-studio/…); ** ` records_cost `
321+ per-instance** . Workspace → git root; settings ` sessionId ` beats the dir name. ** No
322+ subagent tree** — zaly writes subagent transcripts to tmpdir and does * not* fold their
323+ usage into the parent (a latent undercount, documented in the docstring). Settings-only
324+ sessions (zaly launched, nothing asked) are dropped. Implements ** Turns** (epoch-ms
325+ timestamps, ▸-grouped like pi) and ** Tools** (the step's ` tool-call ` content parts).
326+ - ** ` JsonlStore ` ** — tenth backend over a ** JSONL/NDJSON of logged API requests** (one JSON
301327 object per line, generic). ** Subclasses ` CsvStore ` ** — its per-line twin — inheriting
302328 OpenAI-style token accounting, mixed per-row cost (` records_cost ` per-instance;
303329 ` cost_usd ` /` credits ` ), provider-prefixed models, synthetic ` (date, project) ` sessions,
@@ -375,7 +401,7 @@ tuples `month_tabs`/`day_tabs`/`project_tabs`/`workflow_tabs`. `current_tabs()`
375401source of truth (don't index a class tuple directly): it appends, in order, a ** Turns**
376402tab (when ` supports_turns(id) ` — every backend except Hermes, whose DB records no
377403per-message usage) and a ** Tools** tab (when
378- ` supports_tools(id) ` — OpenCode, Claude, Codex, pi, and CSV/JSONL sessions whose log
404+ ` supports_tools(id) ` — OpenCode, Claude, Codex, pi, Zaly, and CSV/JSONL sessions whose log
379405carries the optional ` tool ` column) to the * selected* session's ` workflow_tabs ` , each
380406gated per-session so the merged view hides an unsupported tab rather than showing it
381407empty, and injects ** Sources** in the merged view — so ` draw_detail ` dispatches the
0 commit comments