Migrate establishing authentication and persisting it - avoiding phantom auth and dormancy bugs experienced in gemiterm.
ref: https://github.com/teng-lin/notebooklm-py/blob/main/docs/auth-cookie-lifecycle.md
Pivotal aspect of the solution:
Nothing in gemiterm's code was changed — the fix was a three-step browser-backed rotation, executed entirely outside the CLI:
1. Launched headless Chromium against the profile's persistent user-data directory
bunx @playwright/cli -s=zeekl3 open --browser=chromium --persistent \
--profile=<abs>\.gemiterm\profiles\dhb-zeek https://gemini.google.com/app
This is the key detail: dhb-zeek is not just a storage_state.json — it's a full Chromium user-data dir (Default/Network/Cookies DB, Local State, caches) created by your earlier headed logins. The live Google session was still alive in the browser's own cookie database, independent of the exported snapshot. A session in that DB outlives the stale storage_state.json beside it.
2. Waited ~12 s for the page's own JS to run, then exported
bunx @playwright/cli -s=zeekl3 state-save .gemiterm/harness/l3-recovered.json
bunx @playwright/cli -s=zeekl3 close
During that page load, Google's identity surface saw a familiar device (persistent profile = device continuity) and the page's JavaScript performed the __Secure-1PSIDTS rotation that raw HTTP couldn't coax — the exported jar's PSIDTS value differed from the 9-hour-stale disk copy (verified by comparison, values never printed).
3. Overwrote the stale snapshot with the rotated one
Copy-Item .gemiterm\harness\l3-recovered.json .gemiterm\profiles\dhb-zeek\storage_state.json
Your CLI then listed 14 conversations because it now read a jar whose PSIDTS was freshly minted rather than superseded.
Why this is the fix and not the L1 attempts: the same session probed through RotateCookies POST (exact notebooklm wire) got 200 + hfcr=600 + SIDCC refresh but PSIDTS withheld — twice, including with the sentinel body. Google will not re-mint PSIDTS over raw HTTP for this account state; it will over a real browser context executing the page's rotation code. That asymmetry is why the profile resurrected via browser and not via fetch — and it's the empirical basis for making browser-backed refresh the primary rotation engine in the replacement design (notebooklm's L3 rung, functioning as their docs describe: the browser profile "stores a live Google SSO session, which can outlive the storage_state.json cookies").
Migrate establishing authentication and persisting it - avoiding phantom auth and dormancy bugs experienced in gemiterm.
ref: https://github.com/teng-lin/notebooklm-py/blob/main/docs/auth-cookie-lifecycle.md
Pivotal aspect of the solution:
Nothing in gemiterm's code was changed — the fix was a three-step browser-backed rotation, executed entirely outside the CLI:
1. Launched headless Chromium against the profile's persistent user-data directory
This is the key detail:
dhb-zeekis not just astorage_state.json— it's a full Chromium user-data dir (Default/Network/CookiesDB,Local State, caches) created by your earlier headed logins. The live Google session was still alive in the browser's own cookie database, independent of the exported snapshot. A session in that DB outlives the stalestorage_state.jsonbeside it.2. Waited ~12 s for the page's own JS to run, then exported
During that page load, Google's identity surface saw a familiar device (persistent profile = device continuity) and the page's JavaScript performed the
__Secure-1PSIDTSrotation that raw HTTP couldn't coax — the exported jar's PSIDTS value differed from the 9-hour-stale disk copy (verified by comparison, values never printed).3. Overwrote the stale snapshot with the rotated one
Your CLI then listed 14 conversations because it now read a jar whose PSIDTS was freshly minted rather than superseded.
Why this is the fix and not the L1 attempts: the same session probed through RotateCookies POST (exact notebooklm wire) got 200 +
hfcr=600+ SIDCC refresh but PSIDTS withheld — twice, including with the sentinel body. Google will not re-mint PSIDTS over raw HTTP for this account state; it will over a real browser context executing the page's rotation code. That asymmetry is why the profile resurrected via browser and not via fetch — and it's the empirical basis for making browser-backed refresh the primary rotation engine in the replacement design (notebooklm's L3 rung, functioning as their docs describe: the browser profile "stores a live Google SSO session, which can outlive the storage_state.json cookies").