# vibedating Dating by tokens — connect your Claude Code / Codex usage, get sorted into a **league** (1M / 5M / 10M / 100M / 1B+), and match with people who burn tokens the way you do. The premise: heavy users of these tools share something worth matching on. Part of the **Vibe Suite** — companion tools for agentic coding CLIs. Ships as **CLI + npm package + MCP server**, plus a local web app. Built on [`@pooriaarab/vibe-core`](https://www.npmjs.com/package/@pooriaarab/vibe-core). ## Demo [▶ Watch the launch video](branding/launch-video.mp4) — she matched with the man of her dreams. He was coding in a basement. https://github.com/pooriaarab/vibedating/raw/main/branding/launch-video.mp4 > **Local-first.** Raw token usage is read and stored on your own machine and > **never leaves it.** Only the coarse league *bucket* is ever shared — never the > raw number, never per-project breakdowns. Live matching is peer-to-peer over a > DHT (no central server) and **opt-in only**; without it the pool is a local > seeded demo. ## Status **v0 — works locally, privacy-first.** Usage is **verified from your harness's real local logs** via vibe-core's `readHarnessUsage` (source `real` → `verified: true`); when no logs are readable you can self-report (`VIBEDATING_TOKENS`, unverified) or fall back to a demo value (unverified). Handles are bound to a persistent ed25519 identity (`~/.vibedating/identity.json`, mode 0600): every hello is signed, and a forged signature gets the peer dropped. ## Install ```bash npm install -g vibedate ``` …or run it ad-hoc: ```bash npx vibedate connect ``` ## Quick start ```bash # 1. Read your usage, compute + print your league (stored locally at ~/.vibedating) vibedating connect # 2. See candidates in your league (same or adjacent tier) vibedating matches # 3. (Opt-in) find live same-league peers over the DHT — no server vibedating discover --live # shares ONLY handle+league+harness+verified flag+identity pubkey # 4. Open the local web app in your browser (served from your machine) vibedating open ``` Self-report a token count (otherwise a demo value is used): ```bash VIBEDATING_TOKENS=23400000 vibedating connect # also accepts 12M / 1.2B / 500k ``` ### All commands ``` vibedating connect Read usage, compute + print your league (first run auto-assigns a memetic handle — never @you) vibedating matches [--live] List candidates in your league (live peers if any, with last-message time) vibedating discover [--live] Find live same-league peers over the DHT (opt-in) vibedating live [--keep-alive] Live text chat (--keep-alive / non-TTY survives stdin EOF) vibedating handle [@name] Print or set your handle vibedating daemon [start|stop|status|install|uninstall] Notify-only background daemon — alerts on NEW matches, never opens chat/video; install = run on login (launchd/systemd) vibedating open [--port N] Serve the local web app (default: random free port) vibedating mcp Run the stdio MCP server (tools: profile, matches) vibedating --version vibedating --help ``` ### Live P2P discovery (opt-in) `vibedating discover --live` joins the public [hyperswarm](https://github.com/holepunchto/hyperswarm) DHT on your league topic — `sha256('vibedate:' + leagueBucket)` — so same-league peers find each other with **no central server**. On each encrypted connection the two sides exchange a one-line hello with only `{ handle, league, harness, verified, pubkey, nonce, sig }` — the proof fields sign the hello with your persistent ed25519 identity so a handle can't be impersonated; raw usage is never put on the wire. Discovered peers are stored in `~/.vibedating/peers.json` and shown by `vibedating matches`. Live discovery is **off by default**. The `--live` flag is the explicit opt-in (persisted as the `share:live` consent scope); every live run prints what it shares before joining. `Ctrl+C` leaves the swarm cleanly. ## Three faces, one local engine The same local engine drives all three, so you can use it wherever you work: - **Web** — `vibedating open` serves the dating UI (profile, match stack, league ladder) at `http://localhost:PORT`. The page reads your league + matches from a tiny local JSON endpoint. - **CLI** — `vibedating connect` / `matches`. - **MCP** — `vibedating mcp` exposes `profile` (your league) and `matches` to any MCP host (Claude Code, Codex, Cursor, …). ### As a library ```ts import { league, matches, readUsage, CANDIDATES } from 'vibedate'; const usage = await readUsage('claude-code'); // { totalTokens, verified, ... } const lg = league(usage.totalTokens); // { name: '10M', min: 10_000_000 } const who = matches(lg.name, CANDIDATES); // same/adjacent-tier candidates ``` ## Privacy - **Raw usage stays local.** `totalTokens` is read into memory, stored at `~/.vibedating/state.json`, and shown in the web app only behind an opt-in toggle. It is never transmitted. - **Only the league bucket is shared** — with the local demo pool, and (only if you opt in with `--live`) as `{ handle, league, harness, verified, pubkey, nonce, sig }` with same-league peers over the hyperswarm DHT. The handshake parser whitelists those fields, so a peer can't even be *sent* anything else into your process; the `verified` flag and identity pubkey are the only additions, never a token count. - Consent for sharing the league is modeled with `@pooriaarab/vibe-core`'s consent ledger (scope `share:league`), granted on `connect` and revocable on reset. Live P2P discovery has its own scope (`share:live`), default **off**. ## Leagues & matching Bucketed by lifetime tokens; you match within your league **or an adjacent tier** (so the tiny 1B+ pool still has people to match with): | League | Tokens (lifetime) | | ------ | ----------------- | | 1M | 1M – 4.99M | | 5M | 5M – 9.99M | | 10M | 10M – 99.9M | | 100M | 100M – 999M | | 1B+ | 1B+ | ## Prototype An interactive, self-contained UX prototype (no build, no network): [`docs/prototype.html`](docs/prototype.html). The shipped local web app (`vibedating open`) is an adapted, data-driven version of this prototype. ## License MIT