Skip to content

Release v0.1.1 - #4

Merged
anilmurty merged 1 commit into
mainfrom
release-v0.1.1
Apr 6, 2026
Merged

Release v0.1.1#4
anilmurty merged 1 commit into
mainfrom
release-v0.1.1

Conversation

@anilmurty

Copy link
Copy Markdown
Contributor

Summary

Bump version to 0.1.1 with changelog covering all changes since v0.1.0-alpha.

Fixed

  • ocw export empty output (corrupted DuckDB span indexes)
  • ocw status showing ? for completed sessions
  • ocw status showing $0.000000 cost (date.today vs UTC mismatch)
  • ocw cost spurious zero-cost row from session spans

Added

  • Trace ID prefix matching in ocw trace
  • PyPI/npm publish workflows
  • PyPI metadata (README, classifiers, project URLs)
  • CODEOWNERS

Changed

  • npm package renamed to @openclawwatch/sdk
  • AGENTS.md consolidated to point at CLAUDE.md

Test plan

  • Merge PR, then create GitHub release with tag v0.1.1
  • publish-pypi.yml triggers and publishes to PyPI with updated metadata

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@anilmurty
anilmurty merged commit 96c3006 into main Apr 6, 2026
4 checks passed
@anilmurty
anilmurty deleted the release-v0.1.1 branch April 7, 2026 18:19
anilmurty added a commit that referenced this pull request Jun 19, 2026
#4: plain `tj onboard` honors --plan / prompts for plan tier
HoomanDgtl pushed a commit to HoomanDigital/tokenjam that referenced this pull request Jun 20, 2026
…an tier

Plain `tj onboard` only prompted for daily budget and silently ignored
`--plan`, so `[budget.<provider>] plan` was never written — breaking
plan-aware dollar rendering and contradicting the docs.

- The plain path now honors `--plan <tier>` non-interactively and prompts for
  it interactively (Claude-first: offers the Anthropic tiers). An OpenAI-only
  tier (plus/team/enterprise) is routed to `[budget.openai]`; everything else
  to `[budget.anthropic]`. Non-interactive with no `--plan` writes no plan
  section (no hang, no presumptuous default).
- Confirmation line + CLAUDE.md wording updated to match.

The `--claude-code` / `--codex` global integration flows are unchanged.

Tests: --plan writes the right [budget.<provider>] section (api/max_5x →
anthropic, plus → openai), no-plan non-interactive writes none, output is valid
TOML. Full suite green (711); ruff/mypy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HoomanDgtl pushed a commit to HoomanDigital/tokenjam that referenced this pull request Jun 20, 2026
…Labs#157)

The plan-written confirmation rendered "(written to )" because Rich
interpreted the `[budget.<provider>]` TOML header as a markup tag and
stripped it. Wrap the section name in rich.markup.escape() so it renders
literally. Regression introduced by the Metabuilder-Labs#4 fix (plain onboard --plan).

Adds a regression test asserting the message keeps the section header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
#4)

Claude Code's built-ins leave a real, documented gap: /compact is reactive,
lossy and single-session; /context shows current-session totals only. Neither
attributes WHAT is burning quota across sessions nor suggests a structural fix.
A whole DIY ecosystem (ccusage, codeburn, context-analyzer, session-recall, ...)
has sprung up to fill it — the strongest revealed-demand signal. Proof point:
anthropics/claude-code#24147, where a dev hand-parsed 30 days of JSONL to find
CLAUDE.md re-reads consumed 99.93% of their quota.

`tj context` runs a local diagnostic over Claude Code sessions and reports:

1. Per-turn context composition — what share of each turn went to RE-READING
   prior context (cache-read tokens: conversation history, CLAUDE.md, accrued
   tool output) vs. NET-NEW WORK (uncached input + output), with the re-read
   overhead named.
2. Recurring inclusions — the same file re-read across many sessions,
   frequency-counted, each with a concrete `@file` / CLAUDE.md structural fix
   (capture-gated on `[capture] tool_inputs`).
3. Compact candidates — sessions whose accumulated re-reading makes a
   mid-session /compact reclaim the most quota.

Framing is quota-native (the subscription majority): headline numbers render as
token-share / "% of cycle tokens" via core/framing.py — the single source of
truth for plan-tier-aware rendering — for Pro/Max users. Dollars are a SECONDARY
calibration signal for API users, never the headline. Output is a
screenshottable terminal card; `--json` for machine-readable output.

