<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Mark Thayer</title>
    <description>The latest articles on Forem by Mark Thayer (@f0rest8).</description>
    <link>https://forem.com/f0rest8</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3180631%2F268029bc-d75c-42e6-9467-b9ecb04995bb.jpeg</url>
      <title>Forem: Mark Thayer</title>
      <link>https://forem.com/f0rest8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/f0rest8"/>
    <language>en</language>
    <item>
      <title>Your Habit Tracker Knows More About You Than Your Therapist. Mine Can’t Read Any of It.</title>
      <dc:creator>Mark Thayer</dc:creator>
      <pubDate>Fri, 17 Apr 2026 16:10:58 +0000</pubDate>
      <link>https://forem.com/mosspigletcorp/your-habit-tracker-knows-more-about-you-than-your-therapist-mine-cant-read-any-of-it-3if0</link>
      <guid>https://forem.com/mosspigletcorp/your-habit-tracker-knows-more-about-you-than-your-therapist-mine-cant-read-any-of-it-3if0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpa9ciudh1hsm8f0tsqu0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpa9ciudh1hsm8f0tsqu0.png" alt="Screenshot of the landing page for Metamorphic, with its blue egg logo of geometric striations of color." width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built a habit tracker where the server has no idea what you’re tracking.&lt;/p&gt;

&lt;p&gt;Every habit app I looked at stores your data in plaintext on their servers. Your daily check-ins, your goals, your mood journal, your streaks — sitting in a database, readable by anyone with access. That felt wrong to me.&lt;/p&gt;

&lt;p&gt;So I built Metamorphic: a habit and self-improvement tracker where all your data is encrypted in your browser before it ever reaches the server. The server only stores opaque blobs of ciphertext. Not even your email address is stored in plaintext.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why encrypt a habit tracker?
&lt;/h3&gt;

&lt;p&gt;Think about what a habit tracker actually contains. It’s not just “drink more water” and a checkbox. Over time, it becomes a detailed map of what you’re trying to change about yourself — your struggles, your patterns, the things you fail at repeatedly. That’s more intimate than most of what you’d share on social media.&lt;/p&gt;

&lt;p&gt;The idea came from watching my partner, who has a background in psychology and behavior science. She’s always thinking about how to break old habits and build better ones. It clicked: if your habits, goals, and self-reflections are this personal, they should be private to only you. And you shouldn’t have to worry about whether they are.&lt;/p&gt;

&lt;h3&gt;
  
  
  The backstory
&lt;/h3&gt;

&lt;p&gt;I run &lt;a href="https://mosspiglet.dev" rel="noopener noreferrer"&gt;Moss Piglet&lt;/a&gt;, a bootstrapped public benefit company. Our other product, &lt;a href="https://mosslet.com" rel="noopener noreferrer"&gt;MOSSLET&lt;/a&gt;, is a privacy-first social platform built with Elixir. When I was becoming a new dad, I’d just finished reading &lt;em&gt;The Age of Surveillance Capitalism&lt;/em&gt; by Shoshana Zuboff — and I wanted a better digital world for my daughter. When Meta rolled back end-to-end encryption on its messaging, I was pushed to implement real E2EE in MOSSLET.&lt;/p&gt;

&lt;p&gt;Metamorphic takes that work further. Instead of encrypting just messages, the entire application is zero-knowledge. The server can’t read your habits, your goals, your reflections, your schedule, your group data — none of it. If our database were fully breached tomorrow, an attacker would get nothing useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Metamorphic actually does
&lt;/h3&gt;

&lt;p&gt;It’s a complete self-improvement platform, not just a checkbox app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Habit tracking&lt;/strong&gt;  — Daily and weekly check-ins, streaks, drag-and-drop reordering, categories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-reflections&lt;/strong&gt;  — A journal with mood tracking and daily prompts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal setting&lt;/strong&gt;  — Milestones, progress bars, and the ability to link goals to habits so check-ins automatically advance your progress&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule and calendar&lt;/strong&gt;  — Recurring events, a day planner, and printable views for people who like paper&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Family and group accountability&lt;/strong&gt;  — Shared habits, shared goals, a group dashboard, and member spotlights&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progress insights&lt;/strong&gt;  — Activity heatmaps and completion stats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data export&lt;/strong&gt;  — JSON and CSV, decrypted entirely in your browser. The server never sees the plaintext, even during export&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing I feel strongly about: &lt;strong&gt;encryption is not a premium feature.&lt;/strong&gt; Every tier — including the free one — gets full end-to-end encryption. Paid tiers unlock convenience features like unlimited habits, reminders, data export, and groups. But privacy is not something you should have to pay extra for.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/fGA40p1Fqew"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  How the privacy works (without the jargon)
&lt;/h3&gt;

&lt;p&gt;When you create a habit, type a journal entry, or set a goal, your browser encrypts that data before sending it to the server. The server stores it, but has no way to read it. When you load the page later, the server sends the encrypted blobs back, and your browser decrypts them using keys that only exist on your device.&lt;/p&gt;

