Skip to content

R1 inventory — what ~/tinyai-id actually contains·

Source: ~/tinyai-id @ 72244113 (main) · worker submodule chatgpt-plugin-tinyai/ @ fffcf20. Everything below is derived from the code (grep/find), not from AGENTS.md. Where AGENTS.md disagrees, see DRIFT.md.

Status: v1 (mechanical). Iteration 1 captured the surface (routes, env, storage, deps). The deep read of every handler (auth semantics, wire protocol shapes, SSE event names, relay envelopes) is the remaining R1 work and will extend §6 and produce packages/contracts.

1. Deployables·

Deployable Where Runtime Package name Scripts
Next.js app repo root → Vercel Edge runtime for app/api/* (300 s max on chat) next-strands dev / build / start / lint / test (vitest)
Cloudflare Worker chatgpt-plugin-tinyai/ → plugin.tiny.technology workers, nodejs_compat, cron * * * * *, Email Routing, Durable Object chatgpt-plugin-tiny start (wrangler dev) / typecheck / deploy:default / deploy:production
Clients (NOT ported) tiny-tech/ (npm daemon), ios/, android/ — — Consume the HTTP + SSE contract; documented, not vendored

2. Size·

Area Files Lines
app/ (95 ts/tsx; 64 api route files + 20 pages/routes) 95 14,792
lib/ 111 19,012
components/ 44 16,537
tools/ (http.ts) 1 217
tests/ (vitest) 329 86,481
worker src/ 46 15,903
worker migrations/ 36 SQL files (0002 → 0035; two 0014s, two 0015s) —

3. Web API routes (64)·

See PARITY.md for the full route table with methods, line counts and the source test files that import each route. Groups: auth (auth, auth/cli, auth/cli/token, auth/webauthn/{register,login}, login, logout, me, udid) · agent loop (chat, chat/tool-result, run-tool, tools/*, worker) · tiny CRUD (tiny, control, delete, share, follow, visit) · devices (devices, adopt, ask, endpoint, endpoint/chat, event, heartbeat, messages, relay, task-result, transcript, firmware/manifest) · memory (learnings, graph, archives, prefs, model-config, model-providers, account-voice) · notifications (push, events, messages, telegram, jobs, job-run) · voice (voice/session, sessions, tool, replay/[id], recording-status/[id]) · location · media · money (wallet, wallet/faucet, wallet/withdraw, x402/pay, x402/chat/[slug], chain/join, chain/status, erc8004/registration/[slug]) · manifest/[slug].

4. Web pages & non-API routes (20)·

app/page.tsx (home = chat + Community) · app/[slug]/page.tsx · about · auth/cli · calls · chain, chain/tx/[hash], chain/address/[addr] · devices · map · universe · voice · wallet · wearables · og/[slug]/route.tsx · vcard/[slug]/route.tsx · layout.tsx · manifest.ts · robots.ts · sitemap.ts.

5. Worker endpoints (121 HTTP + cron + email + Durable Object)·

Router: @cloudflare/itty-router-openapi (self-documenting at /, AI-plugin manifest at /.well-known/ai-plugin.json). Full table in PARITY.md. Families: tiny (upsert/get/retrieve/list/community/profile/legal/tiny DELETE) · users & credentials (internal-key) · share · archive · learnings + graph (neighbors/all/conflicts/resolve/social/feed) + follow · reputation · events · jobs · push · tools (+browse) · telegram (+api proxy) · prefs / model-config / model-providers / account-voice · device (enroll/heartbeat/list/revoke/rotate-token/event/ask/endpoint/call/relay/{send,poll,reply,recv,deposit}/ task-result/tool-result/messages) · firmware (publish/current/device-current) · transcript · location · pay/* (17 endpoints: balance/invoke/transfer/refund/price/pricing/credit/spend/spend-sent/spend-reverse/settle-unknown/reconcile-status/ link-address/claim/deposit-info/faucet/withdraw-*) · ring · visit · media (upload, :key) · voice (session/connect/reap/ recording/sessions/replay) · message(s).

Cron (scheduled): runDueJobs, pollTelegramBots, sweepToolUpdates, location sweep, reconcileSentSpends, reconcileSettleUnknown, sweepReconcileAlarm. email: forwards <slug>@domain to the tiny's customer email. Durable Object: VoiceSession (migration tag v1, new_sqlite_classes).

6. Storage·

Cloudflare bindings (wrangler.toml — all ids are tiny.technology-specific and MUST be parametrized)·

Binding Type Prod name Notes
DB D1 tiny-v2 source of truth, 321 references
DB_OLD D1 tiny legacy, read-only, 0 references in src → drop from template (verify)
tiny KV — tiny configs (chat-runtime read path), 22 refs
tiny_old KV — 0 refs in src → drop from template (verify)
post KV — share snapshots, 90 d TTL, 10 refs
applause KV — 0 refs in src → drop (verify)
stats KV — counters (21 refs, incl. email-forward failures)
VECTOR_INDEX Vectorize tiny-v2 universe RAG, 4 refs
MEMORY Vectorize memory per-user learnings, 7 refs
MEDIA R2 tiny-media device media + voice journals, 20 refs
VOICE Durable Object VoiceSession 9 refs

D1 tables (36 migrations)·

archives claimed_txs credentials devices edge entity events firmware_channels job_runs jobs learnings ledger locations messages model_config model_providers notes oauth_tokens prices push_subscriptions relay_messages reputation settle_unknown shares spend_sent telegram_bots tiny_owners tinys tool_results transcripts trial_taint user_prefs user_tools users voice_sessions wallets withdrawals

7. Environment variables·

Web (process.env.* in app/, lib/, components/, tools/, next.config.js)·

AI_GATEWAY_API_KEY AI_GATEWAY_MODEL_ID AUTH_JWT_SECRET AWS_BEARER_TOKEN_BEDROCK AWS_REGION BASE_RPC_URL BASE_SEPOLIA_RPC_URL BEDROCK_EDGE_DEBUG BEDROCK_MODEL_ID BEDROCK_REGION DEPOSIT_ADDRESS ENROLL_SECRET GEMINI_API_KEY GEMINI_MODEL_ID GITHUB_CLIENT_ID GITHUB_CLIENT_SECRET GOOGLE_API_KEY INTERNAL_API_KEY KV_REST_API_TOKEN KV_REST_API_URL NEXT_PUBLIC_APP_URL NEXT_PUBLIC_FREE_TIER_REQUESTS_PER_DAY NEXT_PUBLIC_GOOGLE_MAPS_API_KEY NEXT_PUBLIC_MOONPAY_KEY NEXT_PUBLIC_ONRAMP_APP_ID NEXT_PUBLIC_VAPID_KEY NODE_ENV OPENAI_API_KEY OPENAI_MODEL_ID OWNER_LOGIN PAYMENTS_NETWORK PAYMENTS_TESTNET PAYOUT_PRIVATE_KEY STRANDS_ADDITIONAL_REQUEST_FIELDS TINY_CHAIN_DEPLOYER_KEY TINY_CHAIN_EXPLORER_URL TINY_CHAIN_ID TINY_CHAIN_PUBLIC_BOOTNODES TINY_CHAIN_RPC_URL TINY_CHAIN_USDC_ADDRESS TINY_MODEL_PROVIDER TINY_WORKER_URL WEATHER_API_KEY X402_FACILITATOR_URL X402_PAY_ALLOWLIST X402_PAY_TO X402_QUOTE_SECRET

Hot spots: INTERNAL_API_KEY (117 refs) and TINY_WORKER_URL (40 refs) — the app↔worker channel.

Worker (env.* in src/)·

BASE_RPC_URL BASE_SEPOLIA_RPC_URL CLOUDFLARE_API_TOKEN DB DEPOSIT_ADDRESS INTERNAL_API_KEY MEDIA MEMORY MODEL_CONFIG_ENC_KEY OPENAI_API_KEY VAPID_PRIVATE_KEY VAPID_PUBLIC_KEY VAPID_SUBJECT VECTOR_INDEX VOICE

Plus [vars] in wrangler.toml: TINY_CHAIN_ID, TINY_CHAIN_USDC_ADDRESS, TINY_CHAIN_RPC_URL, PAYMENTS_NETWORK, and the deliberately-unset RECONCILE_ALARM_USER. Secrets documented in the toml: OPENAI_API_KEY, INTERNAL_API_KEY, CLOUDFLARE_API_TOKEN.

8. tiny.technology-specific constants (rule 4 targets)·

Worker: legal.ts (12), index.ts (11 — plugin metadata, contact email, CF account id 6a90…, owner forward address), get.ts (9), upsert.ts (8), retrieve.ts (8), plus single hits in telegram/firmware/ask/users/scheduler/relay/push/ profile/messages/devices/community. Web: app/api/chat/route.ts (49!), app/[slug]/page.tsx (21), lib/chain/calldata.ts (15 — contract addresses), app/layout.tsx (10), erc8004 (7), x402/chat (5), and ~30 files with 1–3 hits (URL of the public site, owner login, plugin.tiny.technology). Every one becomes an env var (NEXT_PUBLIC_APP_URL, NEXT_PUBLIC_SITE_NAME, TINY_WORKER_URL, OWNER_LOGIN, CONTACT_EMAIL, CF_ACCOUNT_ID, …) with an .env.example entry.

9. Dependencies·

Web runtime: @strands-agents/sdk, @modelcontextprotocol/sdk, openai, @google/genai, @ai-sdk/gateway, @simplewebauthn/{browser,server}, jose, @vercel/kv, @upstash/ratelimit, @vercel/analytics, viem, zod, next, react, react-dom, next-themes, @headlessui/react, react-markdown (+remark-gfm/math, rehype-katex, katex), react-syntax-highlighter, recharts, sonner, qrcode, slugify, clsx, tailwind-merge, tailwindcss-animate, copy-to-clipboard, remove-markdown, react-is, bufferutil, utf-8-validate. Web dev: typescript, vitest, jsdom, @testing-library/{react,dom}, eslint(+config-next), tailwindcss/postcss/autoprefixer, playwright-core, @builder.io/partytown, @types/*. Worker: @cloudflare/itty-router-openapi ^1.1.1, openai ^4, slugify; dev wrangler ^4, workers-types, typescript.

10. Tests·

329 vitest files (86k lines). Only a subset exercise the web API / lib / worker — many are iOS/Android/store-asset parity tests (ios-*.test.ts, android-*.test.ts, store-*.test.ts, film-*.test.ts, wearables-*) that read files outside the template's scope. Classification into port / n/a is R1 follow-up work (target: every test whose imports resolve inside apps/web, apps/worker or packages/contracts is ported). tests/_worker.ts and tests/_deployment.ts are shared harnesses — read first.

11. Not in scope for the template (documented as clients / owner assets)·

ios/, android/, tiny-tech/, fastlane/, store-assets/, business/, cad/, strands-cad/, agi-diy/, careless/, chain/ (validator ops), wisp-the-crazyflie/, telegram_events/, whatsapp_events/, overrides/, site/ + mkdocs.yml (owner's docs site), scripts/gen-* (marketing asset generators), templates/.

12. Per-route runtime (verified from export const runtime / maxDuration)·

Edge (default): 55 routes. Node.js: /api/chain/status, /api/devices/ask (90 s), /api/devices/endpoint/chat (120 s), /api/job-run (120 s), /api/run-tool (30 s — the Node sandbox), /api/wallet/faucet (30 s), /api/wallet/withdraw (60 s), /api/x402/pay (180 s). Edge with explicit maxDuration: /api/chat 300 s, /api/x402/chat/[slug] 300 s, /api/tools/run 60 s. (Drift #5 resolved: AGENTS.md's "no Node in app/api/*" is false for 8 routes — DRIFT.md updated.)

13. Wire protocol — seed for packages/contracts·

13.1 Chat request (POST /api/chat, lib/chat/*)·

  • Body: { messages: [{ role, content: string | Block[] }] } — non-object entries dropped, string content normalized to blocks; messages[] required (400 otherwise). Last 31 kept; system messages folded into the soul prompt.
  • Identity headers: x-tiny-name, x-tiny-system-prompt, x-tiny-session, x-tiny-metadata (alias x-tiny-ip, legacy), x-tiny-key, x-tiny-mcp-servers, x-tiny-x402-settled, x-internal-key; cookie (tiny_session) or authorization: Bearer <cli jwt>.
  • BYOK headers: x-tiny-model-provider|api-key|id|base-url|max-tokens|region|additional-fields. Header config wins over the worker-synced /model-config.
  • Response: text/event-stream, X-Accel-Buffering: no; each frame data: {…, seq} with a monotonic seq; : ping comment every 15 s; terminal data: [DONE].

13.2 SSE event vocabulary (lib/chat/events.ts:normalizeAgentEvent)·

type fields
modelContentBlockDeltaEvent one of textDelta · reasoningDelta · toolInputDelta · citationsDelta
modelContentBlockStartEvent toolStart: { name, toolUseId }
modelContentBlockStopEvent · modelMessageStartEvent —
modelMessageStopEvent stopReason
modelMetadataEvent usage, metrics, modelId
beforeToolCallEvent toolCall: { name, toolUseId, input }
afterToolCallEvent toolResult: { name, toolUseId, status, content (media bytes elided), error? } — name is back-filled from a per-turn ToolNames map (native clients drop nameless results)
toolStreamUpdateEvent toolStream: { toolUseId, name, data }
toolResultBlock toolResultBlock: { toolUseId, status, content } (legacy)
agentResultEvent stopReason
error error (also emitted pre-stream on preflight failure)
contextCompacted route-level marker
any other SDK event { type } marker only
isDeliveredOutput() = non-empty text/reasoning delta or an afterToolCallEvent — the refund boundary for paid turns.

13.3 Auth (lib/auth.ts)·

  • Cookie tiny_session, HS256 JWT (AUTH_JWT_SECRET), TTL 30 d; tiny_oauth_state for the GitHub OAuth CSRF state.
  • CLI token: same JWT shape, TTL 90 d, accepted as Authorization: Bearer by every session-gated route (/api/auth/cli, /api/auth/cli/token).
  • SessionUser = { sub, login, name?, avatar?, email? } (verify exact fields in R3). safeReturnPath = same-origin only.
  • App → worker: X-Internal-Key: INTERNAL_API_KEY on TINY_WORKER_URL (default hardcoded https://plugin.tiny.technology in 40 places → env-only in template).

13.4 Device relay (app/api/devices/relay, worker relay.ts, relay-shared.ts)·

  • App: POST { toDevice, payload } (session) → worker /device/relay/send { userId, toDevice, payload }; GET recv; PUT { deviceId, token, max } → /device/relay/poll; PATCH { deviceId, token, inReplyTo, payload } → /device/relay/reply.
  • Worker extras: /device/relay/deposit { userId, ticket, payload }, /device/task-result { deviceId, token, taskId, summary, result }.
  • Table relay_messages(id, user_id, to_device, in_reply_to, payload, created_at, delivered); payload JSON ≤ 8 KB; envelope kinds seen: {type:'invoke'}, {type:'notify'}.
  • Wire strings the app classifies on (lib/chat/relay-send.ts RelaySendKind): device not found (404), payload must be valid JSON ≤8KB (400), unauthorized (401), userId and toDevice required (400). Result: { queued:true, id } | { queued:false, kind, error, delivered:'no'|'unknown', retryable }.
  • Device lifecycle (worker devices.ts): enroll { userId, name, platform, kind, capabilities, url, secret } → heartbeat { deviceId, token, capabilities, lanUrl, wantUnread } → event { deviceId, token, kind, detail } → ask { userId, deviceId, action, prompt } → revoke / rotate-token { userId, deviceId }.

13.5 Push (worker push.ts)·

PushPayload = { title? (≤100), body? (≤400), url? (default '/'), tag? (default 'tiny-notification') }; delivered as Web Push { type:'notify', title, body, tag, url } and mirrored as a relay notify envelope. sendPushToUser(env, userId, payload) → { sent, pruned, relayed }. VAPID keys from env.

13.6 x402 (lib/x402/*)·

Types to lift verbatim: Accept, Challenge, QuoteFields (payer.ts); PayNetwork = 'base'|'base-sepolia'|'tiny', TopUpRoute, FaucetInfo, DepositInfoLike (top-up.ts); LedgerEntry, DepositInfoResponse, PricingResponse, ClaimResponse, FaucetClaimResponse, WalletActionBody, WalletSnapshot (wallet-client.ts); TinyChainConfig (tiny-chain.ts — env-driven).

14. Tests — classification·

329 files → docs/TESTS.md: 126 port-web · 60 port-worker · 43 split (web assertions + client-parity reads) · 86 n/a (iOS/Android/store/film/chain-ops only) · 12 review.

15. Test harnesses (read in full)·

  • tests/_worker.ts — resolves worker source at ../chatgpt-plugin-tinyai/src; when the private submodule is absent (CI) it skips loudly. In the template the worker is in-repo, so every port-worker test runs in CI — a strict improvement over the source.
  • tests/_deployment.ts — asDeployment('base' | 'base-sepolia' | 'tiny') pins BOTH payment selectors (PAYMENTS_NETWORK wins over legacy PAYMENTS_TESTNET) plus TINY_CHAIN_ID, TINY_CHAIN_USDC_ADDRESS, X402_FACILITATOR_URL, and restores them. Port verbatim into apps/web/tests/_deployment.ts in R8.
  • vitest.config.ts — tests/**/*.test.{ts,tsx}, alias @ → root; .tsx tests declare // @vitest-environment jsdom themselves.

