Skip to content
mdr
All work
beta2026·personal

JANE

A personal AI operating system. Deterministic workflows, append-only audit logs, voice UI.

Screenshot of JANE

TL;DR

  • Audit-first: append-only log, no record mutation or deletion.
  • Deterministic workflows via Inngest — no ad-hoc LLM calls.
  • Memory layer: Postgres + pgvector, inspectable + deletable.
  • Voice & multi-party calls with hierarchy-aware handoff.
  • Type-safe end-to-end with Drizzle + Zod.

Architecture

Flow
CLIENTEDGESERVICESSTORAGEUservoice · web · APIGateway + AuthRBAC · ZodAuth.jsAgent runtimepermissionedWorkflow enginedeterministicInngestMemory serviceinspectableExternal toolexplicit approvalPostgreSQL+ pgvectorDrizzleAudit logappend-only

Modular monolith. Strict service boundaries. Every state change funnels into the append-only audit log.

sync · HTTP / RPCauth · permissionasync · eventdata · read / writeaudit · append

Problem

Most personal-AI projects fail a basic safety bar: they can take consequential actions without showing their work, retain unbounded memory, and call LLMs ad-hoc with no audit trail. The result is software you have to fully trust before you can use — which is exactly backwards.

Approach

JANE is a modular monolith with strict service boundaries. Sensitive actions require explicit approval gates. Memory lives in Postgres + pgvector — inspectable, deletable, with no magic recall. Workflows run on Inngest so every step is deterministic and replayable. Voice and multi-party calls are first-class, not bolt-ons.

Deep dive

Why a modular monolith (and not microservices)

Microservices push complexity to the network. A solo-built personal OS doesn't have the ops budget for that. The modular monolith gives strict boundaries via packages and type signatures without paying the deployment-topology cost. If a service ever needs to break out, the interface is already drawn.

Append-only audit log as a design constraint

Once you commit that no record may be mutated or deleted, a surprising number of design questions answer themselves. Memory becomes a derived view. Permissions become attestations. Bugs become forensics, not mysteries.

Determinism via Inngest

Every workflow step is a function with explicit inputs, outputs, retries, and idempotency keys. LLM calls happen inside steps, never at the top level. Replay a workflow with the same inputs, get the same result — or a deterministic divergence point.

tsworkflows/dailyReview.ts — a deterministic step is just a typed function call
import { inngest } from "@/lib/inngest";

export const dailyReview = inngest.createFunction(
  { id: "daily-review", retries: 3 },
  { cron: "0 8 * * *" },
  async ({ step }) => {
    const entries = await step.run("fetch-entries", () =>
      db.select().from(journal).where(eq(journal.date, today())),
    );

    const summary = await step.run("summarize", () =>
      llm.complete({
        prompt: buildPrompt(entries),
        idempotencyKey: `summary:${today()}`,
      }),
    );

    await step.run("audit", () =>
      db.insert(audit).values({
        action: "daily-review",
        payload: { count: entries.length },
      }),
    );

    return { summarized: entries.length };
  },
);

Outcome

Production MVP. Voice UI, multi-party agent 'board rooms', append-only audit log, day-0 onboarding path (OB-01 through OB-09). Built as a personal OS, designed so anyone could fork it without trust assumptions.

Related

More in ai.