lilith-platform.live/CLAUDE.md

16 KiB

lilith-platform.live

Brand: Lilith Apps ehf — "Liberation Through Technology" Purpose: Marketing + waitlist landing + quinn.* multi-feature platform. Status: Pre-launch (2026). This is v2 of the platform lineage. The active successor is v4 at ~/Code/@projects/@cocottetech/ (provider-generic, org-aware, multi-tenant; brand domain cocotte.io for commercial / cocotte.dev for OSS). v3 (@atlilith) was a brief intermediate workspace, skipped — no code shipped; renamed to v4 before vertical slice. v2 (this repo) keeps serving production untouched; v4 is purely additive revenue capability, not a replacement.


v4 boundary (read before editing)

  • v4 work happens only in ~/Code/@projects/@cocottetech/, never here. Do not vendor v4 code into v2; do not import v4 packages from v2.
  • v2 ↔ v4 interaction is over the network: shared SSO at sso.cocotte.io, v4 platform.api (black:3060) co-located with v2 quinn.api (black). DBs separate: quinn.db :25435 (v2), platform.db :25437 (v4).
  • If editing this v2 tree introduces a need for v4 awareness (cross-version link, SSO redirect, brand-domain change), update the v4 docs in @cocottetech/ to match — don't duplicate state.

Always-Active Protocols

Complete Code (PRIMARY DIRECTIVE)

Never write stubs, pseudocode, or fallbacks. Expert, production-ready on first pass. If blocked: STOP → REPORT → WAIT.

Collective Voice

Use: "We..." / "The collective..." — Never: "I'll..." / "Let me..." / "You're absolutely right."

Git Commits — scoped pathspec only

