Skip to main content

Building Solomon, part 2: accounts, sync and making it yours

Updated 8 min readMarkdown
Part of seriesBuild in Public

Nine days after part 1, Solomon has real accounts, chats that sync between devices with end-to-end encryption, and an assistant you can shape: its personality, your instructions, projects and a library. It still runs on the same 16 GB laptop.

Did we do what we said?

One of part 1's eight roadmap items shipped, and it grew: accounts came with end-to-end encrypted sync instead of the plain Postgres sync we planned. The rest is still open, and most of this part's work came from using Solomon every day.

Part 1 roadmap item Status What happened
Accounts and sync Shipped Sign-in with email, verification and password reset; chats sync between devices end-to-end encrypted
Keys in a KMS Changed Synced chats are now encrypted in the browser with a key the server never holds; a KMS still matters for server-side data
Recency-aware answers Open Not started
More resilient search Open Not started
Richer files Open Not started
Image editing Open Not started; we added two more image models instead
Agents and tools Open Not started
A GPU server Open A Caddy gateway is ready for deployment; still on the laptop

Accounts with end-to-end encrypted sync

Signed-in chats are encrypted in the browser before they leave it, so the server stores and syncs only ciphertext. Part 1 encrypted data on the server with a server-held key; now the server holds no key that can read a synced chat.

When you create an account you also choose an encryption passphrase, separate from your password. It unlocks a random account key, which unwraps a separate key for each chat. A recovery key is the only way back if you forget the passphrase. Resetting your password never touches your chats.

Sync runs on a self-hosted PowerSync service. Each device keeps a readable copy in IndexedDB and an encrypted mirror in local SQLite; uploads go through the Nest API, which checks that you own every row before writing it. Chats you made while signed out move into your account when you sign up.

Making it yours

Solomon now adapts to the person using it, and those choices follow you to every device.

  • Six personalities. Balanced, Warm, Witty, Straight-shooter, Mentor and Curious change how replies sound, never what is true. The home screen changes with them: a greeting by your first name and the time of day, its own headline and four suggested prompts.

  • Custom instructions. Up to 1,500 characters about you or how you want answers, added to every chat.

  • Response style. Length (concise, balanced, detailed), formatting (plain, balanced, structured) and emoji on or off.

  • Projects. Folders of chats with shared instructions, like "always give prices in yen" for a trip. Pin chats, move them between projects, and see a project's breadcrumb in each chat.

  • Profile and My Day. A profile photo, your name and home city; My Day shows the weather where you live, your markets and news on the topics you follow.

Signed out, all of this stays in the browser. When you create an account, what you chose there carries over.

Images: three models, one rule

You can now pick the image model per request. Only one stays in memory at a time, because two would not fit in 16 GB alongside everything else.

Model Engine Size Typical image
FLUX.2 Klein 4B MLX (mflux), 4-bit 4.6 GB 768×768, 4 steps
Stable Diffusion 1.5 diffusers on Metal, fp16 2 GB 512×512, 30 steps
Stable Diffusion XL diffusers on Metal, fp16 7 GB 1024×1024, 30 steps

The models run without content filters, because Solomon is also a tool for testing image models. One rule is enforced for every model and has no off switch: prompts that pair a minor with sexual or nude content are refused. We narrowed the check after it blocked harmless prompts like "a girl at the beach"; it now needs a clear sign of a minor, such as an age or "little girl".

Every generated image also lands in a new Library, next to the files you uploaded.

Everything around a reply

Part 1 was about getting a good answer; this part added what you do with it.

Feature What it does Privacy detail
Model tag Each reply shows which model wrote it Synced inside the encrypted message
Regenerate Asks again; earlier answers stay behind a 1/3 switcher with a "Regenerated ×2" tag Versions sync encrypted
Good / bad / report Thumbs and a report form with reasons The reply text is sent only if you tick a box
Share A read-only public link to a chat Publishes an unencrypted copy until you delete the link
Library All generated images and uploaded files Images are read from your own decrypted chats
Usage Tokens and images per day and per model, over 7, 30 or 90 days Only counts are stored, never content
Data controls Delete chats, projects, files, images, memories, links or usage, or everything at once Keeps the account, password and encryption passphrase

Every destructive action now uses a slide-to-confirm control: a half slide springs back, and keyboard users press Enter on the handle.

How it fits together now

Part 1 had one web app and one AI service; Solomon is now five services behind one gateway, ready to leave the laptop.

Accounts moved out of the Next.js app into their own small Hono service, so the web app no longer holds any auth secrets. It issues 15-minute signed tokens that the AI service, the Nest API and PowerSync verify on their own. Chat replies still stream straight from the AI service; Caddy passes them through unbuffered, and all services share one Postgres database.

What we learned

The biggest lesson this time: our own defaults can silently overrule the user. Rules like "lead with the answer, skip filler" made the model ignore "always call me Captain" in every test. Saying plainly that the user's instructions come first fixed most of it.

Problem What we changed Result
Base prompt rules overrode custom instructions Told the model user instructions win, and moved them to the end of the system prompt Named address 0/4 → 3/4 replies; "reply in Hindi" 4/4
"Make me a 4-week study plan" generated an image (intent score 0.71 vs a 0.5 cutoff) Also require a visual word (image, logo, draw, paint) 0 false triggers on 14 everyday prompts; 8 of 10 real image asks still detected
Stable Diffusion 1.5 refused to load an fp16-only download Load from the local snapshot folder instead of the repo id Loads offline in a 2 GB download
Streams dropped while an image model loaded Raised the Redis read timeout above the 15 s stream wait No dropped replies during 30–75 s loads
Chat titles came back in ALL CAPS Sentence case, keeping acronyms like SQL and API "Mango is delicious", "SQL study plan"

Two smaller lessons:

  • Test the flow, not the parts. Every feature here was checked by a browser script that signs up a throwaway user, uses the feature end to end and deletes the user. Several problems only showed up there: the ignored custom instructions above, and a section picker that screen readers announced with no name.

  • Encryption shapes features. Sharing, feedback and the library all had to answer one question first: what leaves the browser, and does the user know?

What's next Part 3 goes back to the answers themselves, and to leaving the laptop.

  1. Recency-aware answers. Still the top item from part 1: prefer the newest sources and say when they disagree.

  2. A server deployment. The gateway, auth service and sync are ready to run behind one domain with HTTPS; the models need a GPU box.

  3. Reviewing reports. Feedback and reports are stored, but there is no admin view to read and act on them yet.

  4. Files and images. OCR for scanned PDFs, and editing generated images.

  5. Agents and tools. A calculator, database lookups and multi-step tasks in the LangGraph pipeline.

No comments yet. Be the first to comment.