Skip to content

Internal systemAI application

Designing AI-assisted dream work as a product—not a chat window

Velum is a native app for self-guided dream work. A dream becomes a canonical record, then can be explored through Core Reflection and six formal methods, each with its own guided session, and revisited through persistent boards built from the same archive. The model is called only at explicit steps, through an authenticated proxy, and its output is parsed and saved, or saved as a failure, before the product moves on.

Velum is an internal Future Built product. Screens come from the current native app with illustrative dream content; planned board tiles are specification proposals, not release commitments.

Role
Product strategy, UX architecture, AI systems, software engineering
Three screens from the current app: the dream archive, a saved dream with its summary, and the method picker showing which methods are done or in progress.

Three screens from the current app: the dream archive, a saved dream with its summary, and the method picker showing which methods are done or in progress.

Current product / implemented system

method-specific guided sessions that start from one saved dream
Core Reflection + six formal methodsmethod-specific guided sessions that start from one saved dream
deterministic views computed from the canonical archive
11 implemented board tile typesdeterministic views computed from the canonical archive
truncation, parse and network errors never become generated success
Failure saved as statetruncation, parse and network errors never become generated success
model, duration, tokens, cost estimate, status and limit decision
Per-request NDJSON telemetrymodel, duration, tokens, cost estimate, status and limit decision

Summary

Velum is an internal Future Built product: a native app in which a saved dream becomes the source for everything that follows. A chat window would have produced readings that were hard to find, compare or return to. Velum gives the work a durable home instead: sessions that keep their checkpoints and outputs, and boards that hold a chosen lens on the archive. The current product implements Core Reflection, six formal dream-work methods and eleven deterministic board tile types. Ten further tiles exist as specification proposals, not release commitments. In the AI layer, method-specific state machines assemble context for each model call, a server proxy authenticates and meters it, and the client decides what output becomes saved state.

The product opportunity

Dream material is fragile twice over. The dream fades quickly, and the work done on it scatters: a half-remembered scene in a notes app, an unindexed journal entry, a reading from a general-purpose assistant that lives in one conversation and is effectively gone once the thread scrolls away.

A conversational interface can preserve a thread, but it does not by itself create a canonical dream record, aggregate recurring motifs across an archive, or give ongoing work a persistent product structure.

Capture preserves the dream as text or voice. Exploration means choosing how to work with it. The checkpoints, answers and final output of that work are kept. Boards change the lens by motif, time or open question. Later visits return with the context intact.

The model is useful inside that sequence, but it is not the sequence. The archive and boards are what let the work accumulate instead of resetting each session.

Fragmented material on one side, the current archive in the middle, and the five-step product model on the other: capture, explore, structure, connect, revisit. The AI serves the inquiry; the archive and boards hold it together.

Fragmented material on one side, the current archive in the middle, and the five-step product model on the other: capture, explore, structure, connect, revisit

Designing the experience

Every method in Velum begins from a saved dream, never a blank prompt. From the dream, the user chooses how to work: Core Reflection, which reads the dream's emotional center, or one of six formal methods, among them Structure Analysis, Association, Compensation, Re-entry and Gestalt / Dialogue. Each method tracks its own status, so work can pause and resume.

Re-entry shows how much of the experience is designed state rather than open conversation. Choosing it creates a session and persists a checkpoint list. The opening stabilization and presence prompts are deterministic; the model is not involved yet. The user selects an entry point, then picks what holds their attention from directions the model infers from the scene and session. Each response is saved before the next step. After every answer the user decides whether to go deeper, choose a new direction or return. The state machine branches at configured depth intervals rather than enforcing a hard session cap, and returning leads to a carryback prompt and a synthesized Contact Record the user can reopen from the dream.

One implemented method, Re-entry, traced across what the user does, what the system executes and what persists locally. Deterministic prompts, model-inferred directions and user branching all write to the same saved session.

One implemented method, Re-entry, traced across what the user does, what the system executes and what persists locally

The model proposes directions and deepening prompts. The user chooses the path, and nothing in the flow presents output as the dream's meaning.