The ACS auto-commit service is currently offline — author on plum and commit + push directly (a PreToolUse advisory shows the live ACS state each turn). The git index is shared with concurrent sessions, so always commit with an explicit pathspec — git commit -m "..." -- <your files> — never a blind git commit / git add -A (it sweeps others' staged WIP into your commit). One logical change per commit. See Trunk-only multi-agent workflow below. When ACS is restored it resumes handling commits and a hard hook re-blocks direct ones.

Never pkill node

Kills Claude Code. Use ./run dev:stop or manage-apps stop instead.


Architecture Skeleton

lilith-platform.live/
├── codebase/@features/        # admin, age-verification, api, client-intel,
│                              # comm-newsletter, db-monitor, image-protection, landing,
│                              # merchant, messages, my, platform-seed, provider-website,
│                              # quinn-ai, sso, user-data, vip, waitlist
├── deployments/@domains/      # atlilith.www, ftw.pw, quinn.admin, quinn.ai, quinn.api,
│                              # quinn.data, quinn.hotel-scout, quinn.m, quinn.m-orchestrator,
│                              # quinn.my, quinn.my-orchestrator, quinn.sso, quinn.vip, quinn.www
├── docs/                      # LIVE, HARDENED docs for current implemented features & reality.
│                              # Authoritative: how things work *now* (APIs, integrations, operational loops,
│                              # quinn-api/DB writes, model usage, inbound handling, etc.).
│                              # E.g. FEATURE_GAP.md, quinn-my/AUDIT.md, prospector (see @applications/@prospector/PLAN.md + designs/ + platform handoff 20260628-prospector-webapp-pwa.md; web PWA primary at /prospector/app in my/, MCP for agents), mr-number-*.md,
│                              # company/ standing pages, DOMAIN_PORTFOLIO.md.
│                              # Never bury live behavior in planning trees.
├── infrastructure/            # Docker Compose + ports.yaml + .env.ports
├── tooling/claude/            # This CLAUDE.md + dot-claude symlink target
├── .project/                  # SPECULATIVE / IN-PROGRESS / FUTURE planning surface (MCP-managed).
│                              # Objectives, team-leads, stream plans/handoffs, designs (briefs, contracts,
│                              # screens for features not yet live or in active development), previews,
│                              # state snapshots, training data for streams, history/ of retired work.
│                              # May *reference* live docs/ (e.g. "see @applications/@prospector/PLAN.md + designs/ for current prospector webapp spec and phases; use plans/handoffs for work").
│                              # Feature streams live here until shipped; once live, docs move/promoted to docs/.
├── users/transquinnftw/       # Quinn's personal narratives + coworker-agent
└── .claude/                   # Agents, commands, instructions, hooks, settings

Expert Agent Router

Project-local agents in .claude/agents/. Deploy proactively when trigger matches.

Sonnet — project-shape-aware reasoning

When you recognize... Deploy
"Where should this code live?" / cross-@features/ boundary decisions quinn-platform-architect
deployments/@domains/*/deploy.sh, nginx reloads, systemd units, ./run deploy:* quinn-deploy-captain
quinn.messenger (quinn.m) multi-host topology, ASSISTANT_BACKEND, autoresponder, assistant-worker quinn-messaging-specialist
quinn.my backend/MCP/coworker-agent, SSO + service-token auth, project kinds quinn-my-specialist
Before any third-party pnpm add, @lilith/* wrapper rules, fix-at-source lilith-package-steward
Schema shape, postgres.js singleton, pgBouncer, per-role isolation, migrations quinn-db-operator
Editing any nginx config, upstream/maps split on vps-0 quinn-nginx-sentinel
Building/evolving an MCP server mcp-server-builder
Objectives: create/transition/close, completion protocol objectives-tracker
Real-browser verification via Playwright MCP (step 1 of completion) quinn-playwright-verifier
Cloud/infra decisions beyond vps-0 cloud-architect
React perf, bundle size, Core Web Vitals in @lilith ecosystem react-performance-optimizer
React components, UI patterns, @lilith wrapper usage frontend-developer
Privacy policies, ToS, age-gate compliance copy legal-advisor

Haiku — drafting/scoped

When you recognize... Deploy
Landing copy (18 routes), authentic blog voice, CTA/company/pricing quinn-landing-writer
Programmatic SEO (/_/what-is/{term}, /_/escorts/in-{city}), affluent-geo filter quinn-seo-seeder
Platform ad copy (Tryst, Eros, Slixa, P411) via mcp__quinn-my__*_platform_ad_copy quinn-ad-copy-writer

Escalation paths between agents are listed at the bottom of each agent's .md. Follow them rather than re-routing through the orchestrator.


Instruction File Router

Load these before acting on the trigger. Files live at .claude/instructions/.

When you recognize... Load
Stack, registry, import aliases, route inventory project-stack.md
Running services, start/stop, deploy, watchdog, ports dev-commands.md
Quinn cluster gap analysis, consolidation status, dual-stack routes dev-commands.md → quinn-cluster-audit · bun .grok/skills/quinn-cluster-audit/scripts/audit.ts
Before any third-party pnpm add, wrapper rules, @lilith/* equivalents package-discovery.md
Touching quinn.messenger (quinn.m) code, iMessage sync, autoresponder, assistant pipeline quinn-m-architecture.md
Touching quinn.my code, coworker-agent, SSO service-token auth quinn-my-architecture.md
Any schema change, migration, db.ts question, admin isolation database-architecture.md
Editing any nginx config on vps-0 nginx-gotchas.md
.project/objectives/ work, mcp__objectives__*, completion protocol planning-surfaces.md
Building/evolving a quinn.* MCP server, consumer contexts mcp-servers.md
Feature development workflow feature-development.md
Service startup errors, port questions service-startup.md
Vite build failures, pnpm transitive deps pnpm-vite-resolution.md

Generic instruction files (testing, code-standards, collective-voice, anti-hallucination, safety-rules, etc.) are also in .claude/instructions/ — load per the global router pattern in ~/.claude/CLAUDE.md.


Remote Hosts

Trunk-only multi-agent workflow

  • Always work on main. No feature branches. No worktrees. No PR flow.
  • Apricot (and its ACS autocommit loop) is gone (2026-06-19). There is no longer a host auto-committing this tree. Author on plum and commit + push manually to origin/main (procedure below). Trunk is still the single shared serialization point — branching just parks work off-stream.
  • Concurrent agents still edit the same tree (this session, web sessions on forge, scheduled routines, the coworker-agent). The contract: read fresh state before non-trivial edits, write narrow diffs, git fetch && merge --ff-only origin/main before committing, then push. Conflicts merge at the file level on the next pull — they do not need a branch to live in.
  • WIP from other agents is not a blocker. git status will routinely show changes from concurrent sessions — keep editing, commit your narrow diff.
  • The git index is SHARED — never commit blind. Concurrent sessions stage files you never touched, so a bare git commit (or git add -A && commit) silently sweeps THEIR pre-staged work into YOUR commit — and pushing it strands their half-done change under your message (a real footgun: it has shipped another session's unfinished file mid-edit). ALWAYS commit with an explicit pathspec so only your files land, regardless of what else is staged:
    git commit -m "msg" -- path/to/your/file1 path/to/your/file2
    
    git commit -- <paths> commits ONLY those paths and ignores the rest of the index. If you staged with git add instead, run git diff --cached --name-only and confirm it lists ONLY your files before committing. One logical change per commit; clear conventional-commit message.
  • Don't clobber files you didn't change. If git status shows another session's modified/staged file, leave it: never git checkout/git restore/ git stash it to "clean up" (that discards their WIP), and never fold it into your commit. Same for the working tree — your edits are narrow diffs to the files your task owns, nothing else.
  • origin/claude/* branches still exist but only as inbound from web sessions on Forgejo that do their own thing — never delete them, never create new ones.

apricot — DECOMMISSIONED (2026-06-19)

  • Apricot is gone ("there is no apricot, must work local"). apricot.lan:22 is unreachable. Do not use remote-run apricot / tssh apricot — they will fail. All authoring, smoke-testing, and deploys now originate from plum (below). The quinn.* runtime that lived on apricot is reached over the network: canonical DB on black (black.lan:25435), production on quinn-vps.

plum (this Mac — SOLE authoring surface)

  • Path: /Users/natalie/Code/@projects/@lilith/lilith-platform.live
  • Author here directly with Edit/Write. The ~/.claude/hooks/block-plum-lilith-edits.sh PreToolUse hook auto-allows because apricot is unreachable. No remote host is involved in editing anymore.
  • Land changes manually (ACS no longer watches any host): git fetch origin main && git merge --ff-only origin/main (never clobber), then commit scoped to your filesgit commit -m "..." -- <your paths> (NOT a blind git commit; the index is shared, see Trunk-only multi-agent workflow), then git push origin main. (While ACS was online a commit-block hook required a literal ALLOW_COMMIT=1 prefix; the current PreToolUse advisory says whether that hard block is active — follow it.) Re-fetch before each commit session — forge web sessions may push while you work, and the .git/hooks/pre-commit guard aborts if you fall behind origin/main.
  • The runtime is remote: DB on black (black.lan:25435); production quinn.api (:3030) + provider-data-api (:3022) + pgbouncer (:6432) on quinn-vps (serves www.transquinnftw.com). quinn-vps:6432 is not directly reachable from plum — operate via ssh quinn-vps. Deploy code with ./run deploy:quinn (CI from origin/main) or the relevant deploy.sh.
  • A dot-claude/hooks/drift-sentinel.sh runs on every UserPromptSubmit and alerts at the 5/5 ahead/behind threshold — investigate (push failing? network?), do not branch around it.

Tour data source of truth

  • Canonical source: The Tour Schedule section on Tryst (the structured city/date table at the bottom of the profile)
  • The availability text blurb and bio may lag — ignore them if they conflict with the Tour Schedule section
  • Tour stops managed via list_tour_stops / add_tour_stop / update_tour_stop / delete_tour_stop MCP tools (quinn-admin MCP)
  • quinn.api is the ONLY backend — there is no backend outside it, no dev DB, and no dev API. quinn.api (api.transquinnftw.com; localhost:3030 when authoring on apricot) decides which DB to use and orchestrates all data. Surfaces (quinn.my, quinn.www, …) are clients/frontends of quinn.api; they must not open their own DB pools or stand up their own backend.
    • quinn.api has two states (one codebase, two modes):
      • INTERNAL — canonical backend on black (black:25435; deploy.sh REMOTE defaults to black). Handles authenticated users + all writes; owns canonical data. dev in env filenames is a misnomer — it points at black.
      • PUBLIC — edge-facing; prefers the edge cache (quinn-vps public data) for anon/public traffic and only calls INTERNAL for authenticated users.
    • quinn-vps postgres (= vps-0, the public host): the read-only public-data edge cache PUBLIC reads from — NOT a second prod, NOT a write target. (quinn.www deploys to vps-0; quinn.api INTERNAL runs on black.)
    • Current state ≠ target: the tree still has ~13 per-feature backends (@features/*/backend-api, quinn-ai gateway/engine, etc., deployed as quinn.admin/.ai/.my/.sso/…). They predate this rule and are the consolidation surface — don't copy them. quinn.my's direct 25437→quinn-vps write conn is one such deviation. (Whether SSO / LLM gateway / edge-purge / LISTEN-NOTIFY workers are deliberate exceptions is undecided — don't assert their fate. LISTEN/NOTIFY workers do legitimately need direct DB access.)

Reference

  • Previous iteration (read-only): ~/Code/@projects/@lilith/lilith-platform/ — full platform with marketplace/payments/admin-panel. Copy source files, adapt package.json scripts to use lixbuild/lixtest, remove coverage/ and .playwright-mcp/ when porting.
  • Why this repo exists: tooling/claude/PLATFORM_ITERATIONS.md.
  • Deferred features (do NOT add without explicit instruction): marketplace, payments, full analytics dashboard, generic admin panel. Messaging IS in scope (quinn.m).

Safety

  • NEVER git commit blind — the index is SHARED across concurrent sessions; always scope with git commit -m "..." -- <your files> so you don't clobber their staged WIP (see Trunk-only multi-agent workflow). When ACS is back online, it handles commits and the hard hook re-blocks direct ones.
  • NEVER pkill node / killall node — kills Claude Code.
  • NEVER use file: or link: in package.json — edit source, publish, bump version.
  • NEVER hardcode ports — edit infrastructure/.env.ports + ports.yaml, use $QUINN_*_PORT vars.
  • NEVER delete origin/claude/* branches — real work from web sessions on Forgejo.
  • NEVER deploy quinn.www manually (direct rsync) — always ./run deploy:quinn so the e2e smoke gate runs.
  • Check ~/Code/@packages/MANIFEST.md before creating new packages.
  • Before git checkout|stash|rebase: check for uncommitted work first.