Arkive

Synergy: System Design

As of
Version1.4.0
Kindspec
Length4,310 words, about 19 min
Tagssystem-designsynergy

How Synergy is built. The PRD and spec say what it does; this page and the decisions it links say where each piece lives and how the pieces meet. Terms follow Mentions and link lifetime.

D198 decision #synergy #database: Synergy is a graph pattern on plain PostgreSQL, not a graph database, and its own repository is the only access path and the one place to change if scale ever needs a graph engine. derived-from D8

Synergy is a graph pattern, not a graph database. At this scale, plain PostgreSQL tables with recursive queries are enough, and everything goes through Synergy's own repository, which is the one place to change if scale ever calls for a dedicated graph engine.

Packages

synergy-packages

An arrow means "imports". The features registry and the type packages register their linkable types with synergy/server; apps/app renders links with synergy/react. Only foundation/core talks to Postgres.

Package Holds
packages/core (foundation) DB client and RLS (withRLS), auth (resolveApiCaller), withApiGuard, entitlements, logging. Unchanged by Synergy.
packages/platform/synergy (platform) Synergy's tables and migrations, its repository (the only access path), the rules, the resolver and renderer contracts, the save call, and the Sneak Peek Link component.
packages/ui (foundation) Design-system primitives the component builds on; later the editor and the Lexicon matcher.
Providers (_sandbox now, features later) Their own entity tables, plus one registration per linkable type.
packages/features-registry or the app Assembles every provider's registrations into the maps Synergy receives as data.
apps/app Guarded API routes and the playground; fetches and translates links for the Sneak Peek Link.

D199 decision #synergy #monorepo: Synergy ships three entry points, /server, /react and /contracts, so a browser bundle can never pull in database code. derived-from D57 derived-from D17

Synergy ships three entry points, so a browser bundle can never pull in database code:

  • @sidekick/synergy/server: the repository, the save call and the resolvers' contract. It imports server-only.
  • @sidekick/synergy/react: the Sneak Peek Link component and the renderers' contract. No database code, so it runs on the server and in the browser.
  • @sidekick/synergy/contracts: zod schemas and types shared by both, the content helpers (extractRefs, the quote re-matcher) and the error codes.

See Platform layer and Dependency flow.

Type registration

D200 decision #synergy #registry: Each linkable type is registered by its provider in two halves, a server half that resolves and a pure React half that renders, and the registry hands Synergy the maps as data, so Synergy never imports a provider. derived-from D187 derived-from D182

Each linkable type is registered by the package that provides it, never listed in Synergy. The registration comes in two halves, a server half and a React half, one per entry point:

TypeScript
// server half, imported from '@sidekick/synergy/server'
interface LinkableTypeServer {
   provider: string; // the registering package, e.g. 'sandbox-notes', 'taxila'
   type: string; // e.g. 'note', 'datum', 'tweet'
   entitlement: string; // feature key whose entitlement gates it, e.g. 'sandbox-notes'
   // the words Synergy draws itself, as keys in the provider's own catalog (D250)
   messages: {
      label: MessageRef;
      count?: MessageRef;
      description?: MessageRef;
   };
   // batched: one call per provider per page; returns JSON only, so it can be cached and sent to any consumer
   resolve(
      tx: Tx,
      requests: readonly ResolveRequest[],
   ): Promise<ReadonlyMap<string, RenderData>>;
   // writes an anchor mark into the target's content when a link to a passage is made; returns the anchor id
   addAnchor(tx: Tx, entityId: string, at: PassageAddress): Promise<string>;
}

// React half, imported from '@sidekick/synergy/react'
interface LinkableTypeReact {
   type: string;
   // pure: no fetching, no hooks, no browser APIs; `word` looks a MessageRef up in the host's `words` (D251)
   render(
      data: RenderData,
      display: "card" | "preview",
      word: (ref: MessageRef) => string,
   ): ReactNode;
}

resolve fetches and always runs on the server; render only turns the fetched data into React, so it runs wherever the component runs. Sidekick renders in both places: in a server component for a page's first paint, and in the browser when the editor inserts or changes a link, where the App's client wrapper fetches the new link's data through POST /links/resolve and the component renders it on the spot (D251). A third party (Notion, Slack, a bot) uses the same JSON and renders it its own way. The registry or the app builds both maps and passes them to Synergy, so neither core nor Synergy imports a provider (research 05, option A). Feature flags are separate and come later.

Keys, never copy

D201 decision #synergy #copy: Synergy stores and returns keys only (types, statuses, states, error codes, message references); every word comes from a catalog, the provider's for its words and Synergy's for its own, and only user content is stored as written. derived-from D243

Synergy holds no user-visible text (Pratik, 2026-10-31; catalogs since Internationalization, 2026-11-06). Everything it stores or returns is a stable key, so a term can be renamed or translated without a migration or an API change:

  • provider and type on registrations and index rows (sandbox-notes, note). The type's label ("Note") lives in the provider's catalog, and the registration names its key (D250); deleting a provider deletes its words.
  • Relation types store a source_key and a target_key, named by the end that reads them (explained-by at the source, explains at the target); "explained by" on screen comes from Synergy's own catalog, as do link states and marks. Synergy may build keys only in its own synergy namespace. User-defined types (post-MVP) are the exception, because their names are the user's own content.
  • Statuses, states, marks and display types are enums (deprecated, no_longer_linked, passage_removed), and error codes carry no message; the client looks up the message by code.
  • The resolved link and every API response carry keys only. The host turns them into words (D251); a third party maps them its own way, with Synergy's exported catalog and the providers'.

D250 decision #synergy #i18n: Every word a provider hands to Synergy is a message reference, { key, values? }, with a fully qualified key the provider names: in its registration for the words Synergy draws itself, and anywhere in its render data for the rest; Synergy never builds, parses or stores a provider's key. derived-from D201 derived-from D243

