Inspiration

When your teammate finishes a Claude Code or Codex session, the context they built up dies with the session. The next AI session — yours, theirs, anyone's — starts from zero. You re-explain. You re-discover. Knowledge gets siloed inside ephemeral conversations.

What it does

Handoff sits inside your AI CLI's hook chain. After every commit, it asks you to summarize what just happened — or auto-generates one using the same CLI you're already paying for. The summary lands in a shared store. When your teammate's next session starts, their AI sees it — only after they explicitly Allow each item.

No re-explaining. No copy-paste. No new API key. Opt-in per teammate, gated per item.

How we built it

WinUI 3 (.NET 8, unpackaged) — dashboard, tray, Outbox, Inbox H.NotifyIcon.WinUI — system tray Node.js — hook scripts Supabase Postgres + REST — shared store System.Text.Json / JSON.parse — wire format on both sides

Challenges we ran into

The first one was hook recursion. When the Outbox spawns the CLI to auto-generate a summary, that subprocess re-fires the same hooks that opened it — instant infinite loop. We solved it with a single environment variable both hook scripts check at the top.

Concurrency was the next surprise. SessionStart and UserPromptSubmit can fire within milliseconds of each other, Stop events can overlap on session end, and without locking you'd get two popups for the same row. File locks with stale-lock recovery, so a crashed predecessor doesn't lock anyone out forever.

Cross-CLI compatibility was harder than it sounds. Calling codex from a Claude session fails because codex isn't on PATH, and vice versa. The hook had to detect which CLI fired it and spawn the matching one for auto-generate.

Unpackaged WinUI 3 has rough edges. No built-in tray icon. Window icon needs code, not XAML. Theme can't be hard-coded if you want a Settings page. One of our NuGet dependencies silently dropped net8 support in its latest version — caught only at restore time.

And the stdout-as-injection contract took some thought. The injected text is whatever the receiver writes to stdout, so the preview the user sees and the text the model sees have to be byte-for-byte identical. No transforms. No surprises.

Accomplishments that we're proud of

Cross-agent handoff actually works. A Codex user can push context that lands in a Claude user's session — same machine or across the network — with no special configuration. The shared store is just JSON; both CLIs read hook stdout the same way. The cross-vendor flow falls out of the design, not a special case.

Zero new bill. Auto-generate uses the user's existing CLI subscription instead of demanding a separate API key. Onboarding is "install and go" instead of "go create an Anthropic console account, generate a key, paste it here."

A polished native surface. System tray, dashboard, theme switcher, custom title bar, branded popups, multi-resolution app icon. It feels like a real Windows app, not a script with a UI bolted on.

Consent gating that respects the user. Allow-list at the teammate level, popup gate at the row level, watermarking so the same content is never re-asked. Nothing reaches the model without an explicit click.

And the moment that lands on camera: two physical machines, two different agents, talking through Supabase, with the consumer's AI visibly responding to the producer's context.

What we learned

Hook systems are way more powerful than the docs let on. Both Claude Code and Codex ship a stdout-prepend contract that's effectively a generic context-injection bus. Once you see it, a lot of "we need a feature for X" becomes "we can do X with a hook."

Concurrency in CLI hook scripts is non-trivial. "It's just a script that runs once" is wrong. Events overlap. Child processes re-fire parents. Your watermark file becomes a tiny distributed system. Locks aren't paranoia, they're the floor.

Subscription versus API is a real product decision, not just a billing one. Subscription-CLI gives you frictionless onboarding. API gives you defensible, scalable, TOS-clean ground. We picked subscription for the demo and would add API as an alternative for any production path.

Unpackaged WinUI 3 is a great way to ship a native Windows app fast — but expect to write your own tray, your own icon plumbing, your own theme application. The packaged-app conveniences don't carry over.

And the smallest UI bug erodes trust the most. "Latest sync" on the Activity page was reading the wrong field — showed the most recent teammate timestamp, not this user's last sync. Tiny fix, but until it landed, nothing else on the page felt reliable.

What's next for Handoff

Hide-to-tray on close, so the daemon survives the X button instead of dying with the window. Live Supabase rewiring after Settings changes — right now you have to restart the app to pick up new credentials. An in-app log viewer for the daemon log with severity filter and copy-to-clipboard, so debugging doesn't need a text editor.

An API-key alternative path. Let users plug in an Anthropic or OpenAI key as an opt-in alternative to the CLI subprocess — removes the subscription-tier gray area entirely for anyone who cares.

More agents. The contract isn't Claude/Codex specific. Cursor, Aider, Gemini CLI, and others expose similar hook surfaces.

Built With

Share this project:

Updates