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(aliasx-tiny-ip, legacy),x-tiny-key,x-tiny-mcp-servers,x-tiny-x402-settled,x-internal-key;cookie(tiny_session) orauthorization: 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 framedata: {…, seq}with a monotonicseq;: pingcomment every 15 s; terminaldata: [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_statefor the GitHub OAuth CSRF state. - CLI token: same JWT shape, TTL 90 d, accepted as
Authorization: Bearerby 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_KEYonTINY_WORKER_URL(default hardcodedhttps://plugin.tiny.technologyin 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 };GETrecv;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.tsRelaySendKind):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 everyport-workertest runs in CI — a strict improvement over the source.tests/_deployment.ts—asDeployment('base' | 'base-sepolia' | 'tiny')pins BOTH payment selectors (PAYMENTS_NETWORKwins over legacyPAYMENTS_TESTNET) plusTINY_CHAIN_ID,TINY_CHAIN_USDC_ADDRESS,X402_FACILITATOR_URL, and restores them. Port verbatim intoapps/web/tests/_deployment.tsin R8.vitest.config.ts—tests/**/*.test.{ts,tsx}, alias@→ root;.tsxtests declare// @vitest-environment jsdomthemselves.
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.