TypeScript
// /contracts
type MessageRef = { key: string; values?: Record<string, string | number> };

A naming convention (<provider>.type.<type>) only covers words Synergy can predict (Pratik, 2026-11-06). With references:

  • Synergy keeps no provider words and assumes no provider keys: the provider names each key.
  • Any word can travel: a status, a field label, a plural count. values fills the ICU message's blanks ({count}, {folder}), never translations; a reference holds no words in any language.
  • The registration's messages slots cover what Synergy draws without calling the resolver (inline and minimal mentions, search rows): label, count, description. More slots are added when Synergy needs them; nothing else changes.
  • TypeScript checks the keys: a provider types its refs against its own en.json with use-intl's MessageKeys, and a registry test checks every registration ref against the merged catalogs, as Atlassian Forge and Shopify check manifest keys at deploy time.
  • Precedent: hosts that draw a plugin's words have the manifest name the key (VS Code's %key%, Chrome's __MSG_key__, Forge, Shopify). Research: the project's i18n-ui/provider-copy-options.md.
  • Keep a provider's word as a standalone label: dropping a noun into one of Synergy's sentences breaks D244 in languages where nouns change form.
  • The same shape carries validation errors (D252).

User content (titles, display names, labels, change notes, tag names) is stored as written.

Tables (Synergy's migrations)

synergy-tables

An arrow points from a table to the tables that hang off it. relationships.from_id and to_id are entity_index ids (left out of the drawing to keep it readable). The outbox and idempotency keys are not synced and are hard-deleted.

Every table: client-generated UUIDs, user_id, created_at, updated_at, provenance (actor kind: person, system, agent or API key; actor id; reason), and RLS comparing user_id = nullif(current_setting('app.current_user_id', true), '')::uuid. Syncable tables soft-delete; every unique index on them is partial (WHERE deleted_at IS NULL), so a tombstone never blocks re-adding the same tag or saving the same item again. How tombstones stay visible to Synergy is in Tombstones.

  • entity_index: id, provider, type, display name, optional title, status (active, deprecated, superseded), version, revision, content_seq, edited_at, deleted_at. "Deleted" is shown from deleted_at, not stored as a status, so a restore brings back whatever status the entity had. No external-reference columns (Capture external content).
  • content_seq goes up on every write to an entity's content: revision saves, version saves, and anchors added for someone else's link. It is the token for the stale-write check, the ETag and the render cache key. version and revision keep their meaning and only drive the dots (Content sequence).
  • version_log: entity, version, optional change note, actor, time.
  • entity_anchors: entity, anchor id, removed_in_version (empty while the passage exists). One row per passage that a link points at, written when the first link to it is made. A reference whose anchor row has removed_in_version set shows "passage removed".
  • entity_mentions: entity, relationship id. The direct and alias mentions in the entity's content, as last reported by its provider (Save content). relationships.mentioned is kept true while the relationship's source has a row here.
  • relationships: from, to, role (solo, list or member), parent and position (members), optional label, type (never empty), version and revision snapshot, to_anchor_id and to_anchor_quote (empty for a whole-entity target), cited, mentioned, tombstone (actor, reason, deletion_batch_id).
    • Members copy their list row's from, type and role into a composite FK (parent_id, from_id, type, parent_role) → (id, from_id, type, role) with parent_role fixed to list by a CHECK, so a member can't point at another member and every member is a complete edge with its own type. A list row has no to; solos and members do (CHECK).
    • type is NOT NULL so the FK can't be skipped (Postgres ignores a composite FK when any column is null). An untyped link uses the seeded system type untyped, kind reference, which displays no type name.
    • Positions are fractional text keys (lexorank) with a unique index on (parent_id, position), so moving one member writes one row.
    • deletion_batch_id groups the tombstones written by one delete, so a restore brings back exactly that batch.
  • relation_types: source_key (the type's identity, which relationships.type references), target_key, kind (reference or association; untyped and superseded-by are system rows of kind reference, not extra kinds), status, system flag; seeded with the starter vocabulary plus untyped, including violates (association) and exception-to (reference) (Violations and exceptions). Labels live in Synergy's own catalog.
  • tags and tag_applications: as in the spec, with the format check constraint.
  • outbox: event type, subject, actor, payload, time, and xact_id (pg_current_xact_id()), which lets a reader process events in commit order. A long transaction can commit a lower bigserial id after a reader has moved past it; the transaction id can't be rebuilt later, so it is stored from the first row. Event types: entity created, content saved, version bumped, status changed, entity deleted, restored or erased; relationship created, updated (label or type), cited, uncited, deleted or restored; snapshot moved (the referencer confirmed the link still holds); passage removed; tag created, renamed, merged or deprecated; tag applied or removed. Read by a dedicated read-only role outside RLS, since readers work across users. 90-day retention after every reader has processed it.
  • idempotency_keys for creates.

The outbox and idempotency keys are non-syncable: hard delete, no soft-delete triggers, so pruning works.

Each provider table has a deferrable foreign key to entity_index(id), so a provider row can't exist without its index row.

Tombstones

Synergy must see its own tombstones: a deleted target still shows its name, "No longer linked" must differ from "never existed", and undo and restore update deleted rows. Three of the existing database templates prevent that, so Synergy departs from them (Tombstone visibility):

  • RLS compares only user_id. The repository filters deleted_at IS NULL in each query that needs live rows. The template in Row-level security also hides deleted rows in USING.
  • Restore may update a deleted row. The update trigger allows an update to a deleted row only when it restores it (NEW.deleted_at IS NULL). Every other update to a tombstone is still refused.
  • Hard delete only on the non-syncable tables (outbox, idempotency keys), which carry no soft-delete triggers.

Indexes

to_id (backlinks), (to_id, to_anchor_id) (passage check), from_id, the unique (parent_id, position), entity_anchors (entity_id, anchor_id), entity_mentions (entity_id) and (relationship_id), tag applications by tag, relationships (user_id, type) (links by type across the graph), index rows by owner and status, an index on outbox xact_id, and the search indexes. Trigram and full-text GIN indexes lead with user_id (btree_gin: (user_id, display_name gin_trgm_ops) and the same for the simple tsvector), so a search reads one user's rows instead of every user's.

Write path

A provider saves inside one withRLS transaction: it writes its own row, then calls Synergy in the same transaction.

synergy-save

D202 decision #synergy #concurrency: Every Synergy write takes the per-user advisory lock before it reads anything, so the delete block and the cycle check can't race and there is one lock order. derived-from D117 derived-from D95

Every Synergy write takes the per-user lock first: pg_advisory_xact_lock(hashtextextended(user_id::text, 0)), before it reads or writes anything. That covers the delete block and the cycle check against each other (a delete and a new reference into the same target can't both commit), and one fixed lock order means no deadlocks between a save and a link create. For one user the contention is negligible.

  • Create: register the entity's index row (id, provider, type, display name).

  • Save content: the provider sends the base content_seq, revision or version, the optional change note, and the current sets it extracts from the new content with extractRefs: every block and anchor id, and every relationship id the content mentions. It also declares the links this save creates (below). Synergy then:

    1. checks content_seq (409 stale_content on a stale one);
    2. compares the sets with entity_anchors and entity_mentions itself;
    3. refuses passage_referenced if a reference points at an anchor that's gone and this isn't a new version; on a new version, sets removed_in_version on those anchor rows;
    4. tombstones associations into gone anchors, moving only their sources' updated_at (actor system, with the reason);
    5. refuses a mention whose relationship has neither end at this entity;
    6. updates entity_mentions and mentioned, and tombstones links with neither cited nor mentioned;
    7. bumps content_seq, the revision or version, and edited_at, and writes the outbox events.

    Sending the current set instead of the changes makes the call self-healing (a missed or buggy save is corrected by the next one) and safe to retry, and the comparison is written once, in Synergy (Anchors in content).

  • Link from content: the editor generates the relationship id, writes it into the mark, and the save that carries the mark declares the new link (target, anchor, type, label). Synergy creates it in that transaction with mentioned = true and cited = false, so removing the text later removes the link.

  • Link from a field, the links panel or the API (POST /links): creates a cited link (cited = true).

  • Every link create snapshots the target's version and revision and runs the cycle check for a reference. A passage target calls the target provider's addAnchor, which writes the mark into the target and moves its content_seq and updated_at, never its version or revision. The response carries an anchor receipt per passage target, { targetId, contentSeq, anchor: { id, blockId, quote } }, so an editor in the same page that has the target open adds the mark itself and moves its base content_seq (no 409). Not the whole target: version and revision don't change on an anchor write, and the request was about the source. An editor the receipt can't reach (another tab, another device) gets 409 on its next save; it fetches the latest content, copies in the anchors it lacks (by block id and quote) and saves again, with nothing shown to the user. The 409 merge is the guarantee; the receipt only saves a round trip.

  • Change a link's type (PATCH /links/:id): runs the cycle check when the new type is a reference. A change from an association to a reference also moves the snapshot to the target's current version and revision, so a waived violation (violates retyped to exception-to) starts without a dot. An open violation is a live violates link; resolving it is DELETE /links/:id. There is no violation status (Violations and exceptions).

  • Supersede: a superseded-by link, stored from the old entity to each replacement, kind reference. An entity may have any number of successors. Creating the first one marks the source superseded, after the confirmation that reports how many entities reference it (confirmation_required until the request confirms). Removing the last one sets the source back to active.

  • Status, tags, cite and uncite: metadata writes that bump no counter.

  • Delete: refused with delete_blocked while a live reference points at the entity; otherwise soft-delete, which tombstones its outgoing links under one deletion_batch_id. Erasure overrides.

  • Restore and undo (restore an entity, undo an unlink, relink): bring back the same rows, but only after re-running the delete block and the cycle check under the lock, because the graph may have changed since. A restored reference into a tombstone, or one that would close a cycle, is refused with restore_conflict, naming each edge.

D203 decision #synergy #save: A save reports the current sets of block, anchor and mentioned relationship ids, and Synergy works out what changed, so the call heals itself after a missed save and is safe to retry. derived-from D61 derived-from D67

D204 decision #synergy #staleness: Every link create snapshots the target's version and revision, and a reference create runs the cycle check. derived-from D109 derived-from D94

D205 decision #synergy #anchors: A link into a passage returns an anchor receipt, so an editor that has the target open adds the mark itself; the 409 merge on the next save is the guarantee. derived-from D63 derived-from D61

D206 decision #synergy #supersede: superseded-by is a reference stored from the old entity to each of any number of replacements; the first one marks the source superseded after a confirmation, and removing the last sets it back to active. derived-from D80 derived-from D81

D207 decision #synergy #restore: Restore and undo re-run the delete block and the cycle check under the lock, and are refused with restore_conflict naming each edge. derived-from D119 derived-from D98

Read path

  1. The guarded route reads the caller's relationships joined to the target index rows: one query per page, cursor-paged.
  2. For each link it decides the state on the server, before any resolver runs: unknown (the type's provider isn't registered; shown like locked), locked (the type's entitlement isn't enabled for the caller), deleted, redacted (later), then the marks (edited, changed) and "passage removed" from the snapshot and entity_anchors.
  3. Inline and minimal mentions need nothing more. Card and preview mentions are grouped by provider and resolved with one batched resolve call each, through the render cache keyed by (entity, content_seq, display type).
  4. The cache holds render data only. Status, states and marks are read fresh from the index on every request, including the states of links shown inside a live preview: a preview's render data carries relationship ids, never their states.
  5. The response is the resolved link (frozen as a zod schema in /contracts): relationship, target index fields, state, marks, and render data when asked for. An entity's read response also carries the roll-up of its outgoing references and ETag: "<content_seq>".

D208 decision #synergy #cache: The render cache holds render data only; status, states and marks are read fresh on every request, including for links inside a live preview. derived-from D177 derived-from D175

API

Entity content (create, save, delete, restore) goes through each provider's own routes, which call Synergy in the same transaction. Synergy's routes, all through withApiGuard, under /api/synergy:

Method and path Request Response Errors
GET /entities/:id If-None-Match (optional) index fields, roll-up, ETag; 304 when unchanged not_found
PATCH /entities/:id/status { status: 'active' | 'deprecated' } index fields not_found
GET /entities/:id/versions cursor version log page not_found
GET /entities/:id/links direction (out or in), type (optional), cursor resolved links page (in = backlinks) not_found
POST /links id, from, to, anchor, type, label, confirm; idempotency resolved link, anchor receipt cycle, locked, deprecated_vocabulary, confirmation_required, not_found
PATCH /links/:id label, type, cited, list position resolved link cycle, deprecated_vocabulary, not_found
DELETE /links/:id none tombstone not_found
POST /links/:id/restore none resolved link restore_conflict, not_found
POST /links/:id/snapshot none (moves the snapshot: "still holds") resolved link not_found
POST /links/resolve [{ relationshipId, display }] resolved links, in request order none per item: a missing one resolves as not found
GET /links type, cursor resolved links page, across every provider none
GET /search q, type, provider, status, tag, cursor index rows page none
GET /tags, POST /tags cursor; name, description; idempotency tags page; tag invalid_tag
PATCH /tags/:id rename, description, deprecate, merge into tag invalid_tag, not_found
PUT / DELETE /tags/:id/applications entity or relationship id application deprecated_vocabulary, not_found
GET /relation-types none vocabulary none

POST /links/resolve is how a client asks for card and preview data: the server never parses content, so only the client knows each mention's display type.

"Page updated"

D210 decision #synergy #concurrency: A page learns that its entity changed elsewhere by asking GET /entities/:id with If-None-Match, which answers 304 while nothing changed; pushing changes waits for post-MVP. derived-from D63

A page someone is viewing or editing can learn that the entity changed elsewhere (another device, an agent, a bot) and offer "Page updated, reload". The foundation is already in the API: GET /entities/:id with If-None-Match: "<content_seq>" answers 304 with no body while nothing changed, so a check is one indexed read. Any module's page can use it, because the check is per entity in Synergy, not per module.

  • MVP client strategy (built with the shared editor, not in Phase 3): check when the tab regains focus or becomes visible, and every 30 seconds while it is visible; tabs of one browser tell each other through BroadcastChannel. While editing, the banner warns early; the 409 merge still protects the save.
  • Post-MVP: push instead of polling, fed by the outbox (server-sent events or Supabase Realtime broadcast from the server). It changes how the client hears about a change, not the API.

D209 decision #synergy #api #security: Another user's ids answer not_found, the same as ids that never existed, so a response never reveals whether an id exists. derived-from D172

Error code HTTP
validation failure 400
not signed in (from the guard) 401
locked (link into a provider the account doesn't have) 403
not_found: also for another user's ids, so a response never reveals whether an id exists 404
stale_content, delete_blocked, passage_referenced, cycle, restore_conflict, confirmation_required 409
invalid_tag, deprecated_vocabulary 422

D251 decision #synergy #react: The Sneak Peek Link takes plain data only, the resolved link and a words dictionary; the host fetches the link and translates its references, so no function and no i18n provider crosses into the component. derived-from D186 derived-from D249 derived-from D250

Lives in Synergy (/react) and builds on ui primitives. It renders on the server and in the browser, owns the frame and every state, and calls the registered renderers with the resolved render data. The display type belongs to each mention.

TSX
// a server component in apps/app
const t = await getTranslations();
const link = await synergy.resolve(request); // MessageRefs, keys only
<SneakPeekLink link={link} words={translateRefs(link, t)} />;
// words: { "sandbox-notes.type.note": "Note", "synergy.state.no_longer_linked": "No longer linked", … }
  • translateRefs(link, t) (Synergy, /react) walks the link, collects every MessageRef (the provider's and Synergy's own state and relation words) and returns plain key-to-text pairs. When one key appears with different values, the dictionary key includes the values.
  • Plain data only. A server component can't pass a function to a client component, so the earlier transport prop (resolveLinks(requests) => Promise<ResolvedLink[]>) is gone (Pratik, 2026-11-06). The host makes the request: Sidekick's server component calls the resolve handler directly for first paint; when the editor inserts a link, a client wrapper in the App, whose fetch code lives in a client module, calls POST /links/resolve with the session cookie and translates with next-intl's client useTranslations; a third party calls the API with its own credentials and translates with Synergy's exported catalog and the providers'.
  • Overrides the PRD and spec (D186): the component stays host-agnostic with no app-wide context; only the transport moves out of it, into the host.
  • No i18n library inside the component, the same rule as ui (D249). It works in any host, and it is "data in, HTML out", the easiest thing to test.

Content helpers

D211 decision #synergy #save: Every provider builds the save call's sets with the shared extractRefs, and the quote re-matcher asks the user when a match is weak instead of guessing. derived-from D203 derived-from D1

  • extractRefs(content) walks Tiptap JSON and returns the block and anchor ids and the mentioned relationship ids. Every provider uses it to build the sets for the save call.
  • The quote re-matcher finds a quote in new content: Markdown import and Refresh of captured external content use it to re-attach anchors. When the best match is weak, the user is asked instead of the match being guessed.
  • Post-MVP candidate: a block-level patch endpoint for bots and agents, which handle whole Tiptap documents with marks they don't understand poorly.

Testing

Integration tests through the guarded API are the main seam; the component is tested in Vitest browser mode with MSW (Testing layers). Synergy adds:

  • Race tests with two database connections: an anchor added while the target is open (stale save gets 409), a delete and a new reference into the same target (one fails), and a restore after the graph changed (restore_conflict).
  • A test pinning spec story 71 ("dep wor" finds "deep work"), tuning trigram word_similarity until it passes.

Design Decisions

Each decision lives in its own page here; the decisions log lists them with dates.

Decision History

  • 2026-11-06 · accepted · Words from catalogs (D201 revised), message references (D250), the Sneak Peek Link takes plain data (D251); apps/web is now apps/app
Arkive

Index

Notes, decisions, and progress on my journey as I build Project Sidekick — built in the open; written as it happens.

Tags (145)

View

242 entries.

As ofTitleKind
2026-11-11Synergy Lesson 0 Walkthrough: One Repobuild walkthrough phase-3 monorepo one-repo git cloudflareguidance
2026-11-11Hosting and Domainssystem-design deployment vercel cloudflare domainspec
2026-11-11Synergy Lesson 0: One Repoplan phase-3 task monorepo one-repo git cloudflareplan
2026-11-11Synergy Checkpoint 3a: Prove the Store, Plan 3bplan phase-3 checkpoint guidanceplan
2026-11-11Synergy Lesson 1: Layer Folders and Lintplan phase-3 task monorepo eslintplan
2026-11-11Synergy - Feature Specificationsprd spec synergyprd
2026-11-11Agent Guideai-coding agent gateway agent-guidance rls supabase drizzle api react prettierguidance
2026-11-11Backlogged / Unplannedplan living-plan backlog feature-system taxila zinsser alter-ego parrot rls supabaseplan
2026-11-11Synergyplan living-plan phase-3 synergy rls postgresql api graphplan
2026-11-09Notesai-coding-harness agent-guidance nextjs eslint pnpm cssguidance
2026-11-08Synergy Lesson 4: Sandbox Providers and the First Routesplan phase-3 task synergy feature-system apiplan
2026-11-08Violations and Exceptionssystem-design synergyspec
2026-11-08Testing Layerssystem-design testing vitest playwrightspec
2026-11-08Best Practice Rulessystem-design code-quality-check eslintspec
2026-11-08Front Door: Hardening Walkthroughbuild walkthrough pre-2 rls supabase drizzle postgresql testing eslintguidance
2026-11-08Alter Egoplan living-plan phase-6 taxila zinsser alter-ego war-room factory core-driveplan
2026-11-08API Versioningsystem-design apispec
2026-11-08Approve Buildssystem-design monorepo nextjs pnpmspec
2026-11-08Best Practicesai-coding-harness agent-guidance drizzle api react pnpm css offline embedding soft-deleteguidance
2026-11-08Centralized Copysystem-design contentspec
2026-11-08dotenv CLIsystem-design config clispec
2026-11-08Installation at Workspace Levelsystem-design code-quality-check typescript pnpmspec
2026-11-08Pocketplan living-plan phase-8 taxila alter-ego nextjs vercel pwa mobileplan
2026-11-08Server Actionssystem-design nextjs rls api authenticationspec
2026-11-08Taxilaplan living-plan phase-4 taxila api-guard rls drizzle api authenticationplan
2026-11-08War Roomplan living-plan phase-7 war-room factory core-drive rls api offlineplan
2026-11-08With API Guardsystem-design security api-guard rls api authentication typescriptspec
2026-11-08Zinsserplan living-plan phase-5 taxila zinsser api mantine ai embeddingplan
2026-11-06Design Tokenssystem-design css design-systemspec
2026-11-06Native UIsystem-design css design-system mantinespec
2026-11-06Public Site: System Designsystem-design site one-repospec
2026-11-06Internationalizationsystem-design content i18nspec
2026-11-06Decisions Logdecisionlog
2026-11-06Synergy: System DesignReadingsystem-design synergyspec
2026-11-06CSS Modulessystem-design css eslint stylelintspec
2026-11-06Dependency Flowsystem-design monorepo clispec
2026-11-06ESLint Plugin Boundariessystem-design code-quality-check eslintspec
2026-11-06Non-Syncable Tablessystem-design database offlinespec
2026-11-06Prettier at Repo Levelsystem-design code-quality-check prettierspec
2026-11-06Runtime Validationssystem-design typescriptspec
2026-11-06Shared tsconfigsystem-design code-quality-check typescriptspec
2026-11-06Syncable Tablessystem-design database offline soft-deletespec
2026-11-06Technology Stacksystem-design supabase drizzle postgresql nextjs typescript turborepo pnpm vercelspec
2026-11-06Architectural OverviewSidekick's architectural overview — an API-first platform tuned for solo developerssidekick project technical architecturedocument
2026-11-05One Repoprd feature synergy one-repoprd
2026-11-05Overview of Synergyprd feature synergyprd
2026-11-03Commands and Environmentai-coding command environment agent-guidance prettier pnpm cliguidance
2026-11-01Synergy Lesson 10: Save Call, Anchorsplan phase-3 task synergy apiplan
2026-11-01Synergy Lesson 11: Delete and Restoreplan phase-3 task synergy databaseplan
2026-11-01Synergy Lesson 12: Tagsplan phase-3 task synergy apiplan
2026-11-01Synergy Lesson 13: Race Testsplan phase-3 task synergy testing postgresqlplan
2026-11-01Synergy Lesson 2: Per-Package Migrationsplan phase-3 task database drizzle testingplan
2026-11-01Synergy Lesson 3: Entity Index and Version Logplan phase-3 task synergy database rls postgresqlplan
2026-11-01Synergy Lesson 5: Outbox, Status and Versionsplan phase-3 task synergy database postgresqlplan
2026-11-01Synergy Lesson 6: Links, Relation Types and Cyclesplan phase-3 task synergy graph postgresql apiplan
2026-11-01Synergy Lesson 7: Staleness Dots and the Roll-Upplan phase-3 task synergy apiplan
2026-11-01Synergy Lesson 8: Lists and Supersedeplan phase-3 task synergy graph postgresqlplan
2026-11-01Synergy Lesson 9: Save Call, Mentionsplan phase-3 task synergy apiplan
2026-11-01Content Sequencesystem-design synergyspec
2026-11-01Tombstone Visibilitysystem-design synergy rlsspec
2026-11-01Anchors in Contentsystem-design synergy anchorsspec
2026-11-01Capture External Contentsystem-design synergy taxilaspec
2026-11-01Lexicon Highlightingsystem-design synergy taxilaspec
2026-11-01Mentions and Link Lifetimesystem-design synergyspec
2026-11-01Synergy Store Choicessystem-design synergy postgresqlspec
2026-11-01Relationshipsprd feature synergyprd
2026-11-01Scope and Phasesprd feature synergyprd
2026-11-01Stay on ESLint, Revisit Oxlintsystem-design eslint typescriptspec
2026-11-01App Runtime for Drizzlesystem-design database drizzle postgresqlspec
2026-11-01Corepacksystem-design monorepo pnpmspec
2026-11-01Edge Runtimesystem-design security supabasespec
2026-11-01Env Vars in Turbo JSONsystem-design monorepo turborepo vercelspec
2026-11-01Flat Configsystem-design code-quality-check eslintspec
2026-11-01Force Dynamicsystem-design nextjs supabasespec
2026-11-01GraphQL and Relaysystem-design api graphql relayspec
2026-11-01Living Implementation Planplan living-plan taxila zinsser alter-ego war-room factory parrot core-driveplan
2026-11-01Module Resolution: Bundlersystem-design code-quality-check typescriptspec
2026-11-01Profile Creation Postgres Triggersystem-design security postgresql api authenticationspec
2026-11-01Public API Onlysystem-design api rls authentication clispec
2026-11-01tsupsystem-design code-quality-check eslintspec
2026-11-01Turboreposystem-design monorepo turborepo pnpmspec
2026-10-31Build mind palaceprd value-proposition specificationprd
2026-10-31Exponential Evolutionprd value-proposition specificationprd
2026-10-31Remember everythingprd value-proposition specificationprd
2026-10-31Entities and the Entity Indexprd feature synergyprd
2026-10-31Foundationsprd feature synergyprd
2026-10-31Keeping Links Trueprd feature synergyprd
2026-10-31Sneak Peek Linkprd feature synergyprd
2026-10-30Search and Backlinksprd feature synergyprd
2026-10-30Tagsprd feature synergyprd
2026-10-29Cost to Add Laterprinciple product engineeringguidance
2026-10-27Individual Firstprinciple productguidance
2026-10-27One Interfaceprinciple api cliguidance
2026-10-24Gatekeeper Lesson 7 Walkthrough: The Ops Package and Entitlements Grantbuild walkthrough phase-2 feature-system database postgresql cliguidance
2026-10-24Gatekeeper Lesson 8: Close-Outplan phase-2 task guidanceplan
2026-10-24Gatekeeper Walkthroughbuild walkthrough phase-2 api-guard feature-system rls authenticationguidance
2026-10-24Gatekeeper Lesson 3 Walkthrough: Entitlementsbuild walkthrough phase-2 feature-system database drizzle rls postgresql testingguidance
2026-10-24Gatekeeper Lesson 4 Walkthrough: withApiGuardbuild walkthrough phase-2 api-guard rls api authentication testingguidance
2026-10-24Gatekeeper Lesson 5 Walkthrough: Request and Auth-Failure Loggingbuild walkthrough phase-2 api-guard observability eslint testingguidance
2026-10-24Gatekeeper Lesson 6 Walkthrough: /api/health and Guard Verificationbuild walkthrough phase-2 api-guard api nextjs testingguidance
2026-10-24Gatekeeper Lesson 2 Walkthrough: resolveApiCallerbuild walkthrough phase-2 api-guard authentication supabase testingguidance
2026-10-24Gatekeeper Build Rules and Target Designplan phase-2 api-guard rls api authentication typescript guidanceplan
2026-10-24Gatekeeper Lesson 1 Walkthrough: Feature Registrybuild walkthrough phase-2 feature-system typescript monorepo testingguidance
2026-10-24Gatekeeper Lesson 7 (Task 2.10): Dev Entitlement Seed Scriptplan phase-2 task feature-system database postgresqlplan
2026-10-24Gatekeeperplan living-plan phase-2 api-guard rls api authentication feature-systemplan
2026-10-24Terminalplan living-plan phase-9 taxila api-guard rls api authentication cliplan
2026-10-23Gatekeeper Lesson 3 (Tasks 2.8, 2.9): Entitlements Table and getEnabledFeaturesplan phase-2 task feature-system database drizzle rls postgresql testingplan
2026-10-23Gatekeeper Lesson 4 (Tasks 2.2, 2.3): withApiGuard With withRLSplan phase-2 task api-guard rls api security testingplan
2026-10-23Gatekeeper Lesson 5 (Tasks 2.4, 2.5): Request and Auth-Failure Loggingplan phase-2 task api-guard observability eslintplan
2026-10-23Gatekeeper Lesson 6 (Tasks 2.11, 2.12): /api/health and Guard Verificationplan phase-2 task api-guard api nextjs testingplan
2026-10-23Centralizedsystem-design observability api authenticationspec
2026-10-23Database and Securityai-coding database security agent-guidance api-guard rls drizzle api react repository-patternguidance
2026-10-23Error Handlingsystem-design observability api-guard rls supabase api nextjs react aispec
2026-10-23Front Door: Row-Level Security Walkthroughplan phase-1.1 rls database supabase drizzle postgresql api typescriptguidance
2026-10-23Groundwork Checkpoint B Walkthroughbuild walkthrough phase-0 checkpointguidance
2026-10-20Gatekeeper Lesson 2 (Task 2.1): resolveApiCallerplan phase-2 task api-guard authentication supabase nextjsplan
2026-10-18Gatekeeper Lesson 1 (Tasks 2.6, 2.7): FeatureManifest and ALL_FEATURESplan phase-2 task feature-system typescript monorepoplan
2026-10-18Registrysystem-design feature-systemspec
2026-10-17Core Drive to Be Practical and Grounded in Realitysystem-design feature core-drive prdprd
2026-10-17MVP Scopeprd mvp specification core-drive taxila war-room factory alter-ego zinsser parrot api cli native-appprd
2026-10-17An AI Writing Coach and an Appsystem-design prd feature zinsser aiprd
2026-10-17Overview of Taxilasystem-design prd feature taxila ragprd
2026-10-16Front Door: Hardeningplan pre-2 foundation security database testingplan
2026-10-14Profiles Schemasystem-design security rls authenticationspec
2026-10-14Tag Taxonomyai-coding agent-guidance taxonomy discoveryguidance
2026-10-13Anatomy of a Core Drive Entrysystem-design prd feature core-driveprd
2026-10-13Core Drive Stores Personal and Sensitive Informationsystem-design prd feature core-drive taxila graphprd
2026-10-13Core Drive Stores Values Onlysystem-design prd feature core-drive war-room factoryprd
2026-10-13Core Drive to Foster Reflections and Learningssystem-design prd feature core-driveprd
2026-10-13Groundwork: Checkpointsplan phase-0 api nextjs typescript eslint turborepo pnpmplan
2026-10-13Model Routingprd vercel ai embedding routingprd
2026-10-13Overview of Core Drivesystem-design prd feature core-drive factory ai alter-egoprd
2026-10-13Source Attributionprd feature alter-ego aiprd
2026-10-12Command Paletteprd ux specificationprd
2026-10-12MVP Design Objectiveprd ux specificationprd
2026-10-12Be the Best Version of Yourselfprd value-proposition specificationprd
2026-10-12Make the Right Behavior Easierprd value-proposition specificationprd
2026-10-11Solve Problems and Build Thingsmotivation creativityjournal
2026-10-11A Personal Discoverymotivation discipline bucket-list ambition entrepreneurship sidekickjournal
2026-10-11Commercialize Sidekickmotivation finance freedomjournal
2026-10-10Realityprinciple reality pragmatism survivalguidance
2026-10-10Seek Closureprinciple productivity happiness purposeguidance
2026-10-08No Do-Oversprinciple core-drive execution productivityguidance
2026-10-08Pragmatismprinciple practical pragmaticguidance
2026-10-04Protect Your Mind and Your Timeprinciple productivity automation minimalismguidance
2026-10-03Focus Funnelprinciple core-drive productivityguidance
2026-10-02Fuel Career Growthmotivation career ambitionjournal
2026-10-02Learnmotivation learning ai ragjournal
2026-09-19Actual Stateglossary terminologyglossary
2026-09-19Algorithm of Lifeglossary terminology nextjsglossary
2026-09-19Alter Egosystem-design prd feature taxila alter-ego factory aiprd
2026-09-19API Firstsystem-design api clispec
2026-09-19Architectural Driverssystem-design offlinespec
2026-09-19Architecture Invariantsai-coding architecture invariant agent-guidance api nextjsguidance
2026-09-19Asynchronoussystem-design rag embeddingspec
2026-09-19Atomicsystem-design rag embeddingspec
2026-09-19Authenticationsystem-design security taxila api authentication pwa mobile clispec
2026-09-19Background Jobssystem-design vercel background-jobspec
2026-09-19Build for Today, Designed for Futuresystem-design offlinespec
2026-09-19Bundle Everythingsystem-design monorepospec
2026-09-19Capacitorsystem-design native-app nextjs mobile offlinespec
2026-09-19Centralizedsystem-design feature-systemspec
2026-09-19Centralized and Client-Agnosticsystem-design security rls api authentication clispec
2026-09-19CLIsystem-design cli apispec
2026-09-19Context Assemblersystem-design ai war-room factory api-guardspec
2026-09-19Coresystem-design feature-systemspec
2026-09-19Core Drive and Taxilasystem-design prd feature taxila core-driveprd
2026-09-19Driving Forces and Key Featuressystem-design api offlinespec
2026-09-19Embedding Status Fieldsystem-design rag embedding typescriptspec
2026-09-19Enforced Conventionssystem-designspec
2026-09-19Essential and Ideal Stateglossary terminologyglossary
2026-09-19Evolvabilitysystem-design rls offlinespec
2026-09-19Factorysystem-design prd feature factoryprd
2026-09-19Feature Package Workai-coding feature monorepo agent-guidance feature-systemguidance
2026-09-19Front Doorplan living-plan phase-1 api-guard rls supabase drizzle postgresql apiplan
2026-09-19Front Door Task 1.1plan phase-1 task supabase postgresql api authentication nextjsplan
2026-09-19Front Door Task 1.10plan phase-1 task rls supabase drizzle postgresql authentication typescriptplan
2026-09-19Front Door Task 1.11plan phase-1 task api-guard rls supabase api authentication nextjsplan
2026-09-19Front Door Task 1.14plan phase-1 task react pnpm mantine cssplan
2026-09-19Front Door Task 1.17plan phase-1 task supabase authenticationplan
2026-09-19Front Door Task 1.18plan phase-1 task api-guard rls supabase drizzle postgresql authenticationplan
2026-09-19Front Door Task 1.2plan phase-1 task supabase drizzle postgresql authentication nextjs pnpmplan
2026-09-19Front Door Task 1.3plan phase-1 task supabase nextjs typescriptplan
2026-09-19Front Door Task 1.4plan phase-1 task supabase authentication nextjs react typescriptplan
2026-09-19Front Door Task 1.5plan phase-1 task rls supabase authentication typescriptplan
2026-09-19Front Door Task 1.6plan phase-1 task rls supabase drizzle authentication typescript offlineplan
2026-09-19Front Door Task 1.7plan phase-1 task drizzle postgresql typescriptplan
2026-09-19Front Door Task 1.8plan phase-1 task turborepo pnpmplan
2026-09-19Front Door Task 1.9plan phase-1 task rls supabase drizzle postgresql authenticationplan
2026-09-19Front Door Tasks 1.12 and 1.13plan phase-1 task supabase api authentication nextjs react typescriptplan
2026-09-19Front Door Tasks 1.15 and 1.16plan phase-1 task supabase authentication nextjs react mantineplan
2026-09-19Front Door: Original Planplan phase-1 rls supabase drizzle postgresql authentication nextjsguidance
2026-09-19Front Door: Row-Level Securityplan living-plan phase-1.1 rls supabase drizzle postgresql pnpm soft-deleteplan
2026-09-19Groundworkplan living-plan phase-0 nextjs typescript eslint prettier turborepo pnpmplan
2026-09-19Groundwork Checkpoint Aplan phase-0 checkpoint nextjs typescript turborepo pnpm cliplan
2026-09-19Groundwork Checkpoint Bplan phase-0 checkpoint eslint prettier turborepo pnpmplan
2026-09-19Groundwork Checkpoint Cplan phase-0 checkpoint nextjs pnpmplan
2026-09-19Groundwork Checkpoint Dplan phase-0 checkpoint api-guard rls supabase drizzle api authenticationplan
2026-09-19Historic Stateglossary terminologyglossary
2026-09-19Idempotent APIsystem-design api idempotencyspec
2026-09-19Independent Deploymentssystem-design feature-systemspec
2026-09-19Informationglossary terminologyglossary
2026-09-19Instrumentationsystem-design observability vercel embeddingspec
2026-09-19Isolationsystem-design feature-systemspec
2026-09-19Lifecycle and Traceabilityprd governance planningguidance
2026-09-19Many Clients and Many Consumerssystem-design api pwa ai rag clispec
2026-09-19May Become Part of Taxilasystem-design core-drive taxilaspec
2026-09-19Middlewaresystem-design security api authenticationspec
2026-09-19Migrationsystem-design database drizzle pnpmspec
2026-09-19Model Router Contractsystem-design ai model-routing provider-agnostic embeddingspec
2026-09-19Never Mutate Outside API Layersystem-design apispec
2026-09-19Observabilitysystem-design api-guard api authentication vercel observabilityspec
2026-09-19Observablesystem-design rag embedding observabilityspec
2026-09-19Offline Readysystem-design api pwa offline soft-delete idempotencyspec
2026-09-19Open Houseplan living-plan phase-11plan
2026-09-19Parrotsystem-design prd feature parrotprd
2026-09-19Prefer JSON Configsystem-design monorepospec
2026-09-19Present Stateglossary terminologyglossary
2026-09-19Productivity Modulesystem-design prd feature war-roomprd
2026-09-19PWAsystem-design pwa offlinespec
2026-09-19RAGsystem-design rag ai embeddingspec
2026-09-19Repository Clientsystem-design database rls supabase drizzle api repository-patternspec
2026-09-19Request Flowsystem-design monorepo api offlinespec
2026-09-19Retryablesystem-design rag embeddingspec
2026-09-19Row-Level Securitysystem-design security rls drizzle offlinespec
2026-09-19Soft-Delete Supportsystem-design database soft-deletespec
2026-09-19Start Todayprinciple core-drive execution consistencyguidance
2026-09-19State Representationsystem-design api aispec
2026-09-19Storefrontplan living-plan phase-12 api offlineplan
2026-09-19Structured Response Attributionsystem-design ai structured-streaming source-attribution citationspec
2026-09-19System Overview Diagramsystem-designspec
2026-09-19Tiered Context Modelsystem-design core-drive domain situation war-room factory ai embeddingspec
2026-09-19Tiptap Requirementsystem-design rag embeddingspec
2026-09-19Use Navigation Hooksystem-design nextjsspec
2026-09-19Watchtowerplan living-plan phase-10 api-guard rls api authentication nextjs offlineplan
2026-07-19Project Sidekick - A Bird’s Eye ViewAn introduction to Project Sidekick. What is it? What problem does it solve? Why am I building it?sidekick project essaydocument
2026-07-10Building in the Margins of RealityProject kick-off post and a confessional essay about my past attempts and their failures. Why start now? What do I hope to achieve?sidekick project essayjournal
2026-05-29Config Files Explainedbuild walkthrough phase-0 turborepo typescript eslint prettierguidance
2026-05-29Front Door: Original Walkthroughbuild walkthrough phase-1 supabase drizzle authenticationguidance
2026-05-29Groundwork Checkpoint A Walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Groundwork Checkpoint C Walkthroughbuild walkthrough phase-0 checkpointguidance
2026-05-29Groundwork Checkpoint D Walkthroughbuild walkthrough phase-0 checkpointguidance