Honesty discipline (CLAUDE.md Rule 14): every figure is a measured token share
or a structural candidate flag, never a guaranteed saving; re-read tokens are
cache reads (billed at a reduced rate, not free) — real quota, stated as such.

Needs a direct DuckDB connection (reads the raw `attributes` column, which the
API shim doesn't expose) — fails gracefully with a `tj stop` hint when the
daemon holds the lock, mirroring `tj report --trim`.

Scoped OUT of v1 (named, not faked): MCP schema-injection attribution and
prompt-cache-miss attribution aren't derivable from current backfill data;
recurring-inclusion detection covers file Reads only. Per the #3 handoff,
content lands only on freshly-ingested spans after enabling `[capture]` — the
command surfaces that nudge rather than silently showing empty recurring data.

Covered by tests/unit/test_context_diagnostic.py over a synthetic multi-session
fixture: per-turn re-read-vs-work composition, cross-session recurring-inclusion
detection with structural fix, compact-candidate detection, the capture-off
nudge, and end-to-end CLI rendering of quota-share for a Max plan.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
…e reads

#4's recurring-inclusion detection only covered file Reads (group by
`file_path`, frequency-count across sessions, suggest `@file`/CLAUDE.md).
Repeated prompts, repeated searches, and large repeated tool outputs also
re-paste across turns/sessions and burn the same quota, but went undetected.

Generalize the detector into one `(inclusion_type, tool_name, signature)`
aggregation carrying a distinct-session set + occurrence count, then flag four
kinds, each with a type-appropriate structural fix:
  * file reads (Read/View/Cat `file_path`) -> `@file` / CLAUDE.md;
  * searches (Grep/Glob/Search query/pattern) -> pin / capture the result;
  * prompts (identical `gen_ai.prompt.content` re-sent) -> save as a
    slash-command / CLAUDE.md note;
  * large tool outputs (identical `gen_ai.tool.output` >= 2K chars re-pasted)
    -> reference the artifact instead of re-running.