&lt;p&gt;Your password is never stored or transmitted in a usable form. Instead, it’s used to derive a cryptographic key locally, and that derived key unlocks everything else. If you lose your password and haven’t set up a recovery key, your data is gone — by design. That’s the real trade-off of zero-knowledge, and it’s the correct one.&lt;/p&gt;

&lt;p&gt;For the more technically inclined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client-side encryption&lt;/strong&gt; uses libsodium (XSalsa20-Poly1305)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key distribution&lt;/strong&gt; uses a hybrid post-quantum scheme: ML-KEM-768 combined with X25519 — the same approach Signal and Apple iMessage have adopted to protect against future quantum computers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three independent encryption layers at rest&lt;/strong&gt; : client-side E2E, AES-256-GCM in Postgres, and LUKS disk encryption on the hosting infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-knowledge email&lt;/strong&gt; : no plaintext email column in the database. Only a one-way hash for lookups and an encrypted blob&lt;/li&gt;
&lt;li&gt;A detailed architecture writeup is at &lt;a href="https://metamorphic.app/encryption" rel="noopener noreferrer"&gt;metamorphic.app/encryption&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The interesting tension
&lt;/h3&gt;

&lt;p&gt;Metamorphic is built with Phoenix LiveView, a framework where the server renders the page. But in a zero-knowledge system, the server can’t render the &lt;em&gt;content&lt;/em&gt; — it doesn’t know what it says. The result is a choreography: the server sends the page structure with placeholder skeletons, and JavaScript hooks decrypt and fill in the real content on arrival.&lt;/p&gt;

&lt;p&gt;It works. The skeletons flash in briefly, then the real data appears. UX-wise, it’s not dramatically different from any app with a loading state. Architecturally, it’s a very different beast — 15+ JavaScript hooks managing the encrypt/decrypt lifecycle across habits, goals, reflections, events, groups, and export.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real trade-offs
&lt;/h3&gt;

&lt;p&gt;I won’t pretend zero-knowledge doesn’t have costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No server-side search.&lt;/strong&gt; If you want to filter habits by name or search your reflections, that happens client-side after decryption. Fine at our current scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you lose your password and your recovery key, your data is unrecoverable.&lt;/strong&gt; This is a real UX concern. The recovery key flow mitigates it, but the fundamental constraint is by design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing is harder.&lt;/strong&gt; You can’t assert on decrypted content in server-side tests because decryption only happens in JavaScript. Tests verify DOM structure and that encrypted fields are stored correctly — the decrypt-and-display pipeline is the gap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are trade-offs I’m willing to make. Your habit data being unreadable to everyone except you — including me — is worth it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it
&lt;/h3&gt;

&lt;p&gt;I’m not very good at habit tracking myself, which is partly why I built this. I’ve been using Metamorphic to get back into yoga, meditation, and running. So far, so good.&lt;/p&gt;

&lt;p&gt;Check it out at &lt;a href="https://metamorphic.app/" rel="noopener noreferrer"&gt;metamorphic.app&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>security</category>
      <category>elixir</category>
      <category>privacy</category>
    </item>
    <item>
      <title>I Built a Zero-Knowledge Encrypted Habit Tracker with Elixir &amp; Phoenix LiveView</title>
      <dc:creator>Mark Thayer</dc:creator>
      <pubDate>Thu, 16 Apr 2026 23:16:47 +0000</pubDate>
      <link>https://forem.com/f0rest8/i-built-a-zero-knowledge-encrypted-habit-tracker-with-elixir-phoenix-liveview-3jc9</link>
      <guid>https://forem.com/f0rest8/i-built-a-zero-knowledge-encrypted-habit-tracker-with-elixir-phoenix-liveview-3jc9</guid>
      <description>&lt;p&gt;I'm the solo dev at &lt;a href="https://mosspiglet.dev" rel="noopener noreferrer"&gt;Moss Piglet&lt;/a&gt;, a bootstrapped public benefit company. I've been building &lt;a href="https://metamorphic.app" rel="noopener noreferrer"&gt;Metamorphic&lt;/a&gt; — a habit and self-improvement tracker where all personal data is encrypted client-side before it ever reaches the server. The server only stores opaque cipher-text blobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why encrypt a habit tracker?
&lt;/h2&gt;

