# Overview

> What agentcookie replicates between two Macs, the three cookie delivery surfaces, the parallel secrets bus, and the shortest source-backed path through these docs.

- Repository: mvanhorn/agentcookie
- GitHub: https://github.com/mvanhorn/agentcookie
- Human docs: https://grok-wiki.com/public/docs/mvanhorn-agentcookie-137da38edfae
- Complete Markdown: https://grok-wiki.com/public/docs/mvanhorn-agentcookie-137da38edfae/llms-full.txt

## Source Files

- `README.md`
- `docs/architecture.md`
- `cmd/agentcookie/main.go`
- `internal/cli/root.go`
- `CHANGELOG.md`

---

---
title: "Overview"
description: "What agentcookie replicates between two Macs, the three cookie delivery surfaces, the parallel secrets bus, and the shortest source-backed path through these docs."
---

agentcookie is a macOS-only daemon and CLI that one-way-replicates Chrome session state and per-CLI auth secrets from a "source" Mac (the laptop you log in on) to a "sink" Mac (where agents act on your behalf). The source watches Chrome's `Cookies` SQLite with `fsnotify`, decrypts each row with the local Keychain-backed Safe Storage key, wraps the result in a versioned `SyncEnvelope`, AES-256-GCM-seals it under a per-peer pairing key, and POSTs it over the Tailscale tailnet to the sink's `/sync` endpoint. The sink validates the envelope, then fans the payload out across three cookie delivery surfaces and a parallel secrets bus so any unmodified or agentcookie-aware tool can read the synced session.

The unified entry point is `cmd/agentcookie/main.go`, which dispatches to the cobra tree wired in `internal/cli/root.go`: `source`, `sink`, `pair`, `status`, `version`, `wizard`, `doctor`, `secret`, `discover`, `cookies`. Configuration lives under `~/.config/agentcookie/` (`source.yaml`, `sink.yaml`, `allowlist.yaml`); paired per-peer keys live at `~/.config/agentcookie/keys/<peer>.json` mode `0600`; sink-side runtime state lives under `~/.agentcookie/`.

## What agentcookie replicates

| Surface on source | Carried in envelope | Surface on sink |
|---|---|---|
| Chrome `Cookies` SQLite (Default profile, decrypted via macOS Keychain Safe Storage) | Filtered + sealed cookie set | Re-encrypted into sink Chrome `Cookies` + plaintext sidecar + per-CLI adapter files |
| `~/.agentcookie/secrets/<cli>/secrets.env` (mode `0600`, watched by `fsnotify`) | Per-CLI `KEY=VALUE` secrets payload | Mirrored to identical path on sink; optional sealed twin under v0.12 master key |
| `agentcookie.toml` manifests discovered under user dirs and project roots | Materialized `[[files]]` blobs | Files materialized at declared `env`/path on sink |

The push is one-way: source → sink. There is no merge, no destination prompt, no GUI click after install. Filtering happens on both sides via `allowlist.yaml`, and a `SequenceTracker` in sink memory rejects equal-or-lower envelope sequences.

## Sync lifecycle

```mermaid
sequenceDiagram
    autonumber
    participant Chrome as Chrome (source Mac)
    participant Bus as secrets bus<br/>(~/.agentcookie/secrets)
    participant Src as agentcookie source<br/>(LaunchAgent watcher)
    participant Net as Tailscale tailnet<br/>(AES-256-GCM over HTTP)
    participant Sink as agentcookie sink<br/>(LaunchAgent on :9999)
    participant Out as Sink delivery surfaces

    Chrome-->>Src: fsnotify(Cookies SQLite) + debounce
    Bus-->>Src: fsnotify(secrets.env) + manifest scan
    Src->>Src: read SQLite RO, decrypt Safe Storage,<br/>filter by allowlist, build SyncEnvelope (v1)
    Src->>Net: POST /sync (sealed with per-peer key)
    Net->>Sink: deliver bytes
    Sink->>Sink: open seal (401 on key mismatch)<br/>check ProtocolVersion==1 (400)<br/>check Sequence (409 on replay)<br/>filter against sink allowlist
    Sink->>Out: 1) Chrome SQLite (re-encrypt with sink key)
    Sink->>Out: 2) ~/.agentcookie/cookies-plain.db sidecar
    Sink->>Out: 3) per-CLI adapter session files
    Sink->>Out: 4) ~/.agentcookie/secrets/<cli>/secrets.env
```

## The three cookie delivery surfaces

The sink runs all three after every successful sync; consumers pick the surface that matches how they read cookies.