16. D1 table → worker module map·

Table Modules
tinys ask, community, delete, get, graph, list, messages, payments, profile, retrieve, turns, upsert, users, visit
users account-voice, ask, community, graph, learnings, locations, messages, money-events, payments, profile, tools, users
devices devices, firmware, media, push, relay
telegram_bots delete, messages, reconcile-alarm, telegram-api, telegram
user_tools graph, payments, profile, tool-updates, tools
prices ask, payments, profile, scheduler
ledger / wallets deposits, payments, withdrawals
edge, entity graph, learnings (+profile for edge)
jobs, job_runs scheduler, delete
notes delete, retrieve, turns
messages devices, messages
model_config, model_providers model-config, model-providers
relay_messages relay, relay-shared
trial_taint, claimed_txs, spend_sent, settle_unknown payments / deposits
archives · credentials · events · firmware_channels · learnings · locations · oauth_tokens · push_subscriptions · reputation · shares · tool_results · transcripts · user_prefs · voice_sessions · withdrawals one module each (same name)
tiny_owners no module references it — migration-only; drop candidate (verify against tests)

17. Toolchain facts for the port·

next ^16.2.10 (installed 16.2.10) · react 18.2.0 · typescript 5.1.3 (pinned; Response.json() static is NOT in its DOM lib — source uses new Response(JSON.stringify())) · vitest ^4.1 · tailwind ^3.3 (installed 3.4.19) · eslint 9 flat config · zod ^4 · jose ^6 · @strands-agents/sdk ^1.10 · openai ^6 (web) vs ^4 (worker) · wrangler ^4 · node 22. Next 16 prints "The Edge Runtime is deprecated" for runtime = 'edge' — the source's 55 edge routes still build; migration to nodejs is a behaviour question for the owner (DECISIONS D-008), not a port decision.

R1 is complete: surface, runtimes, wire protocol, storage, env, tests and harnesses are inventoried. Remaining reads happen per-module as each rung ports it.