&lt;p&gt;I was inspired by my partner's background in psych and behavior science. It clicked that something as personal as your habits, goals, and self-reflections — basically a map of what you're trying to change about yourself — should be private to only you, and you shouldn't have to worry about it being otherwise.&lt;br&gt;
Every other habit tracker I looked at stores your data in plaintext. Metamorphic doesn’t.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Habit tracking&lt;/strong&gt; — daily/weekly check-ins, streaks, drag-and-drop reordering&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Self-reflections&lt;/strong&gt; — mood tracking and daily prompts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Goal setting&lt;/strong&gt; — milestones, progress bars, habit linking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Schedule/calendar&lt;/strong&gt; — recurring events, day planner, printable views&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Family/group accountability&lt;/strong&gt; — shared habits, shared goals, group dashboard&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Progress insights&lt;/strong&gt; — activity heatmaps, completion stats&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data export (JSON/CSV)&lt;/strong&gt; — decrypted entirely client-side, server never sees plaintext&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Encryption is not a premium feature.&lt;/strong&gt; Every tier gets full E2E encryption. Paid tiers gate convenience (unlimited habits, reminders, export, groups), not privacy.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the crypto works
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Client-side encryption via &lt;code&gt;libsodium-wrappers-sumo&lt;/code&gt; — XSalsa20-Poly1305 for data, NaCl box/seal for key distribution&lt;/li&gt;
&lt;li&gt;Hybrid post-quantum key encapsulation (ML-KEM-768 + X25519 via &lt;code&gt;@noble/post-quantum&lt;/code&gt;) — the same approach as Signal and Apple iMessage&lt;/li&gt;
&lt;li&gt;Three independent encryption layers at rest: client-side E2E, Cloak AES-256-GCM in Postgres, and LUKS disk encryption on &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zero-knowledge email: no plaintext email column in the database — only an HMAC blind index for lookups and an E2E-encrypted blob&lt;/li&gt;
&lt;li&gt;Password never touches sessionStorage — only the Argon2id-derived session key&lt;/li&gt;
&lt;li&gt;Persistent key cache using Web Crypto API (non-extractable AES-256-GCM wrapping key in IndexedDB) so browser restarts don't require re-entering your password&lt;/li&gt;
&lt;li&gt;Recovery key flow for password reset without server access to private keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More detail on the architecture: &lt;a href="https://metamorphic.app/encryption" rel="noopener noreferrer"&gt;metamorphic.app/encryption&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The interesting tradeoff: LiveView + zero-knowledge
&lt;/h3&gt;

&lt;p&gt;This is the part I think other Elixir/Phoenix devs will find most relevant.&lt;/p&gt;

&lt;p&gt;LiveView is server-rendered by design. Zero-knowledge encryption means the server can't see the content it's rendering. These are fundamentally in tension.&lt;/p&gt;

&lt;p&gt;The result: brief placeholder skeletons that JS hooks fill in after client-side decryption, and a lot of &lt;code&gt;push_event/handleEvent&lt;/code&gt; choreography (15+ hooks). It's not too different UX-wise from a trust-the-server model — the skeletons flash in briefly — but architecturally it's a very different beast.&lt;/p&gt;

&lt;p&gt;Other tradeoffs:&lt;/p&gt;

&lt;p&gt;No server-side search on encrypted fields. Filtering by habit name or reflection text happens client-side after decryption. Fine at current scale.&lt;/p&gt;

&lt;p&gt;Testing is harder. You can't assert on decrypted content in LiveView tests since decryption is JS-only. Tests focus on DOM structure and data attributes. Context-level tests verify encrypted fields are stored and retrieved correctly — the decrypt-and-display pipeline is the gap.&lt;/p&gt;

&lt;p&gt;If you lose your password and haven't set up a recovery key, your data is gone. By design. Real UX tradeoff, but correct for zero-knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Elixir/Phoenix LiveView&lt;/strong&gt; — full-stack web app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecto + Postgres&lt;/strong&gt; (&lt;a href="https://fly.io" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt; Managed Postgres)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;libsodium-wrappers-sumo + &lt;a href="https://github.com/paulmillr/noble-post-quantum" rel="noopener noreferrer"&gt;@noble/post-quantum&lt;/a&gt;&lt;/strong&gt; — client-side crypto&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloak/cloak_ecto&lt;/strong&gt; — application-level at-rest encryption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oban&lt;/strong&gt; — background jobs (reminders)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS v4 + daisyUI&lt;/strong&gt; — UI/theming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sortable.js&lt;/strong&gt; — drag-and-drop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSZip&lt;/strong&gt; — export packaging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tidewave&lt;/strong&gt; — AI-assisted development (runtime introspection, live SQL/eval, a11y diagnostics)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot was shared from my work on &lt;a href="https://mosslet.com" rel="noopener noreferrer"&gt;MOSSLET&lt;/a&gt;, a privacy-first social platform with private journal and Bluesky interop, also built with Elixir.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it
&lt;/h3&gt;

&lt;p&gt;I'm not very good at habit tracking myself, so I've been using Metamorphic to get back into yoga, meditation, and running. So far so good.&lt;/p&gt;

&lt;p&gt;Check it out at &lt;a href="https://metamorphic.app" rel="noopener noreferrer"&gt;metamorphic.app&lt;/a&gt;. Happy to answer questions about the architecture, the zero-knowledge approach, bootstrapping a public benefit company, or anything Elixir-related.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>showdev</category>
      <category>security</category>
      <category>privacy</category>
    </item>
  </channel>
</rss>