<CardGroup cols={3}>
  <Card title="1. Real Chrome Default profile" href="/universal-delivery">
    Re-encrypts each cookie under the sink's Chrome Safe Storage key and upserts into the sink's `Cookies` SQLite (schema-aware INSERT … ON CONFLICT). At install, one login-password entry opens Safe Storage for the `apple-tool:`, `apple:`, and `teamid:<your-team>` partitions so any unmodified cookie reader (yt-dlp, gallery-dl, browser-driving agents) sees a logged-in Default profile. This is the universal default.
  </Card>
  <Card title="2. Plaintext sidecar" href="/cookie-delivery-surfaces">
    Decrypted cookies written to `~/.agentcookie/cookies-plain.db` for agentcookie-aware consumers that prefer not to touch Chrome. Toggleable via `AGENTCOOKIE_PLAIN_COOKIES`. Works in degraded mode when no Keychain password is available.
  </Card>
  <Card title="3. Per-CLI adapter fan-out" href="/cookie-delivery-surfaces">
    Built-in adapters write the shape each PP CLI expects: `instacart` and `table-reservation-goat` → `session.json`; `airbnb`, `ebay`, `pagliacci` → `config.toml` + `cookies.json`. New adapters are ~50 lines plus a `Register()` call.
  </Card>
</CardGroup>

## The parallel secrets bus

Bearer tokens, API keys, and other `KEY=VALUE` auth blobs ride the same encrypted push the cookies do. On the sink they land at:

```text
~/.agentcookie/secrets/
  <cli>/
    secrets.env        # mode 0600, KEY=VALUE per line
    secrets.env.sealed # optional twin under the v0.12 master key
    manifest.toml      # optional per-key sync overrides
```

Three adoption tiers coexist for opting a CLI into bus-driven sync:

| Tier | How it works | When to use |
|---|---|---|
| explicit-manifest | Drop `agentcookie.toml` with `[secrets]`, `[aliases]`, `[[files]]`; `agentcookie discover` picks it up | First-class adoption for new or external CLIs |
| pp-cli-derived | Auto-synthesized in memory from a CLI's existing `.printing-press.json` (`auth_env_var_specs`) | Printing Press CLIs that ship today with no manifest |
| legacy-v1 | Existing `~/.agentcookie/secrets/<cli>/` directories continue to work; `agentcookie secret import-from` still imports JSON/TOML/env into the standard layout | Pre-v2 setups; ad-hoc imports |

Consumers read the bus three ways: shell env (`eval "$(agentcookie secret env <cli>)"`), the in-process Go library `pkg/agentcookiesecret`, or a CLI's own `agentcookie.toml` `[[files]]` materialization.

## Security boundaries at a glance

| Boundary | Enforced by |
|---|---|
| Cookie value at rest | Chrome Safe Storage per-machine AES key + Keychain ACL |
| Cookie value in transit | AES-256-GCM with per-peer pairing key + Tailscale WireGuard |
| Pairing authenticity | X25519 + HKDF-SHA256 with the base32 pairing code mixed into the salt |
| Listener exposure | Tailnet-only bind validation in `sink.yaml`; pair endpoint rate-limited with a 64-bit code |
| Replay defense | Monotonic `Sequence` checked by sink `SequenceTracker` (HTTP 409 on regress) |
| Protocol stability | `ProtocolVersion` field on every envelope (HTTP 400 on mismatch) |
| File mode discipline | `0600` on `keys/*.json`, `secrets.env`, sealed twins |

For device-bound cookies (DBSC), the source flags suspect rows and by default ships them with a warning; pass `--skip-dbsc-suspect` or set `AGENTCOOKIE_SKIP_DBSC_SUSPECT=1` to drop them. The secrets bus is untouched by DBSC.

## What's in the box

