Skip to content

v0.9.0

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 25 May 21:15
· 53 commits to main since this release

Highlights

Bundles three improvement loops landed since 0.8.0 (37-iter context/compaction on 2026-05-25, 68-iter reliability/perf on 2026-05-24, 55-iter context-savings baseline).

Security

  • DNS-rebinding window closed in SSRF guard: webfetch.py resolves once and pins the connection to that IP via a custom transport, so a hostile DNS server can't return a public IP to validation and a private IP (e.g. 169.254.169.254 IMDS) to the reconnect.
  • paths.safe_join() promoted as the canonical fragment joiner; two raw joins that took user-controlled session_ids now flow through it.
  • dispatch() ensures continue=true so handlers returning {} can't become harness-blocking responses.
  • webfetch sidecar path-traversal fix: validates that shrunk_path resolves inside the cache roots before writing.
  • PIL decode-bomb cap: MAX_IMAGE_PIXELS set to prevent multi-gigapixel decompression crashes.

Reliability

  • Hook registry consolidated to single source of truth (hook_registry.py); a startup _assert_hook_registry_aligned() raises ImportError if any event lacks a @hook_app.command decorator. Eliminates the recurring registry drift bug class.
  • Persistent hook wrapper at data_dir/bin/tg-hook.cmd survives uv tool install --reinstall; emits {"continue":true} and exits 0 when the venv is briefly absent.
  • paths.ensure_dir() retry helper for the Windows mkdir(parents=True, exist_ok=True) race where is_dir() returns stale False after a concurrent create.
  • Surrogate-escape crash fix in post_bash (1,311 crashes/week in production).
  • Orphaned project GC: reclaims 2.3 GB on the audited install with a 30-min safety window.
  • Session lock hardened: 5 s timeout, jittered poll backoff, fsynced PID write, rejects invalid PIDs.
  • Worker SIGTERM-aware drain loop via _GRACEFUL_SHUTDOWN event.
  • Hook crash log at hooks-stderr.log (100 KB cap, .prev rotation).
  • Concurrent dirty-queue write protected by fcntl/msvcrt locks.
  • Session CAS re-applies size caps after merge so a race can't inflate the JSON beyond limits.
  • Hooks stderr log test isolation: 230 KB / 316 crash blocks of test garbage were polluting the production sink.

Token savings — manifest, hints, hot path

  • Manifest format shortening: L:X-Y instead of lines X-Y, bash entries drop id=/shorten exit= to e=, lower _MAX_TODO_SUBJECT_CHARS (~71 tokens/manifest).
  • Active-skills section collapsed to a single line (**Skills:** name1, name2 — recall via ...) (~160 tokens/6-skill manifest).
  • Manifest Delta line: +sections that grew since last compact.
  • Bash entries grouped by exit class (Failed/Slow/Ok); suppresses TODOs that reference edited files.
  • Manifest bold-label bundle: ### Edited:**Edited:**, **Syms:** for inline labels.
  • Manifest SHA sidecar cache: pre_compact writes a sentinel and rebuilds only when the session SHA differs.
  • Cross-session grep dedup via global.db::grep_patterns.
  • Adaptive _MAX_BASH_ENTRIES scales with bash_history length.
  • Clean-repo session brief collapses to <branch> (clean) one-liner.
  • status_lines cap (50 + (+N more files)).
  • Single rev-list + adaptive git-log entry count; in-sync repos skip the git-log section.
  • WebFetch HTML strip before caching (60-90% byte reduction).
  • Process-local LRU on session.load() (cap 4, mtime-keyed).
  • Pre-Read structured-file hint (CSV headers, JSON top-level keys, log entry count) ~70% smaller.
  • Pre-Read index-only file suppression (lockfiles, source maps, build artifacts).
  • AVIF image-shrink support (~15% smaller than WebP when libaom available).
  • Hint fingerprint includes file path to prevent false positives across files.
  • Session-level hint budget caps (files 5, bash 3, web 2, skills 4).

Performance

  • Test suite 22% faster: eviction tests use patch.object(session, "save") instead of 200-500 real disk writes.
  • Hook cold-start: 190 ms → 110 ms (~42% faster) via lazy imports in hooks_session.py.
  • Compact-skip sentinel: <1 ms exit on fresh sessions when no edits since the last manifest.
  • Skip git ops entirely when cwd is not a repo (saves 60-100 ms per hook fire in non-repo dirs).
  • DB contention metric surfaced in doctor.
  • pytest-xdist --dist=loadscope for module-scoped fixture reuse across tests.

DRY

  • 16 git subprocess sites consolidated through util.run_git() (always --no-optional-locks + UTF-8 with errors="replace").
  • cache_common.safe_cache_op context manager + store_blob for atomic blob writes + short_content_hash() shared across bash/web/skill caches.
  • paths.safe_join(), paths.hook_wrapper_path(), paths.normalize_key() promoted as canonical helpers.
  • util.sanitize_surrogates, util.humanize_bytes, util.ellipsize cross-module helpers.
  • Session 6-item helper bundle (safe_load, _merge_lists, _cap_dict, _bump_read_count, _session_path, _atomic_write).

Codex / opencode / openclaw compatibility

  • Wire-format round-trip tests for every hook event across all four harnesses (Claude / Codex / opencode / openclaw); bridge TS event-table alignment regression test.
  • PowerShell bash_parser coverage: Get-Content, gc, type ambiguity guard, equals-form flags.
  • Bash dispatch + golden-output tests (+151) across all 17 compression filters.

CI

  • Workflow split into gating fast tier (-m "not slow") + opt-in slow tier with continue-on-error: true so racy multi-process stress tests don't block the build.

Suite at end of loop: 5051 pass / 28 skipped (started this release cycle at 4598; +453 tests added).

Full details in CHANGELOG.md.