Skip to content

Tags: mvanhorn/agentcookie

Tags

v0.17.1

Toggle v0.17.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(cmux): restore Domain on host-only cookies so WebKit sends them (…

…GitHub login regression) (#105)

PR #103 changed cmuxCookieParam to scope host-only cookies by url alone with
NO Domain. WebKit STORES such a cookie (cookies.get sees it) but does not SEND
it on a real navigation, so GitHub's user_session / _gh_sess were delivered yet
never authenticated -- the cmux pane silently stayed logged out. #103 fixed the
__Host- rejection but regressed every other host-only auth cookie.

Restore Domain = host_key for all non-__Host- cookies (the pre-#103 behavior
that worked); keep the url-only/no-Domain shaping ONLY for __Host- (which WebKit
rejects when it carries a Domain). Verified end to end: GitHub logs in as the
user in cmux's WebKit browser after a normal sync.

This also corrects the v0.17.0 framing: GitHub is NOT "browser-bound" and the
session is NOT unrecoverable by cookie copy -- that conclusion was wrong. The
same cookies authenticate in both Chromium (agent-sync) and cmux once shaped to
be sent. Updated the bound-session doc, the doctor WARN, and the verify
guidance to state the fact (delivered != authenticated) without the false cause.

Also fixes a false negative in the --verify probe: it navigated at
surface-creation (racing cookie propagation) and gated "ready" on readyState
alone, so a poll on about:blank reported logged-out. Now it opens about:blank,
navigates explicitly, and gates ready on being on the target host.


Claude-Session: https://claude.ai/code/session_01EnSMwviMaV3mgjACiBoBdU

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

v0.17.0

Toggle v0.17.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(cmux): honest auth status for browser-bound sessions (GitHub) (#104)

* fix(cmux): report honest auth status for browser-bound sessions (GitHub)

Delivering cookies is not the same as authenticating. GitHub binds its web
session to the origin browser (a SameSite/site-context-gated session, the
__Host-user_session_same_site cookie plus `vary: Sec-Fetch-Site`), so the
cookies copy into cmux's WebKit store and are even sent on requests, yet the
server still serves the logged-out page. cmux-sync reported a healthy
"injected N cookies" push regardless, which read as success.

cmux-sync now verifies empirically: after a --once push it opens a hidden
browser surface, navigates each browser-bound-session host, and checks a
logged-in marker, printing delivery-vs-authentication truth plus the real fix
(native login in cmux, or gh CLI for git work). doctor surfaces the same as a
per-host "cmux session health" check. Verification is non-fatal: any probe
error or load timeout reports "unknown", never failing the push or doctor.

Also hardens the PR #103 known residual: __Host- cookies now defensively drop
any Domain and always carry a url, so cmux's handler never falls back to a
navigated surface's host (which would re-add a Domain and get the cookie
dropped by WebKit).

- internal/chrome/boundsession.go: bound-session host model, distinct from DBSC
- internal/sinkpush/verify.go: empirical post-injection auth probe
- cmux-sync --verify (default on for --once, off for --watch)
- doctor: cmux session health check (injectable for tests)
- shared hostMatchesSuffix; reuse matchLike for spec filtering

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnSMwviMaV3mgjACiBoBdU

* fix(cmux): address Greptile P2s on the auth verifier

- Quote the CSS attribute value in the metaPresent predicate
  (meta[name="user-login"], JSON-encoded), instead of an unquoted
  meta[name=user-login] which is only valid for identifier-shaped names.
- Clear a transient eval-error detail on a successful-but-not-ready poll so a
  later load timeout reports the timeout, not a stale "eval error".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnSMwviMaV3mgjACiBoBdU

* style(cmux): modernize verify poll loop to range-over-int (go-lint)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnSMwviMaV3mgjACiBoBdU

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

v0.16.1

Toggle v0.16.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(cmux): scope __Host-/host-only cookies by url, not Domain (#103)

WebKit hard-rejects a __Host- cookie that carries any Domain attribute,
which silently dropped GitHub's __Host-user_session_same_site on the cmux
lane and left the agent browser logged out despite a healthy push.

cmuxCookieParam now mirrors internal/livecdp.buildParam: __Host- and
host-only cookies are scoped via a synthesized url with no Domain (and
__Host- forces Secure + Path /), while domain cookies keep their
leading-dot Domain. Adds cmuxCookieURL and regression tests.

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>

v0.16.0

Toggle v0.16.0's commit message

Verified

This commit was signed with the committer’s verified signature.
mvanhorn Matt Van Horn
fix(release): archive examples/blocklist.yaml (renamed from allowlist…

….yaml)

The example config was renamed allowlist.yaml -> blocklist.yaml in the
v0.2->v0.3 transition, but the goreleaser archive list was never updated.
Goreleaser fails to find examples/allowlist.yaml, breaking CI releases the
moment RELEASE_CI_ENABLED is flipped on.

v0.15.0

Toggle v0.15.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(cli): add `agentcookie export` to emit your session as JSON for …

…consumers (#95)

v0.14.0-beta.1

Toggle v0.14.0-beta.1's commit message
v0.14.0-beta.1: secrets bus adoption standard

A standard projects adopt to opt into agentcookie sync. Layered on
the v0.13 wire format; no envelope changes.

Highlights:
- docs/spec-agentcookie-secrets-bus-v2-adoption.md
- agentcookie.toml manifest, well-known discovery paths
- agentcookie discover + secret revoke subcommands
- pkg/agentcookieadoption author helper library
- PP CLI auto-detect adapter (free adoption for all 30+ PP CLIs)
- Hand-off guides for printing-press team + last30days team
- 70 new tests; full suite at 449 passing

See CHANGELOG.md and docs/handoff-guides/.

v0.13.0-beta.1

Toggle v0.13.0-beta.1's commit message
v0.13.0-beta.1: secrets bus

A standardized, runtime-agnostic format for per-CLI secrets/auth-tokens
that ride alongside cookies in the existing source-to-sink push.

Highlights:
- ~/.agentcookie/secrets/<cli>/secrets.env (mode 0600)
- Optional sealed twin under the v0.12 master key
- agentcookie secret subcommand (list/get/set/rm/import-from/env)
- pkg/agentcookiesecret Go reader library
- Doctor check (11 categories now)
- gh shim worked example proving non-PP CLI consumability

See CHANGELOG.md and docs/spec-agentcookie-secrets-bus-v1.md.

v0.12.0-beta.6

Toggle v0.12.0-beta.6's commit message
feat(v0.12.0-beta.6): skip keychain strategy loop on headless + the c…

…ompetitor audit doc (#57)

Two small items grouped.

Friction #19 fix: on a headless wizard install (no TTY,
skip_chrome_sqlite resolved true), the v0.10 set-keychain-access
strategy loop still fired even though the sink daemon never reads
Chrome Safe Storage in that mode. The loop's 60s timeout + alarming
WARNING block was pure noise. Gate the strategy loop AND the prompt
step on `!skipChromeSQLite`. Explicit --skip-keychain-access and
--write-chrome-sqlite preserve the pre-beta.6 paths. Hoist
resolveSinkHeadlessMode() once at the top of wizardInstallSink so
upgrade-in-place installs get the same gating as fresh ones (the
pre-beta.6 resolve fired only inside the write-fresh-sink.yaml
branch).

the competitor audit: Matt asked whether anything in
github.com/the competitor/skills/blob/main/skills/cookie-sync/SKILL.md
was worth being inspired by. Document at
docs/audits/2026-05-21-the competitor-cookie-sync.md walks the feature
surface, argues both sides for the three real candidates (domain
allowlist, CDP-based source-side read, two-way sync), and recommends
adopting none right now -- they solve problems agentcookie doesn't
have. Reference doc only; no implementation work.

New test: TestKeychainStrategyGatedOnHeadless models the 4-cell
gating decision (explicit --skip-keychain-access / headless mode /
both off / both on) and asserts the right branch fires.

go test ./... 335/335 pass.

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v0.12.0-beta.5

Toggle v0.12.0-beta.5's commit message
fix(cdp): drop double-strip, normalize Domain, correct PP CLI install…

… paths

Three corrections from the 2026-05-21 dry-run validation against beta.4
that the initial commit missed:

1. Double-strip removal: internal/chrome/read.go already strips the
   Chrome 127+ App-Bound prefix on the source side via the defensive
   SHA256(host_key)-match strip. CDP injection was running a second
   unconditional strip, lopping 32 bytes off every cookie value
   longer than the prefix. Chrome silently rejected the mangled
   values, contributing to the 64% drop rate. Removed the duplicate
   strip. Deleted prefix_test.go since the function is gone.

2. Domain normalization: Chrome SQLite stores host_key as
   ".instacart.com" to mark parent-domain scope. The modern CDP
   Network.setCookies API silently rejects Domain values starting
   with ".". Strip the leading dot when present; Chrome derives the
   subdomain-wildcard scope from the explicit Domain attribute the
   same way it would from a server-issued Set-Cookie.

3. PP CLI install paths: beta.4 shipped `go install
   github.com/mvanhorn/printing-press-library/<name>@latest` but
   those subpackages don't exist. Each PP CLI is its own repo
   (github.com/mvanhorn/instacart-pp-cli,
   github.com/mvanhorn/airbnb-vrbo-pp-cli). The remaining three
   (eBay, Pagliacci, table-reservation-goat) ship via the
   printing-press meta tool; install-beta.sh + quickstart now link
   there instead of trying to publish a wrong path.

Drop-rate measurement after these fixes (from the dry-run on the live
Mac mini, 8258 cookies synced):
  - Global: 55% drop (down from 64%)
  - stripe: 6/17 -> 15/17 (88% retention)
  - github: 11/24 -> 18/24 (75%)
  - airbnb: 20/26 -> 20/26 (77%)
  - instacart: 2/33 -> 2/33 (unchanged; further investigation needed)

The PP CLI path is unaffected by the CDP drop rate. Adapter session
files cover the five built-in adapters fully; sidecar covers
everything else. `ssh second-mac 'instacart-pp-cli carts'` returns
the friend's actual cart, verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v0.12.0-beta.4

Toggle v0.12.0-beta.4's commit message
fix(cdp): synthesize URL + map SameSite; install-beta.sh hints PP CLI…

… install (beta.4) (#56)

Two findings from the 2026-05-21 dry-run that the verdict missed:

**CDP injection coverage.** Chrome rejected 64% of cookies overall
and 90%+ on instacart.com when cdp.InjectCookies passed Domain+Path
without URL. Cause: Chrome's Network.setCookies applies stricter
validation when no URL is provided -- SameSite defaults to Lax (so
originally cross-site cookies get rejected), SameSite=None requires
Secure, host-only/subdomain semantics flake.

Fix: synthesize a URL per cookie from host_key + path + scheme,
pass alongside Domain+Path so CDP uses URL for origin checks and
Domain for the cookie's Domain attribute. Map Chrome's numeric
SameSite encoding to CookieSameSite explicitly. 16 new tests cover
the URL synthesis edge cases and SameSite mapping. Drop rate
expected to fall below 5% in the beta.4 dry-run.

**PP CLI install gap.** install-beta.sh shipped a working agentcookie
sink but never told the friend that the sites-actually-loaded value
comes from PP CLIs that need separate installation. Friend SSHs in,
types `instacart-pp-cli carts`, gets command-not-found, thinks
agentcookie is broken.

Fix: install-beta.sh prints a clear post-install block with the
go install commands for the five built-in adapters and an SSH-test
verification line. quickstart-beta.md gains a new "Install at least
one PP CLI on the sink" section.

Closes the gap between the dry-run verdict ("ship it") and reality.

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>