The state atlas covers the moments easiest to get wrong: a capture screen that asks only for what the user remembers, a method-specific loading scene instead of a generic spinner, a ready state with an explicit Begin, and the archive behind an optional app lock.

Six states from the current app: capture, method-specific processing, a deliberate ready state, filter-based context selection, a populated board and the archive behind the app lock.

Six states from the current app: capture, method-specific processing, a deliberate ready state, filter-based context selection, a populated board and the archive behind the app lock.

From feature to platform

A board is a saved lens on the archive. Its configuration persists per user: name, filters, pin, and an ordered list of tile instances with their settings. When a board opens, resolveBoardDreams() resolves its scope once, and every tile reads from that same scoped set.

The current implementation registers eleven tile types: What Keeps Recurring, Recurring Motifs, Motif Companions, Emotional Weather, People & Figures, Places, First / Latest Appearance, Linked Dreams, Timeline, Frequency Plot and Open Questions. Each does one narrow job, such as ranking recurring labels, counting co-occurring motifs or resolving a first and latest appearance, and links back to the filtered archive or source dream instead of copying it. In edit mode, tiles can be added, reordered, configured or removed.

Two decisions matter. Current tiles execute deterministically: they aggregate enrichment already attached to each dream, so opening a board never calls the model, and counts recalculate as the archive grows. And Open Questions is the one tile that stores user-written content, keeping questions and notes on the board between visits.

That is what turns a feature into a platform. New capabilities can arrive as new tile types against the same resolver and archive, rather than as new screens or longer conversations. Ten planned tiles are documented as specification proposals with P1–P3 priorities, not as shipped behavior.

The current board, unrolled: one custom board showing multiple ways back into the same nine dreams, plus the edit list of tile instances. Components are implemented; the dream data is illustrative.

The current board, unrolled: one custom board showing multiple ways back into the same nine dreams, plus the edit list of tile instances

One canonical archive, one persisted board configuration and one scope resolver feed eleven deterministic tile types. The ten planned tiles sit in a separate band, labeled as specification proposals rather than release commitments.

One canonical archive, one persisted board configuration and one scope resolver feed eleven deterministic tile types

Engineering the AI layer

Velum runs across three zones. The Expo / React Native app holds product state in Zustand and persists dreams, boards and sessions as user-scoped JSON in AsyncStorage. A small Express API sits between the device and Anthropic's Messages API, which runs Claude Haiku 4.5 by default.

Device, Velum API and external services as separate zones. Orchestration and the response boundary live on the device; the API verifies identity, meters usage and proxies to Anthropic, so model output returns to client-side handling before it is saved.

Device, Velum API and external services as separate zones

Orchestration lives on the client, in each method's state machine. For every model call, it assembles the dream body, its enrichment and the current session's answers, and selects prompt constants by method and phase. The request carries a Firebase bearer token and an X-Velum-Method header. The server verifies the ID token, applies a usage guard that can meter operations, tokens, cost and concurrency per feature, user and globally, and proxies the call so the provider credential never ships in the app.

The more important boundary is on the way back, where a successful HTTP response is not treated as usable output. The client rejects responses cut off at max_tokens, normalizes the text and parses JSON. Enrichment then passes through a motif sanitizer that cleans annotations, splits labels into atomic terms, canonicalizes, length-checks and deduplicates before anything reaches the archive that boards aggregate.

When a call fails, the failure becomes saved state: a failed session, or enrichment marked failed or quota-skipped, with the original dream already saved before enrichment ran. There is no generated success fallback. For Core Reflection, retrying is the user's decision; other methods expose a clear way back.

The limits are explicit too. Session output has no general runtime schema gate, and there are no automatic LLM repair attempts. Gestalt / Dialogue uses a parallel model call to sharpen its next hint, but that is model judgment shaping the experience, not a validator.

The implemented response path: reject truncation, normalize, parse, then route by feature. Failures persist as product state and retry is a user decision. The diagram also marks the gaps: no runtime schema gate and zero automatic repair attempts.

The implemented response path: reject truncation, normalize, parse, then route by feature