<Tabs>
  <Tab title="Commands">
    | Command | Role |
    |---|---|
    | `agentcookie source` | Long-lived watcher or `--once` push from the laptop |
    | `agentcookie sink` | Long-lived `/sync` listener on the second Mac |
    | `agentcookie pair` | X25519 + HKDF pairing handshake |
    | `agentcookie wizard install` | Drops configs, pairs, installs LaunchAgents, opens Safe Storage |
    | `agentcookie doctor` | Fifteen health categories; `--json` for agents |
    | `agentcookie status` | Last sync, sequence, peer state |
    | `agentcookie secret` | `list`/`get`/`set`/`rm`/`revoke`/`import-from`/`env` |
    | `agentcookie discover` | Walk for `agentcookie.toml` manifests |
    | `agentcookie cookies` | Inspect the synced cookie store |
    | `agentcookie version` | Linked-in `Version` string |
  </Tab>
  <Tab title="Module layout">
    ```text
    cmd/agentcookie/         CLI entry (cobra)
    internal/cli/            Subcommand implementations
    internal/chrome/         Read + decrypt + schema-aware write of Chrome Cookies
    internal/cdp/            Chrome DevTools Protocol client (Storage.setCookies)
    internal/transport/      AES-GCM seal/open
    internal/pairing/        X25519 + HKDF pairing handshake
    internal/keystore/       Per-peer key file management
    internal/protocol/       SyncEnvelope, SequenceTracker, AllowlistMatcher
    internal/config/         YAML loaders (source.yaml, sink.yaml, allow/blocklist)
    internal/secretsbus/     fsnotify watcher + on-disk layout for secrets
    internal/sinkpush/       Adapter registry + delivery fan-out
    internal/launchd/        LaunchAgent plist generation + bootstrap
    internal/tsclient/       Tailscale tailnet checks
    internal/watcher/        Debounced fsnotify for cookies + secrets
    pkg/agentcookiesecret/   In-process Go reader for the bus
    ```
  </Tab>
  <Tab title="On-disk layout">
    ```text
    ~/.config/agentcookie/
      source.yaml            sink URL, peer hostname, watch options
      sink.yaml              listen address, Chrome paths, sealing posture
      allowlist.yaml         SQLite-LIKE host patterns
      blocklist.yaml         negative patterns
      keys/<peer>.json       per-peer pairing key (mode 0600)

    ~/.agentcookie/
      cookies-plain.db       plaintext cookie sidecar
      secrets/<cli>/
        secrets.env          KEY=VALUE per line (mode 0600)
        secrets.env.sealed   optional sealed twin
        manifest.toml        optional per-key overrides
    ```
  </Tab>
</Tabs>

## Source-backed paths through these docs

<CardGroup cols={2}>
  <Card title="Install on two Macs" href="/installation">
    Prereqs, `go install`, and the `agentcookie wizard install` flow that pairs both sides and installs LaunchAgents.
  </Card>
  <Card title="Five-minute quickstart" href="/quickstart">
    Configs + pair + push + verify with `agentcookie doctor`.
  </Card>
  <Card title="Headless second Mac" href="/headless-install">
    SSH-only install, degraded-mode fallback, and the `wizard set-keychain-access` upgrade path.
  </Card>
  <Card title="Source and sink topology" href="/source-sink-topology">
    The one-way model, role split, and what each side reads and writes.
  </Card>
  <Card title="Cookie delivery surfaces" href="/cookie-delivery-surfaces">
    The three sink-side delivery paths in depth.
  </Card>
  <Card title="Secrets bus" href="/secrets-bus">
    How bearer tokens, API keys, and KEY=VALUE blobs ride the push.
  </Card>
  <Card title="Pairing and per-peer keys" href="/pairing-and-keys">
    X25519 + HKDF-SHA256 handshake and the per-peer key files.
  </Card>
  <Card title="DBSC handling" href="/dbsc-handling">
    Detection, default warn-and-ship, and `--skip-dbsc-suspect`.
  </Card>
  <Card title="Wire protocol v1" href="/wire-protocol">
    `SyncEnvelope`, sink validation order, and 401/400/409 semantics.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Every `agentcookie` subcommand and its flags.
  </Card>
  <Card title="Configuration files" href="/config-files-reference">
    Schemas for `source.yaml`, `sink.yaml`, `allowlist.yaml`, `blocklist.yaml`.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Pairing `connection refused`, sink Keychain prompts, stale `SingletonLock`, DBSC-suspect drops.
  </Card>
</CardGroup>

## Status snapshot

Working today on macOS for both ends: continuous laptop-to-second-Mac sync with debounced `fsnotify`; the three cookie delivery surfaces; the secrets bus with sealed twin; v2 adoption manifests and `agentcookie discover`; tailnet-only listeners and rate-limited pairing; persistent replay defense; Developer ID signed binaries with `teamid:` partition trust; headless SSH install with degraded-mode fallback; fifteen-category `doctor`; 520+ unit tests across 26 packages. Not yet shipping: a Python reader at `clients/python/agentcookie_secret`, manifest signature verification (`signed_by` reserved for v2.1), `[secrets.command]` / `[secrets.keychain]` source kinds, `agentcookie pair --rotate` (re-run `wizard install` instead), and many-sink fan-out.

## Next

<CardGroup cols={2}>
  <Card title="Installation" href="/installation">Prereqs and `go install` flow.</Card>
  <Card title="Quickstart" href="/quickstart">Five-minute laptop + second-Mac pairing.</Card>
  <Card title="Source and sink topology" href="/source-sink-topology">Mental model for the one-way replication.</Card>
  <Card title="CLI reference" href="/cli-reference">Every subcommand and flag.</Card>
</CardGroup>