Each kind is independently capture-gated by its `[capture]` toggle
(tool_inputs / prompts / tool_outputs), so default-off behavior is unchanged
and a flag-off kind contributes nothing. File reads / searches gate on distinct
sessions (a single session re-reading a file isn't structural); prompts /
outputs re-paste across turns within a session too, so they gate on raw
occurrence count. Framing stays quota-native (#4). Tool outputs are only
captured on the live ingest path, not the on-disk transcript — the nudge note
says so. `RecurringInclusion` now carries `inclusion_type`; the CLI renders a
per-kind tag and the JSON payload round-trips it.

Extends the synthetic fixture to exercise recurring Grep, prompts, and large
outputs, asserting each is detected with frequency + the structural fix, plus a
size-gate test and a per-flag gating test.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
`tj context` (#4) named re-read overhead (cache reads) but not the two
specific large sources #11 asked for: MCP schema-injection and prompt-
cache-miss tokens. This ships the derivable half and parks the other with
a precise note, keeping the honesty discipline (Rule 14) — no invented
attribution numbers.

Cache-miss (DERIVABLE): cache-creation tokens (NormalizedSpan.cache_write_
tokens, from the on-disk usage block's cache_creation_input_tokens) are
input that missed the cache and had to be written to it, billed by
Anthropic at a premium. They were already summed into total_cache_write_
tokens and the composition denominator but never named as their own
overhead category — so the re-read and net-new-work shares silently failed
to sum to 100% whenever cache writes were present. Now surfaced as a
distinct `cache_miss` category: total_cache_miss_tokens / cache_miss_share
on the diagnostic, cache_miss_tokens / cache_miss_share per turn, a new
"Cache-miss:" breakdown line in the card (shown only when non-zero so
default output is unchanged), and corresponding JSON fields.

MCP schema-injection (~25K tok/call) (PARKED): not derivable from current
data. Neither the on-disk transcript nor live spans carry per-tool /
per-schema token attribution — tool-definition tokens are folded into
input/cache-creation, and `mcp__`-prefixed names appear only on tool-
invocation spans (no schema-injection token count). Surfaced as
MCP_INJECTION_PARK_NOTE (a diagnostic note + a JSON field) naming exactly
what data would be needed (a per-request tool-schema token delta) rather
than fabricating a figure.

Tests: extend the synthetic fixture so session B pays a cache-creation
premium; assert the named cache-miss category is computed (core + per-turn
+ JSON), rendered in the card, and that the MCP half is parked with a
precise note. Default-off behavior unchanged. Full suite green
(1207 passed), ruff + mypy clean.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
Add `tj quota-audit` — the accountability companion to opusplan / `/model`.
Those are forward-looking and say nothing about session history; nothing
answered the backward-looking question "which of my PAST Opus sessions were
Sonnet-shaped?". This runs the structural downsize heuristic retroactively,
scoped to Opus sessions, and reports:

- the headline "% of your Opus quota reclaimable from Sonnet-shaped sessions"
  computed as candidate-Opus-tokens / total-Opus-tokens — quota language, not
  dollars (the subscription majority is on a flat fee, so dollar framing
  mis-targets them; implied dollars are a secondary API-only calibration line);
- the specific example sessions to spot-check;
- an optional tuned routing-config export (`--export-config claude-code`,
  reusing the existing snippet generator via a DowngradeFinding shim).

Framed as an audit (quota terms) with the honesty caveat always visible —
"candidates to spot-check, never safe-to-downgrade". Computes purely from
already-backfilled token/model metadata; does not depend on captured content.

`audit_opus_quota()` + `OpusQuotaAudit` / `OpusAuditExample` extend
model_downgrade.py / types.py; framing reuses core/framing (#4 pattern,
window-independent plan mix per #177). Covered by a synthetic-mix test
(Sonnet-shaped Opus candidates vs Opus-shaped Opus vs excluded Sonnet sessions)
asserting the % reclaimable, the spot-check listing, and the caveat render.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
The "tokenmaxxing → tokenminimizing" cultural shift (June 2026) means a
spend-brag card now repels while an efficiency/quota card aligns, and the
subscription majority has no dollar spend to brag about at all. The old card
rendered an (ironic) spend-tier ladder — the wrong polarity.

Reframe the card to a quota/efficiency artifact:
- Lead with the context-COMPOSITION headline from #4's
  compute_context_diagnostic: what share of quota went to overhead (re-reading
  history / CLAUDE.md / tool output) vs real work (uncached input + output).
- Classify into 5 efficiency tiers keyed on the overhead share (lower = leaner
  = a better tier), replacing the 6-tier spend ladder.
- Render quota-native via core/framing, mirroring #5's polarity: headline is a
  token-share / "% of cycle tokens"; dollars are demoted to a secondary
  "Implied API value" line shown only for api plans, suppressed for
  subscription / local / unknown. No dollar spend-brag for subscription users.
- Frame the action line as reclaimable quota (points at tj context).
- Add a --weekly "Quota Wrapped" recap preset (7-day window + recap copy).

The card now needs a direct DuckDB connection (it reads context composition),
matching tj context / tj quota-audit. Tests rewritten to assert the efficiency
framing (composition + reclaimed, not spend-brag) and quota-native suppression
of dollars for a subscription plan, plus weekly mode and the api secondary line.
Updated the two forward-looking release checklists and CLAUDE.md to match.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
Distribution research (adoption.md) is blunt: 15-second-TTFV `npx` tools
dramatically out-adopt 2-minute-install tools, and every high-star CLI in
this niche has sub-30s time-to-first-value. TokenJam's `pipx install` +
launchd/systemd daemon + onboarding is great for power users but measurably
higher friction than `npx ccusage` for the Claude Code crowd — who reach for
`npx` first and whose JSONL tj reads is the very same file ccusage parses.

This ships a no-setup first-run path so a user with zero prior setup runs ONE
command and sees where their Claude Code quota actually goes in well under 30s.

- `tj quickstart` (cmd_quickstart.py): opens a transient InMemoryBackend
  (nothing written to ~/.tj, no config read/written, no daemon started or
  contacted), backfills ~/.claude/projects/*.jsonl into it, then renders quota
  composition (reusing #4's context_diagnostic engine) + a session timeline
  (new core/session_timeline.py). Output leads with ccusage-parity framing.
  Registered in `no_db_commands` so the CLI never opens the on-disk DB / trips
  the daemon lock for it.
- Bare `tj` (no subcommand) routes to quickstart — the group is now
  `invoke_without_command=True`, so `uvx --from tokenjam tj` is one command.
  `--help`/`--version` are eager and still short-circuit.
- `npm-wrapper/`: a dependency-free npm package named `tj` so `npx tj` works —
  a thin launcher that shells out to the Python CLI via the first available
  runner (uvx -> pipx run -> installed tj) and passes args through. NOT
  published here (build + document only).
- Docs: README + docs/installation.md lead with `npx tj` / `uvx --from
  tokenjam tj` as the primary starting point; `tj onboard` stays the opt-in
  "go deeper" (daemon/MCP/live) path.

Honesty discipline (Rule 14) preserved: every figure is a measured token share
re-derived from the JSONL, never a projected saving.

Tests: tests/unit/test_quickstart.py covers the timeline core, the CLI render,
the JSON output, the no-logs branch, and that quickstart + bare `tj` never open
the on-disk DB (open_db patched to raise). Validated with `make all` — ruff +
mypy clean, full suite 1171 passed. `uvx --from <repo> tj` and the npm wrapper
passthrough were exercised locally end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
… flags (#3)

The Claude Code JSONL backfill parser recomputed cost from token/model
metadata but never extracted per-message content or tool-input from the
transcript — even though that data is present and core/transcript.py already
reads it. Because backfill bypasses IngestPipeline/strip_captured_content, the
[capture] toggles were a no-op on the CC path: flipping capture.prompts changed
nothing. This blocked the context-cost diagnostic (#4), which needs per-message
content + inclusion args to attribute tokens.

parse_claude_code_session now accepts a CaptureConfig and, gated per toggle,
populates the assistant LLM span with gen_ai.prompt.content (the triggering
human prompt) and gen_ai.completion.content (the agent narration), and each
tool span with gen_ai.tool.input (the raw args). The keys match GenAIAttributes
so downstream consumers and alert content-stripping treat backfilled content
identically to live content. ingest_claude_code reads config.capture and
forwards it; iter_claude_code_sessions threads it through.

Extraction is strictly opt-in: the None default and the all-False CaptureConfig
default leave every span's attributes byte-for-byte unchanged ({"source": ...}),
so a default backfill is unchanged and stays 100% local. Reuses _block_text from
core/transcript.py for the record-walking.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
Enabling [capture] after a Claude Code session is already ingested never
landed message content / tool_input on the existing rows: the idempotent
INSERT skips on span_id conflict, and the --reingest path updated only
sub_agent_id, leaving the attributes column untouched. So #4's
recurring-inclusion detection (which reads that content) only worked
against a fresh DB.

The --reingest UPDATE now also overlays the freshly-parsed span's
attributes over the stored ones (parsed wins per key) via a small
_merge_attributes helper. This ADDS the content keys
(gen_ai.prompt.content / completion.content / tool.input) without
discarding any keys the stored row already carried (e.g. from live
ingest). Capture-off reingest stays a no-op — the parsed attributes are
just {"source": ...}, which the stored row already has — so it never
wipes content a prior capture-on backfill stored.

Two tests added: (1) ingest with capture OFF, enable capture, re-run with
--reingest -> existing spans now carry content/tool_input, no fresh DB,
no new rows; (2) a capture-off --reingest does not delete previously
stored content.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit to tarun73/tokenjam that referenced this pull request Jul 3, 2026
…s running

`tj context` is the launch-hero command (issue Metabuilder-Labs#4 wedge), but the
composition diagnostic reads the raw `attributes` column for
recurring-inclusion detection — data the API shim never exposed. So
whenever `tj serve` held the DuckDB write lock, the CLI fell back to
`ApiBackend` (no `.conn`) and refused to run, telling users to stop the
daemon on the exact command the launch drives them to.

DuckDB permits only one writer OR many readers across processes (a
concurrent read-only conn alongside the serve write-lock raises an
IOException), so a client-side read-only workaround isn't available.
Route the compute through the daemon instead — which already owns the
direct connection — mirroring `/api/v1/reuse/clusters` (Metabuilder-Labs#154) and
`/api/v1/optimize` (Metabuilder-Labs#68):

  * new `GET /api/v1/context` endpoint computes the diagnostic
    server-side (incl. recurring inclusions from raw `attributes`) plus
    a plan-tier `framing` block, exactly as the CLI's direct-conn path
    does
  * new `diagnostic_from_dict` inverse of `diagnostic_to_dict` so the
    CLI reconstructs the dataclass and renders identically through serve
  * `cmd_context` shim path: on `ApiBackend` (no `.conn`), fetch +
    render via `_render_via_serve`; on a truly non-conn/non-Api backend,
    still surface a clean error (guards on `isinstance(db, ApiBackend)`)

Covered by `tests/integration/test_context_serve.py`:
  * endpoint computes diagnostic server-side, including the recurring
    file-read only surfaceable from raw `attributes`
  * `tj context` (plain + `--json`) renders through an in-process
    ASGI-wired `ApiBackend` — the exact daemon-is-running state
  * a non-conn/non-Api backend still errors cleanly (no traceback)

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant