Choose a buddy, then watch it listen, think, work, talk, wait for approval, and celebrate an agent run

# Agent Buddies **Let your users pick their agent’s buddy.** A growing library of cute, swappable characters for AI agent interfaces. Give people a searchable buddy picker, remember their favorite, and let that character express what their agent is doing. Start with ten original buddies; add your own without changing your app’s state handling. [Gallery](https://izr8809.github.io/agent-buddies/) · [Pack specification](docs/SPEC.md) · [Make a buddy](docs/STYLE.md) · [Contribute](CONTRIBUTING.md) > **v0.1 preview.** npm packages are coming soon — for now, clone the repo and use the local setup below. ## A little character for every state `idle` → `listening` → `thinking` → `working` → `talking` → `waiting` → `success` (or `error`). `blink` is an internal expression frame. One complete bitmap is shown at a time. Variants edit only declared eye, mouth, or small prop regions of a locked master. There are no image crossfades or stacked eyes. Motion is gentle: 1.015× breathing, seeded 3–6 second blinks, spring tilts, and a 5.5 fps streaming mouth. Reduced Motion keeps the expression static with blinks; hidden views pause. ## Quick start Planned package entry points: `agent-buddies`, `agent-buddies/react`, `agent-buddies/element`, `agent-buddies/adapters`. Scoped packages can be split after the owner’s review; they are not required for this prototype. ### React: let users choose ```tsx import { useState } from 'react'; import { AgentBuddy, BuddyPicker } from 'agent-buddies/react'; export function AgentPanel() { const [buddy, setBuddy] = useState('koko'); return <> ; } ``` `announce` opts into polite state text, such as “Koko is thinking”; the character always exposes role="img" and a name/state aria-label. Native picker buttons, search and selects support keyboard navigation. The picker remembers choices in localStorage. Handle `onChange` to connect a controlled choice to your application. `defaultBuddy`, `catalogURL`, and `allowlist` are optional. Buddy assets load lazily; React is a peer dependency, not part of the core. ### Web Components ```html ``` Serve `dist/` with its `characters/` and `catalog.json` sidecars. For a remote collection, set `catalog-url` on both elements. The picker supports `allowlist="koko,cat"`, `default-buddy`, `value`, and a configurable `storage-key`. The character supports `paused` and `reduced-motion` boolean attributes. ### SwiftUI Add the local package in Xcode, or after release use the Git repository as a SwiftPM dependency. ```swift import SwiftUI import AgentBuddies struct AgentPanel: View { @State private var buddy = "koko" var body: some View { VStack { BuddyPicker(selection: $buddy, storageKey: "my-app.buddy") AgentBuddyView(character: buddy, state: .thinking) } } } ``` `catalogURL` opts into remote packs; `allowlist` pins permitted IDs. `BuddyStore` verifies SHA-256 hashes, caches on disk, and falls back to bundled Koko. macOS 13+ / iOS 16+. macOS window occlusion, scene inactivity, and view disappearance pause animation. The iOS target has not been device-tested. ### Claude Agent SDK / Anthropic ```ts import { claudeAgent } from 'agent-buddies/adapters'; for await (const event of stream) { const state = claudeAgent(event); if (state) setAgentState(state); } // Permissions arrive through the host callback, not ordinary token events: setAgentState(claudeAgent({ type: 'permission_request' })!); ``` ### Vercel AI SDK ```tsx import { vercel } from 'agent-buddies/adapters'; const { status, messages } = useChat(); const last = messages.at(-1); const state = vercel({ status, parts: last?.role === 'assistant' ? last.parts : [] }) ?? 'idle'; return ; ``` `openai(event)` handles Responses events and Agents SDK envelopes. `fromEvents()` replays fixture or app event streams; `fromAsyncEvents()` is its async iterable equivalent. All adapters are pure mappings; they never call APIs. Application-specific permission callbacks must emit the documented host event. See [adapter contracts and sources](docs/ADAPTERS.md). ## Runtime catalog and offline behavior The versioned [catalog.json](catalog.json) contains ID, name, author, art license, tags, thumbnail, pack URL, and a SHA-256 manifest hash. Each manifest hashes every PNG. Catalog paths are relative so a self-hosted copy works at any base path. The intended public endpoint is `https://izr8809.github.io/agent-buddies/catalog.json`. ```ts import { PackLoader } from 'agent-buddies'; const pack = await new PackLoader().resolve('cat', { catalogURL: 'https://izr8809.github.io/agent-buddies/catalog.json', allowlist: ['koko', 'cat'] }); // A direct HTTPS character.json URL is also accepted as character={url}. // If an allowlist is present, a direct URL must itself appear in it. // Call pack.dispose() when you finish with its blob URLs. ``` Same-origin static hosting works immediately. Other hosts must allow cross-origin GETs. Verified bytes are cached with CacheStorage (memory fallback) on web and atomic files on Swift. An unavailable catalog can use its cached snapshot; a missing or rejected pack falls back to the bundled Koko sidecar. Keep bundled assets with the runtime to guarantee that fallback on a first offline launch. Hashes detect corruption against a trusted catalog; they are not signatures or proof of authorship. A direct URL without an expected manifest hash trusts that URL’s manifest while still checking its PNG hashes. ## Local development ```sh npm ci npm run check swift test python3 -m pip install -r scripts/requirements.txt npm run media npm run site python3 scripts/serve.py # loopback only; Ctrl-C stops it ``` The gallery is static and Storybook-free. `site/out` is the build artifact. `npm run validate` checks all character packs; `npm test` exercises motion, state transitions, adapters, catalog generation, hash verification, cache fallback, and persistence. See [validation evidence](validation/README.md). No network access or keys are used by tests. npm dependency installation and documentation/name lookups are read-only network operations. ## Make the collection bigger ```sh # Today, from this checkout (planned post-release alias: npx agent-buddies …): node scripts/cli.mjs new "a sleepy white cat" --id sleepy-cat # Use the written brief with Codex built-in image generation, select a master, then: node scripts/cli.mjs finish --id sleepy-cat --master path/to/master.png node scripts/cli.mjs validate characters/sleepy-cat ``` The CLI is an image-generation handoff, not a hidden API client. It writes a prompt and supports automatic or manually reviewed eye/mouth anchors, creates exact local expression edits, and runs validation. An image-capable Codex session generates the master without API keys. Python dependencies are optional until you author art. [Template and review checklist](templates/character/README.md). Artists can [submit an issue](https://github.com/izr8809/agent-buddies/issues/new/choose) without writing code. ## Licensing and status Code: [MIT](LICENSE). Art: [LICENSE-ART.md](LICENSE-ART.md) and each manifest; all starter packs use **CC-BY-4.0**, attributed to **Agent Buddies contributors**, with `ai_generated: true`. CC0 submissions are also accepted. AI generation does not establish exclusivity, copyright eligibility, or clearance; attribution and provenance remain visible. Koko is an authorized port of the EnglishCoach white puppy. No Tori or Bori artwork is included. Working name, package IDs, repository and gallery URLs live in [product.config.json](product.config.json). Run `npm run build` after changing branding; public API identifiers are a semver decision, not a runtime preference. No telemetry is installed. [Release checklist](docs/RELEASING.md) · [Launch drafts](launch/README.md). ## Ideas / roadmap - CLI/terminal agents (Claude Code, Codex CLI): a state-line buddy or terminal-safe expression badge; doc-only concept, no terminal integration shipped. - A VS Code extension connecting editor agent events to the same catalog and picker. - Optional voice-amplitude lip sync, respecting reduced motion and microphone privacy. - Phase 2: a web upload/preview/submission site for artists; no upload service is part of this static release. ## Safety and performance Runtime manifests are validated against the bundled JSON Schema; only bounded raster assets are fetched and verified. See [security/CSP](docs/SECURITY.md). Optimized 512px WebP and PNG fallback frames are each under 60KB; non-idle poses are fetched on demand and picker hover/focus preloads. JS bundle sizes and asset budgets are recorded in validation. The site’s hero includes a scripted agent simulation (prompt, tool call, streamed text, approval, success) that drives the buddies without an API key. [Content policy and takedown process](CONTENT_POLICY.md) · [Publication runbook](PUBLISHING.md) · [0.1.0 changelog](CHANGELOG.md).