Development journal
Building UserTold
Selected milestones in making continuous research trustworthy, recoverable, fast, and native to agents.
Target invitations without tracking visits
Why it matters. A Project can show the right research invitation without
reporting each page a visitor views to UserTold.
- The widget downloads one cacheable, Project-scoped placement catalog and
evaluates route and language rules in the browser; navigation makes no
follow-up targeting requests.
- Pre-consent responses omit remote Invitation images, and direct recruitment
arrivals send only their opaque campaign reference rather than page context.
- Live readiness and the operational Study bundle are requested only after
explicit Start; participant state begins with the recording-consent action.
Let agents recover without guessing
Why it matters. An agent arriving without product context should be able to
discover the right contract or recover from a wrong URL without scraping a
browser page or guessing the next path.
- A predictable
/openapi.json endpoint publishes the same generated OpenAPI
3.1 contract as the existing API route, with descriptions for every operation.
- Unknown route-like requests from non-browser clients return a concise Markdown
404 with links to documentation, the agent index, the API contract, and sitemap.
- The compact agent index now says when UserTold is useful and routes agents to
the widget, MCP, CLI, or REST surface that fits the job.
Read more: UserTold for agents
Keep every interview recoverable
Why it matters. An interrupted connection or a partial backend failure
should not cost the participant the research they already contributed.
- Recording uploads use append-only parts capped at 1 MiB, with
browser-provided SHA-256 integrity. Pending parts are committed to browser
storage before upload, while the live uploader retains only bounded work in
memory instead of buffering an entire Interview.
- Readiness-gated Cloudflare Workflows coordinate media preparation,
transcription, and Evidence extraction with deterministic identities and an
atomic claim that prevents overlapping analysis.
- Processing and transcription state now distinguishes active work, recoverable
failure, and uncertain outcomes instead of presenting a complete-looking result.
Read more: Recording integrity and recovery
An MCP interface an agent can trust
Why it matters. Agents should be able to complete the research loop without
guessing what a tool does or receiving more participant data than they need.
- The remote MCP supports the modern stateless protocol with OAuth 2.1
Authorization Code and PKCE, explicit schemas, and bounded results.
- One reviewed public catalog covers Project setup, Studies, Interviews,
Evidence, Work, and explicit GitHub or Linear delivery; there is no hidden
callable catalog.
- Privacy limits and side-effect annotations are part of every tool contract,
including conservative recovery rules for destructive processing retries.
- An experimental Server Card and AI Catalog publish the live MCP endpoint and
supported protocol versions without copying authenticated tools or resources.
Read more: MCP technical verification
Public by design, private by default
Why it matters. Public pages and installation data should be fast at the
edge without turning authentication or customer state into shared cache data.
- A dedicated cache-enabled Worker entrypoint handles only reviewed public
routes; the default application entrypoint remains outside shared caching.
- Private and rejected cache candidates fail closed to
no-store, while public
routes use explicit descriptors, normalized keys, and response checks.
- Versioned widget assets are served from immutable R2 URLs, and Project-specific
SDK responses retain tenant-safe cache variation.
Read more: Private-by-default edge caching
BYOK custody gets its own security boundary
Why it matters. The keys protecting customer provider credentials should
not share the application deployment's permissions or secret surface.
- A separate key-broker Worker is the only runtime with access to versioned key
encryption keys in Cloudflare Secrets Store.
- Provider credentials use a per-Project data-encryption key; runtime inference
reads carry a declared purpose and D1-verified Interview or processing-job context.
- Configured BYOK fails closed when custody cannot be verified, with explicit,
restartable paths for Project-key and fleet-key rotation.
Read more: BYOK key custody
Backups outside the provider blast radius
Why it matters. A second copy inside the same cloud account does not protect
customer research from an account-level provider failure.
- Daily D1 snapshots and event-driven copies of new or changed R2 media are
stored in DigitalOcean Spaces, outside Cloudflare. Database snapshots rotate
after 90 days; the media copy follows source deletions.
- Delayed retries handle transient destination outages; a dead-letter queue
configured for a 14-day buffer and rate-limited operator alerts surface
persistent failures.
- The restore procedure rebuilds derived search indexes and preserves the
deletion ledger; scheduled cleanup re-applies erasures made after a snapshot.
Read more: Off-provider backups
Evidence becomes delivery, not another report
Why it matters. Research changes a product only when the original observation
remains visible in the decision and in the Work that eventually ships.
- Evidence keeps its source Interview context from playback through review and
GitHub or Linear handoff.
- Work remains review-gated: UserTold can group and prioritize Evidence, while a
Project-aware human or agent decides what is ready for delivery.
- Completed Linear Work resolves its linked Evidence, and later Interviews can
surface possible recurrence without erasing the earlier decision history.
Read more: Track resolved Evidence