Skip to content

v0.10.3

Latest

Choose a tag to compare

@github-actions github-actions released this 27 Aug 17:28
· 9 commits to main since this release
fbf97d9

Added

  • Subagent work now survives into committed checkpoints, for every agent that reports subagent completion: Claude Code, Codex, Cursor, Copilot CLI, and Factory AI Droid. 0.10.2 shipped the in-session half and noted that committed checkpoints still carried no per-subagent data for any agent — this is the durable half. A subagent's work becomes a task_records ledger on the parent session, and condensation materializes each record's transcript into tasks/<tool-use-id>/ inside the parent session's checkpoint, so every checkpoint is self-contained; the ledger, the materializer, and the commit linkage are all agent-agnostic. Commits a subagent makes between the parent's turns link to their session too, instead of shipping with no Entire-Checkpoint trailer at all — six of seven commits on a real subagent-driven branch had gone unlinked. The one agent-specific piece is Claude Code's SubagentStop hook, now registered: a backgrounded Task fires PostToolUse at the launch acknowledgment, before the subagent has done anything, so a session that dispatched 29 background agents running 5–18 minutes each had captured nothing but a launch stub per agent. Gemini CLI, OpenCode, and Pi expose no subagent hook and are unchanged (#2032, #2034)
  • An agent's commit links to its session by who made it, not by worktree path: the owner fingerprint already recorded at every turn start is matched against the commit hook's own process ancestry, so a commit made in a sibling worktree links automatically with no entire session adopt. Nearest ancestor wins for nested agents, host/boot/start-time guards defeat PID reuse, and a human commit typed in the same terminal still never matches. Identity is unioned with worktree matching, never a replacement; on Windows, where the process walk is unavailable, linking is unchanged (#2013)
  • Zombie sessions self-heal instead of waiting for someone to run entire doctor. The session-start hook cheaply detects sessions whose agent died without a stop hook, or that have been sitting on uncondensed checkpoint data for over 24h, and fires a detached __sweep_sessions that finalizes and condenses them — one real session had been stuck for 4 days with 60 checkpoints, slowing every commit in the meantime. The hook's own timeout budget is untouched regardless of backlog (#2029)
  • Teams can choose which secret-scanner engines feed redaction, via redaction.betterleaks.enabled and redaction.goredact.enabled in committed .entire/settings.json. Defaults are unchanged (betterleaks on, goredact off), the keys are deliberately ignored in settings.local.json — the choice affects everyone who reads the repo's checkpoints — and disabling both fails settings load rather than shipping unscanned content. If the sole enabled engine fails at runtime, transcript writes fail closed instead of persisting under-scanned data (#2081)
  • entire doctor trace --summary aggregates hook traces into per-hook p50/p90/max with the dominant step, and --slow narrows to the slow ones — the question with slow traces accumulating is "what is slow in general", which previously meant hand-rolling a grep over .entire/logs. The command's help no longer claims traces need DEBUG to be enabled; they have been emitted at WARN by default since 0.10.1 (#2092)
  • Redaction diagnostics reach .entire/logs and entire doctor reports a log directory Entire cannot write to. Pack load failures, rule compile errors and sample mismatches went to the process-default logger — bare stderr, which hook contexts swallow — so a user debugging custom rules could grep for component=redaction, find nothing, and reasonably conclude the rules never ran. There is now also one INFO summary per process naming pack/rule/inline counts and PII/OPF state, and an unwritable .entire/logs is called out by name instead of presenting as a silent exit 0 (#1973, #2082)
  • entire trail update --body sends the description's ETag as If-Match, so a body write is rejected rather than silently clobbering a description that changed since it was read. --overwrite writes unconditionally, and a server or trail without an etag degrades to the previous behavior (#2079)
  • Telemetry gained three content-free signals, all gated on the same opt-in setting and ENTIRE_TELEMETRY_OPTOUT: cli_skill_invoked for skill invocations (skill name from a closed vocabulary — no prompt text or arguments), cli_commit_condensed for whether a commit landed files already carrying AI checkpoint history without the session ever consulting search, and cli_search_completed for whether a search actually returned a usable response rather than just that it ran (#2023, #2024, #2100, #2130)

Changed

  • The search TUI scrolls continuously instead of paging 10 results at a time — commit search reads like a pruned git log, and the next API page loads automatically as you approach the end. Type tabs move on ←/→ (or tab/shift+tab) with wraparound; the 1-3 number keys are gone, and the status row reports N of M results instead of page X/Y (#2138)
  • CLI search results match the web's. Per-cell responses were always identical — only the client-side merges diverged: the CLI cut the merged list globally at 100 where the web windows per type, reported summed corpus counts up to 13× larger, deduped every type where the web dedupes sessions only, and dropped every completeness flag. Counts now describe exactly what you can see (with a + when lower-bounded), incomplete results are labeled rather than silent, and the retired ANN fallback tail no longer renders (#2090)
  • A logged-out git pull against a cluster now names one login server — entire login — instead of printing a list of seven hosts and leaving you to pick, three of which were not login servers at all. Staging still names --server where the flag is genuinely required (#2128)

Security

  • task.json's task_description — the free text an agent writes when dispatching a subagent — was copied verbatim into the pushed checkpoint while the subagent transcript beside it went through the full sanitize → externalize → redact pipeline. The checkpoint writer now redacts it, covering both persistent backends (#2129)
  • betterleaks moves to 1.8.0, which closes a real under-redaction gap: a bare password=<secret> assignment previously escaped every layer. Validated with an A/B diff over 22 real checkpoint transcripts (64MB) — 21 byte-identical, one file with five safe-direction over-redactions of test-fixture passwords, zero under-redactions. The upstream dependency swap also makes the transcript redaction path 1.36× faster and shrinks the binary (#2042)

Fixed

  • Every git status Entire runs now passes --no-optional-locks. git status is a write: it refreshes the index's stat cache, holds .git/index.lock for the whole worktree walk, and renames a fresh index over .git/index. Entire read the porcelain output once and discarded it, so that write bought nothing — but on a filesystem where rename-over-existing is not atomic against a concurrent lookup (virtiofs / gRPC-FUSE bind mounts, i.e. Docker Desktop devcontainers — measured at 9.9% ENOENT across 29,596 opens, versus 0 on ext4) a reader can observe .git/index missing, and git treats ENOENT, and only ENOENT, as an empty index: a git commit landing in that window records the empty tree with exit 0 and no warning. Output is byte-identical with the flag. This removes Entire's contribution rather than the hazard — any concurrent git status on an affected mount opens the same window, including several agents working one repo, and the environment-wide mitigation is GIT_OPTIONAL_LOCKS=0 (#2143)
  • A Stop hook on a large transcript no longer re-redacts the whole thing. Redaction was 99.7% of the blob write, and because full.jsonl is append-only but was re-redacted in full at every checkpoint, a session with N checkpoints re-redacted O(N²) bytes — a 70MB Codex transcript took ~67s. The line pass is now sharded across goroutines (byte-balanced, output byte-identical) and the previous checkpoint's redacted prefix is reused, so only appended lines are redacted: ~66s → 2.0s on a simulated 14-checkpoint session. The same reuse now covers post-commit condensation and the Stop finalize rewrite, which had been left out — a coworker was hitting Codex's 30s Stop-hook timeout on a 65MB rollout and losing the checkpoint's final transcript rewrite to the kill (#2002, #2107)
  • A pathological repo can no longer leave orphaned hook processes grinding for hours. A stray git init in a user's $HOME meant every Stop hook walked the entire home directory: the agent stopped waiting at its ~60s hook timeout but the entire process survived, and two were found hours later at ~1.8GB RSS each, one with 25 CPU-minutes, still writing loose objects — silently, with no session state, no checkpoint, and no log line. Agent-hook status walks are now bounded by a 20s wall-clock budget with a process-local latch, the unbounded git status subprocess on the first-checkpoint path is bounded the same way, capture degrades to transcript-derived data instead of failing the turn, and entire status reports the degradation instead of showing a healthy session with new-file detection silently off (#1977)
  • Session-end condensation could write a checkpoint durably before saving its updated session state, so a hook killed in that window left recovery thinking the transcript was unfinished — and entire doctor would write it again under a different checkpoint ID. Condensation now reserves its checkpoint ID write-ahead and reuses it on retry, and doctor reconciles interrupted writes from older CLI versions by session identity and transcript bounds rather than minting a new ID. Existing duplicate pairs are deliberately left in place (#2038)
  • entire disable --uninstall reported success while leaving an external agent's hooks on disk — the uninstall reached agents only through the registry and never ran external-agent discovery, so the plugin was absent from the confirmation summary and its UninstallHooks never ran, leaving agent hooks calling into an Entire that was no longer installed. Discovery is now ungated (the setting that would gate it lives in the .entire/ this command deletes), AreHooksInstalled distinguishes "no hooks" from "cannot tell" instead of collapsing both into "none", and any step that fails exits non-zero with a per-agent remedy rather than claiming a success it could not verify (#2010)
  • Cursor's file attribution used the transcript. Six places in the Cursor agent asserted as fact that Cursor transcripts contain no tool_use blocks — a real session has 26 of them — so ExtractModifiedFilesFromOffset returned nothing and every session fell back to git status while real Write/StrReplace blocks sat unread. Shell stays excluded, since the transcript records only the command string (#2120)
  • Imported Cursor session titles no longer read <timestamp>Tuesday, Aug 18, 2026, 2:37 PM…</timestamp>; Cursor's injected block is stripped by the single shared prompt cleaner, fixing live and imported prompts at once (#2045)
  • Codex 0.149.0 can load project hooks from a different checkout than the one it runs in, so a linked worktree's own .codex/hooks.json was silently not the file Codex used. entire doctor and entire status now report the discovered path alongside the current worktree's, while installs, removals and cleanup still touch only the checkout the command was invoked from (#2052)
  • OpenCode hooks fire under OpenCode Desktop: the plugin spawned via Bun.spawn, which does not exist in the Electron sidecar's Node runtime, and now uses node:child_process so both the Bun CLI/TUI and Desktop work (#2018)
  • entire session attach <id> --agent opencode works for sessions Entire never tracked. Preparation was only attempted when a transcript file already existed, but OpenCode produces its transcript on demand via opencode export for any session in its store — so a session spawned outside a hooked terminal could not be attached at all. A new optional agent capability materializes the transcript on demand; file-based agents are unaffected (#1877)
  • Search routed each repo to every placement it has, home and mirrors alike, so a multi-region repo returned the union of all its namespaces — 100 rows against the web's 6 on one measured query, 94 of them duplicate or stale mirror rows. Each repo now routes to exactly one home placement, and a home placement that is not ready is reported as skipped rather than substituted with a mirror (#2044)
  • entire search --json --compact no longer emits a repo description; its only source was the legacy MySQL repos table, which is gone server-side, so the field could never be populated again. checkpointCount stays, re-sourced from core (#2125)
  • entire trail create delivered the trail's branch to a hardcoded origin in four places with nothing warning, so a fork workflow, remote.pushDefault, or branch.<name>.pushRemote all sent it to the wrong remote. Delivery now resolves through git's own precedence, once, so push and cleanup cannot disagree (#2086)
  • entire enable showed only six of its eight agents, hiding OpenCode and Pi below the initial viewport even on a tall terminal — a huh height-sizing bug, worked around here for single-line multi-select fields while the library fix is handled upstream (#2132)
  • entire doctor without a TTY crashed on a stuck session instead of reporting it: the fix prompt went straight to an interactive select, bubbletea failed with could not open TTY, and the whole scan aborted mid-report with exit 1. It now prints the diagnosis with a --force hint and completes the scan (#2015)
  • Checkpoint reads on a partial clone no longer hammer the remote one blob at a time. entire checkpoint explain could trigger a Git lazy fetch per missing blob per promisor remote before reaching its own batched prefetch, so blob-existence probes and fallback reads now set GIT_NO_LAZY_FETCH=1, and the probe settles a whole candidate set with one git cat-file --batch-check rather than one subprocess per blob. Two hook paths — post-commit attribution and the stop hook's turn finalize — opened the checkpoint store with a ref fetcher and no blob fetcher, so with lazy fetch off a filtered-out metadata.json read as "checkpoint not found": attribution was skipped, the finalized transcript never reached its checkpoints, and nothing above DEBUG said why. Both now carry a blob fetcher bounded by a 15s whole-call budget with non-interactive SSH, memoized so a dead network costs one budget per store instead of one per checkpoint (#2141, #2145, #2146)
  • Telemetry payload building no longer shells out once per event. The machine ID is resolved via ioreg on macOS (p50 11.8ms), the registry on Windows, and nothing cached it — so a hook draining a 20-event skill backlog paid 217ms of blocking subprocesses in the parent. It is now resolved once per process, dropping ~11.6ms from every command that builds an event (#2101)
  • The committed SessionStart hook in .claude/settings.json left ${CLAUDE_PROJECT_DIR} unquoted, so any checkout whose path contains a space failed on every session start (#2139)
  • Every control-plane request went out as Go-http-client/2.0, not entire-cli/<version> — so entire org|project|repo|grant|search|api|auth traffic was invisible to server-side CLI version gating, along with cluster discovery, the cluster catalog GET, and plugin release-asset downloads. The User-Agent is now stamped at the client constructors, innermost in each transport chain so the token-exchange and federation hops carry it too (#2096)

Housekeeping

  • mise run lint no longer rewrites source. The local path passed --fix, which made the documented pre-commit sequence a mutating command — it could strip a //nolint directive, report 0 issues, and fail on the next run with the deprecation the directive was suppressing. Rewriting stays with mise run fmt (#2117)
  • This repo's committed dogfood hook configs are now checked against their templates on the CI path, using the same drift check entire doctor already runs. The committed Pi extension had sat two commits behind its template for three weeks, silently forwarding a subagent's lifecycle as the user's session (#2084)
  • A Cloud Agent development environment boots with the pinned toolchain, the CLI built, and entire on PATH so this repo's committed hooks fire (#2114)
  • Two CI flakes removed at the mechanism rather than the probability: a Text file busy (ETXTBSY) fork race on test-written fake binaries, now linked instead of written, and the Factory Droid E2E tests, which had polled shadow branches for task data that #2032 stopped writing and had failed on every push to main since (#2094, #2095)
  • The logger is closed in one place (main.go, which covers the error paths cobra's post-run loop skips), the security-review runner prompt is reframed around an engineer who owns the codebase rather than a checklist auditor, and three docs corrections landed: the ref-backend doc no longer lists pre-push OPF among the paths the primary backend drives, the log-flush comments point at main.go, and phone PII redaction is qualified as North American (NANP) formats only (#1914, #2083, #2093, #2097, #2110)
  • The gemini-cli E2E leg is dropped from the automatic agent fan-out, where it had been reddening main on every push; it stays in every workflow_dispatch choice list so it can be run by hand against a newer release. This turns off the alarm, not the bug — since Gemini CLI 0.57.0 the agent forces core.hooksPath='' on every shell command it runs, so a commit the agent makes records no checkpoint, and no change on Entire's side can win that back (#2147)
  • Go dependencies bumped as a group: bubbles 2.2.0, bubbletea 2.0.9, betterleaks 1.8.1, posthog-go 1.23.1, testify 1.12.1, x/mod 0.40.0, x/net 0.58.0 (#2118)

Thanks

Thanks to @Legonaftik for making entire session attach work for OpenCode sessions Entire never tracked, @sdshah09 for fixing OpenCode hooks under OpenCode Desktop's Node sidecar and qualifying the phone PII pattern as NANP-only in the docs, and @MuskanPaliwal for preventing duplicate session-end checkpoints, making Codex hook discovery honest in linked worktrees, and unhiding OpenCode and Pi in the agent picker!