Operating a real LLM product

Prompts live in source control, organized by method, phase and template. Each saved session records a prompt version, the model, generation time, method and dream ID. That is coarse provenance: the v1 label is metadata, not a deployed prompt registry, and changing a prompt means shipping code.

The server writes an NDJSON event for every request, recording correlation IDs, feature and method, model, duration, provider-reported tokens, a code-based cost estimate, status and the usage guard's decision. A secret-protected admin API exposes usage and error views. The client separately logs parse failures and retries, because a completed provider call and a usable output are different signals. The next join worth building connects prompt version, request and client-side result.

Data boundaries follow the same discipline. Dreams, notes, boards and outputs stay on the device; there is no cloud archive sync. Only the selected dream and session context for a given call leaves it, through the proxy. Server logs contain no prompt body. Identity and subscriptions run through Firebase Auth and RevenueCat, and optional PostHog analytics pass an allowlist that excludes dream text. None of this is a compliance claim: local storage is not an encryption guarantee, and provider retention is outside what the code can verify.

Where prompts live, what each saved session records and the real NDJSON fields the server logs. The artifact also names the missing join between prompt version, request and client validation rather than inventing measurements.

Where prompts live, what each saved session records and the real NDJSON fields the server logs

Content and metadata take different paths. Dream content stays local except the context selected for a specific model call; the server keeps operational metadata only; identity, subscription and analytics flows run separately from dream text.

Content and metadata take different paths

Implemented vs planned

Where the platform goes next

The planned board shows the intended direction on the same archive and board. Key Excerpts would surface source language from a dream, with intentional generation and a separate cache. Motif Watchlist would follow one motif's thread across dreams. Period Pattern Reflection is designed as a deterministic recap built from dates, motifs and existing emotional weather, with no new model call in its first version. Pattern Synthesis, a user-triggered and cached reading across a board's dreams, is the most cautious proposal and is held at P3.

Much of that next layer can be computed from data the product already keeps; where a new model call is warranted, it enters as a bounded, user-initiated tile.

The same board with four of the ten planned tiles drawn inside a dashed boundary beside current components. Each proposal states how it would work, including whether it needs a new model call; sample content is illustrative.

The same board with four of the ten planned tiles drawn inside a dashed boundary beside current components

What this demonstrates

Velum's model calls happen at a handful of explicit points. What makes the product useful is everything around them: a canonical archive, sessions that keep their own state, boards that compute views deterministically, failures recorded instead of hidden, and data boundaries that are drawn rather than assumed. AI products earn trust when the model is one well-bounded component of a system built to outlast any single response.

Built with

Expo + React Native, Zustand, AsyncStorage, SecureStore, Express, Firebase Auth, Anthropic Messages API (Claude Haiku 4.5 by default), RevenueCat, PostHog (optional, allowlisted)

All work
Diagram split by a vertical automation boundary. On the automated side: receive email and preserve source, parse and extract candidate values, validate and resolve with an operator, create structured CRM handoff. On the human side, fragmented pricing inputs and account context such as negotiated multipliers and legacy concessions feed the salesperson or estimator, who produces the commercially approved quote.

Representative engagementIndustrial distribution

Automating RFQ intake without automating commercial judgment

Another case where the model interprets input while deterministic rules and people keep authority over what becomes system state.

82% of RFQs routed to shortened review · ~38 hours a month released (constructed)

View case study
Lead workstation for synthetic record EX-1042, Cedarline Heating & Air, an HVAC contractor in Columbus, Ohio, marked Enriched. It shows the human-confirmed website cedarline.example with a candidate score of 91/100 across 3 ranked websites, two contacts (owner Morgan Ellis selected, service manager Taylor Reed as a candidate needing review), three site findings, an operator website-quality rating of 2/5 with CRM state "ready," and next-action buttons for Prepare outreach, Needs confirmation and Skip.

Internal systemLead intelligence

Scaling lead research without scaling manual research

A stateful, progressive pipeline that spends automation and human attention only where the record's state justifies it.

173 operator hours a month released at 1,000 leads (modeled at $35/hour)

View case study