{"id":51318291,"url":"https://github.com/jayzalowitz/skytwin","last_synced_at":"2026-07-01T10:02:15.579Z","repository":{"id":349254620,"uuid":"1196922281","full_name":"jayzalowitz/skytwin","owner":"jayzalowitz","description":"A digital twin that learns what you'd want — and does it. Delegated judgment with safety constraints, explanations, and progressive trust.","archived":false,"fork":false,"pushed_at":"2026-06-23T20:01:05.000Z","size":9979,"stargazers_count":2,"open_issues_count":20,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-23T20:21:25.333Z","etag":null,"topics":["ai-agent","cockroachdb","decision-engine","digital-twin","personal-automation","preference-learning","safety","typescript"],"latest_commit_sha":null,"homepage":"https://github.com/jayzalowitz/skytwin","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jayzalowitz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-31T06:59:33.000Z","updated_at":"2026-06-23T20:01:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jayzalowitz/skytwin","commit_stats":null,"previous_names":["jayzalowitz/skytwin"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/jayzalowitz/skytwin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jayzalowitz%2Fskytwin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jayzalowitz%2Fskytwin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jayzalowitz%2Fskytwin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jayzalowitz%2Fskytwin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jayzalowitz","download_url":"https://codeload.github.com/jayzalowitz/skytwin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jayzalowitz%2Fskytwin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35001655,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agent","cockroachdb","decision-engine","digital-twin","personal-automation","preference-learning","safety","typescript"],"created_at":"2026-07-01T10:02:14.452Z","updated_at":"2026-07-01T10:02:15.553Z","avatar_url":"https://github.com/jayzalowitz.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# SkyTwin\n\n**A digital twin that learns what you'd want — and does it.**\n\n\u003ca href=\"https://github.com/jayzalowitz/skytwin/actions/workflows/build.yml\"\u003e\u003cimg src=\"https://github.com/jayzalowitz/skytwin/actions/workflows/build.yml/badge.svg\" alt=\"Build\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jayzalowitz/skytwin/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-Apache%202.0-blue.svg\" alt=\"License\"\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/github/package-json/v/jayzalowitz/skytwin?color=brightgreen\u0026label=version\" alt=\"Version\"\u003e\n\u003ca href=\"https://github.com/jayzalowitz/skytwin/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/jayzalowitz/skytwin?label=download\u0026color=blue\" alt=\"Download latest release\"\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/platform-macOS%20%7C%20Windows%20%7C%20Linux%20%7C%20iOS%20%7C%20Android-lightgrey.svg\" alt=\"Platform\"\u003e\n\n\u003c/div\u003e\n\n---\n\nEvery personal assistant today has amnesia. You tell it you prefer aisle seats three times. It asks again. You archive the same newsletter every morning. It keeps notifying you. Every interaction starts from scratch.\n\nSkyTwin is different. It builds a structured model of your preferences, risk tolerances, and decision patterns — a **digital twin** — then uses that model to act on your behalf. When it's confident, it just handles things. When it's not, it asks the right question instead of the wrong one.\n\n**The core principle: ask the twin before asking the user.**\n\n## How It Works\n\n```\n  Gmail, Calendar, etc.\n         │\n         ▼\n  ┌──────────────┐\n  │   Connectors  │  Ingest signals from your accounts\n  └──────┬───────┘\n         ▼\n  ┌──────────────┐\n  │   Decision    │  \"What's happening? What would\n  │   Engine      │   the user want here?\"\n  └──────┬───────┘\n         ▼\n  ┌──────────────┐\n  │  Twin Model   │  Your preferences, patterns,\n  │  + Memory     │  and episodic memory (gbrain default,\n  │               │  MemPalace optional)\n  └──────┬───────┘\n         ▼\n  ┌──────────────┐\n  │   Policy      │  Spend limits, trust tiers,\n  │   Engine      │  safety constraints\n  └──────┬───────┘\n         ▼\n    ┌────┴────┐\n    ▼         ▼\n Auto-     Escalate\n execute   with context\n    │         │\n    ▼         ▼\n Explain   You decide\n    │         │\n    └────┬────┘\n         ▼\n  ┌──────────────┐\n  │  Feedback     │  Your response trains the twin\n  │  Loop         │  to be better next time\n  └──────────────┘\n```\n\nEvery path produces an explanation. Every outcome feeds back into the twin. The system gets better at predicting what you want over time.\n\n## Screenshots\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eOnboarding\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/onboarding.png\" alt=\"Onboarding — connect Gmail, tell your twin about yourself, or explore a sample profile\"\u003e\n\u003c/td\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eDashboard\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/dashboard.png\" alt=\"Dashboard — your daily briefing: what needs you, what the twin handled, and recent activity\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eApprovals\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/approvals.png\" alt=\"Approvals — pending actions that need your OK\"\u003e\n\u003c/td\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eDecision History\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/decisions.png\" alt=\"Decision history — filterable log of every decision with reasoning\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eSetup \u0026amp; Credentials\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/setup.png\" alt=\"Setup — execution engines, Google OAuth walkthrough, credential management\"\u003e\n\u003c/td\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eSettings\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/settings.png\" alt=\"Settings — autonomy level, spend limits, connected accounts, privacy controls\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eMy Learnings\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/twin.png\" alt=\"My Learnings — preferences, inferences, and corrections your twin has learned\"\u003e\n\u003c/td\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eDaily Briefing\u003c/strong\u003e\u003c/p\u003e\n\u003cimg src=\"docs/screenshots/briefing.png\" alt=\"Daily briefing — a source-cited digest that splits to-dos (act) from topics (FYI), with a Power view for the reasoning behind each call\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## Concrete Examples\n\n| Scenario | What SkyTwin Does |\n|----------|-------------------|\n| **Newsletter arrives** | Your twin knows you archive these without reading. Auto-archived. Explanation logged. You never see it. |\n| **Calendar conflict** | You always prioritize skip-level 1:1s over standups. Standup rescheduled with a note to the organizer. |\n| **Subscription renewal** | $15.99/mo streaming service, used 3x this month, 18 months of renewals. Auto-renewed within your spend norms. |\n| **Grocery reorder** | Repeats your last order with your substitution rules. Flags the one item that jumped 15% in price. |\n| **Flight booking** | Finds the United aisle seat, morning departure, direct, $380. At high trust: books it. At low trust: presents top 3 options. |\n| **Unknown sender email** | Low confidence. Escalates with a one-line summary so you can decide in 5 seconds instead of 5 minutes. |\n\n## What Makes This Different\n\n**It's not a chatbot.** SkyTwin is operational, not conversational. It doesn't wait for you to type a prompt — it watches your connected accounts and acts when opportunities arise.\n\n**It earns trust incrementally.** New users start at `observer` — the system only suggests. As you approve and correct, it earns autonomy domain by domain. Trust in email triage doesn't mean trust with your calendar.\n\n**Safety constraints are the product.** Every action passes through a policy engine with hard spend limits, trust tier gating, reversibility checks, and sensitivity classification. The system can be inspected, overridden, narrowed, and shut off at any time. [Read the full safety model →](./docs/safety-model.md)\n\n**Every action is explainable.** No black boxes. Every automated decision produces an explanation record: what happened, what evidence was used, what preferences were invoked, why this action over alternatives, and how to correct it.\n\n**Your twin is inspectable.** It's not a vector embedding or a bag of keywords. It's a typed, versioned data structure where every preference has a confidence level, supporting evidence, and provenance. Contradictions are tracked, not hidden.\n\n**Memory knows who said what.** Signals from supported connectors arrive stamped with an authoring tier — content you wrote vs. a newsletter vs. an inbound stranger — and tier-weighted retrieval lets self-authored content outrank broadcast noise. The twin feels like it knows *you* instead of just having read your inbox.\n\n## Quick Start\n\n### Download and install (no terminal)\n\n**[⬇ Download the latest release →](https://github.com/jayzalowitz/skytwin/releases/latest)**\n\nGrab the installer for your OS, double-click, and you're in. No terminal, no Docker, no Ollama, no `.env`. CockroachDB ships inside the bundle as a hash-verified native binary and an embedded llama.cpp model is the default LLM — nothing else to install.\n\n| OS | Installer on the release page |\n|----|-------------------------------|\n| **macOS** (Apple Silicon) | `SkyTwin-…-arm64.dmg` |\n| **Windows** | `SkyTwin.Setup.….exe` |\n| **Linux** | `SkyTwin-….AppImage`, `.deb`, or `.rpm` |\n\n\u003e **⚠ Unsigned builds (for now).** Code-signing certs (Apple Developer + Windows EV) are a pending launch step, so your OS warns on first launch:\n\u003e - **macOS:** right-click the app → **Open** → **Open** (clears Gatekeeper once).\n\u003e - **Windows:** SmartScreen → **More info** → **Run anyway**.\n\u003e\n\u003e Signing lands before the public launch; until then this is the expected first-run experience.\n\n### Build from source (one-command, macOS / Linux / WSL)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/jayzalowitz/skytwin/main/install.sh | bash\n```\n\nThe installer detects your OS, installs anything missing (Homebrew on mac, Node 20+, pnpm), fetches the official CockroachDB single-node binary (hash-verified), clones the repo to `~/skytwin`, runs the bootstrap, starts the services, and opens the dashboard at `http://localhost:3200` once it's up. Re-running pulls latest and restarts.\n\n**No Docker required.** Before v0.6.56 the installer pulled Docker Desktop and ran CockroachDB inside a container — by far the heaviest dependency on the list, with its own EULA and a \"open it once after install\" gotcha. The default path now installs the CRDB binary directly into `~/.local/share/skytwin/bin/cockroach` and spawns it as a child process. Docker remains supported via `SKYTWIN_USE_DOCKER=true` for users who already have a Docker workflow.\n\nTo stop later: `cd ~/skytwin \u0026\u0026 ./bin/skytwin-dev --stop`.\n\n**The first 60 seconds:**\n1. The dashboard opens. Type any situation into \"Ask your twin\" — the agent reasons out loud and explains what it would do, with confidence and alternatives. No accounts connected yet, no signals required.\n2. Click **\"Try with a sample profile\"** on the welcome screen to skip the OAuth setup entirely and poke at a fully populated example twin (decisions, learnings, approvals, the whole thing). The button is enabled whenever the seeded demo user is loaded — and tells you exactly what to run (`pnpm db:seed`) when it isn't, instead of silently disappearing.\n3. Want to look around first? Press **Esc**, click the **×** in the modal corner, or hit **Skip for now** — the dashboard chrome stays navigable behind the modal, and a \"Sign in\" button on the placeholder gets you back into the wizard whenever you're ready.\n4. When you're ready to wire up your own, the in-app walkthrough handles the Google API setup in about 5 minutes — paste your client ID, click \"Save and connect now,\" and you're at Google's sign-in.\n\n### Advanced env vars\n\nThe defaults give you a working SkyTwin without any LLM API keys or Docker. Power users can opt into:\n\n| Env var | Effect |\n|---------|--------|\n| `SKYTWIN_USE_DOCKER=true` | Run CockroachDB inside Docker instead of as a native binary. Useful for users who already have Docker and prefer container lifecycle. |\n| `SKYTWIN_DOCKER_SQL_PORT`, `SKYTWIN_DOCKER_ADMIN_PORT`, `SKYTWIN_DOCKER_API_PORT` | Override Docker Compose host ports for SQL, the Cockroach admin UI, and the optional API container. Useful when another Conductor workspace or local stack already owns `26257`, `8080`, or `3000`. |\n| `TURBO_DEV_CONCURRENCY` | Override the `pnpm dev` Turbo concurrency. The default is `50`, high enough for the current persistent dev task count. |\n| `SKYTWIN_DEV_SKIP_PORT_PREFLIGHT=1` | Bypass the `pnpm dev` port preflight. Use only when you intentionally want Turbo to try starting even though a required dev port is already listening. |\n| `SKYTWIN_WITH_OLLAMA=true` | Install Ollama + pull the gemma4 model (~9.6GB). The default install uses the embedded llama.cpp provider, which doesn't require this. |\n| `SKYTWIN_DISABLE_EMBEDDED=1` | Skip the embedded LLM provider in the API's provider chain. Pair with hosted-only keys (e.g. `ANTHROPIC_API_KEY`) for reproducible evaluation runs. |\n| `SKYTWIN_CRDB_VERSION` | Pin a non-default CockroachDB version. Refresh the hash tables in `bin/skytwin-db` and `apps/desktop/scripts/build-single-binary.sh` together. |\n\n### Manual setup\n\nIf you'd rather drive each step yourself:\n\n**Prerequisites**\n\n- [Node.js](https://nodejs.org/) \u003e= 20\n- [pnpm](https://pnpm.io/) \u003e= 9\n- That's it. CockroachDB is fetched as a native binary by `bin/skytwin-db install`. No Docker, no system DB install.\n\n```bash\ngit clone https://github.com/jayzalowitz/skytwin.git \u0026\u0026 cd skytwin\npnpm install\n\n# Fetch + start CockroachDB (native binary, hash-verified)\n./bin/skytwin-db install\n./bin/skytwin-db start\n./bin/skytwin-db ensure-db\n\n# Configure\ncp .env.example .env   # edit with your values\n\n# Migrate and seed\npnpm db:migrate\npnpm db:seed\n\n# Build and run\npnpm build\npnpm dev\n```\n\nThe API starts on `localhost:3100`, the web dashboard on `localhost:3200`.\n`pnpm dev` preflights the API, web, OpenClaw bridge, and Twin MCP ports before\nTurbo starts. If another process owns a required port, it prints the owning\nPID/command/cwd; if this same workspace is already healthy, it exits cleanly\ninstead of starting a duplicate dev stack.\nThe OpenClaw bridge is supervised during `pnpm dev`, so a one-off child\nSIGKILL/exit 137 restarts the bridge without tearing down API/web/worker; fast\ncrash loops still fail visibly.\n\n### Validating the install path\n\nBefore shipping, regression-check the install end-to-end across a matrix\nof Linux distros:\n\n```bash\n./bin/validate-installs              # Ubuntu 22.04, Debian 12, Fedora 40\n./bin/validate-installs ubuntu       # one distro\n./bin/validate-installs --keep-on-fail ubuntu  # leave container alive on failure\n```\n\nEach run spawns a fresh OS container, untars a snapshot of the working\ntree, runs `install.sh` exactly the way a real user would, and asserts\nthe dashboard responds at `localhost:3200`. macOS/Windows are exercised\nvia the same `install.sh` and `bin/skytwin-db` codepaths but need a real\nmachine to verify the platform-specific bits (Homebrew, NSIS, etc.).\n\n### Running Tests\n\n```bash\npnpm test   # 3,800+ tests across 307 test files in 29 packages + 7 apps\n```\n\n## Architecture\n\nSkyTwin is a TypeScript monorepo (pnpm + Turborepo) with 29 packages and 7 apps:\n\n```\napps/\n  api/                HTTP API — decisions, user management, webhooks, /api/voice/*\n  web/                Dashboard — review decisions, manage preferences, configure policies\n  worker/             Background jobs — async execution, briefing generation, memory action loop, tier backfill\n  desktop/            Electron app — macOS (.dmg), Windows (.exe), Linux (.AppImage)\n  mobile/             React Native (Expo) — QR pairing, push notifications, SSE, voice capture\n  openclaw-bridge/    OpenClaw proxy — bridges local API to OpenClaw execution service\n  twin-mcp-server/    MCP server exposing the twin's read-only surface to external clients\n\npackages/\n  shared-types/                   TypeScript interfaces — the dependency root for everything\n  config/                         Env var loading and validation\n  core/                           Retry logic, circuit breaker, error types, logging\n  db/                             CockroachDB client, migrations, repositories\n  twin-model/                     Twin profile CRUD, preference learning, confidence scoring\n  decision-engine/                Event interpretation, candidate generation, action selection\n  policy-engine/                  Trust tiers, spend limits, domain policies, safety checks\n  policy-prompts/                 Versioned LLM prompts with JSON schema validation and deterministic fallbacks\n  ironclaw-adapter/               Execution adapter with HMAC auth, retries, circuit breaker\n  execution-router/               Adapter selection, fallback chains, risk modifiers, plugin discovery\n  llm-client/                     Unified LLM client — Anthropic / OpenAI / Google / Ollama / embedded\n  embedded-llm/                   Local-first: llama.cpp text, whisper.cpp STT, Piper TTS — spawn-based\n  explanations/                   Human-readable explanation generation\n  connectors/                     Gmail / Google Calendar / Outlook mail+calendar / mock connectors with OAuth, stamps AuthoringTier\n  assistant/                      Stateless chat service wrapping LlmClient with context enrichment\n  capability-engine/              Infers user app capabilities from signals (keyword v1 + LLM verification)\n  credential-vault/               Envelope encryption for OAuth tokens (AES-256-GCM + scrypt KDF)\n  idle-miner/                     Filesystem scanner that extracts project metadata during idle time\n  mcp-host/                       Manages MCP servers (stdio/HTTP/SSE) with circuit breakers + telemetry\n  dxt/                            Serializes/deserializes DXT artifacts (packed MCP server configs)\n  observability/                  In-memory metrics + ring-buffered rollup for the capability loop\n  registry-client/                Loads curated MCP registry entries with OAuth quirks and service lookup\n  routines/                       No-code routines: plain-language → schedulable RoutineSpec (read-only digest/notify)\n  mempalace/                      Legacy memory: episodic, knowledge graph, 4-layer retrieval (opt-in backend)\n  memory-port/                    Backend-agnostic MemoryPort interface + capability negotiation\n  memory-gbrain/                  Default memory backend — vector + tsvector RRF on CRDB brain_* tables\n  memory-gbrain-crdb-adapter/     CRDB driver for gbrain — tier-weighted RRF, pin/hide, embedding providers\n  memory-hybrid/                  Composes any two MemoryPort impls — per-capability read routing\n  memory-mempalace/               MemoryPort adapter for the legacy mempalace classes\n  evals/                          Decision quality evaluation and regression testing\n```\n\n### Tech Stack\n\n| Layer | Technology |\n|-------|-----------|\n| Language | TypeScript (strict, ES2022) |\n| Database | CockroachDB (PostgreSQL wire protocol) |\n| Runtime | Node.js \u003e= 20 |\n| Package Manager | pnpm with workspaces |\n| Build | Turborepo |\n| Desktop | Electron + electron-builder |\n| Mobile | React Native + Expo |\n| Testing | Vitest (3,800+ tests) |\n| CI/CD | GitHub Actions |\n| Execution | [IronClaw](https://github.com/nearai/ironclaw/), OpenClaw (via local bridge), and a Direct fallback — trust-ranked with automatic failover |\n\n## Deployment\n\n### Reverse proxies and `TRUST_PROXY_HOPS`\n\nThe API uses `req.ip` for every IP-keyed check: the session-auth\nlocalhost dev-bypass, the OAuth new-user rate limit, the\n`/api/v1/demo/preview` per-IP bucket, and any future per-client limit.\nBehind any reverse proxy, `req.ip` is the proxy's address by default —\nwhich collapses every per-IP limit into a single shared bucket. You\nneed `TRUST_PROXY_HOPS` set to the exact number of trusted hops between\nthe Node process and the real client.\n\nThe number you want is \"trusted proxies between this Node process and the\nactual client\" — count every box that legitimately appends to\n`X-Forwarded-For` on its way in, including any platform-injected router\nyour provider sits behind.\n\n| Topology | `TRUST_PROXY_HOPS` |\n|----------|--------------------|\n| Direct (no proxy, or untrusted upstream) | `0` (default) |\n| Single reverse proxy (your own nginx, Caddy, ELB target) | `1` |\n| Single platform hop (Fly's edge, Render's router, Heroku's app router, an AWS ALB on its own) | `1` |\n| CDN → your reverse proxy (Cloudflare → nginx → Node, no platform router) | `2` |\n| CDN → platform router → Node (Cloudflare → Fly/Render/Heroku → Node) | `2` |\n| CDN → platform router → your reverse proxy → Node (Cloudflare → Fly → nginx → Node) | `3` |\n| Multi-hop edge (Cloudflare → AWS WAF → ALB → Node) | `3+` |\n\nIf you can't draw the topology from memory, prefer Express's array/CIDR\nform for `trust proxy` (set per-network, not per-hop) — see the\n[Express docs](https://expressjs.com/en/guide/behind-proxies.html). Hop\ncounts are simple but brittle when a platform inserts a hop you didn't\nknow about.\n\n**Setting this too high is a security hole.** A client-controlled\n`X-Forwarded-For` becomes `req.ip` and bypasses every per-IP limit by\nheader rotation. **When in doubt, prefer fewer hops.**\n\nVerify after deploy:\n\n```bash\ncurl -H 'X-Forwarded-For: 1.2.3.4' https://your-api/api/health/live\n# response includes {\"clientIp\": \"...\"} — should NOT be \"1.2.3.4\"\n# unless 1.2.3.4 is actually a trusted upstream\n```\n\nIf `clientIp` in the response matches the spoofed header, your\n`TRUST_PROXY_HOPS` is too permissive and rate-limit bypass is open.\n\n### Public demo preview (`/api/v1/demo/preview`)\n\nThe public LLM-backed preview endpoint has three layers of protection:\n\n| Env var | Default | Purpose |\n|---------|---------|---------|\n| `DEMO_PREVIEW_DISABLED` | unset | Set to `1` to return 503 unconditionally — operator kill switch when the endpoint gets abused. |\n| `DEMO_PREVIEW_GLOBAL_LIMIT_PER_HOUR` | `500` | Hard global cap across all callers. Survives misconfigured `TRUST_PROXY_HOPS` and rotated-IP abuse. |\n| Per-IP bucket | 20 / 5 min | Built in. Effectiveness depends on `TRUST_PROXY_HOPS` resolving the real client IP. |\n\nThe per-IP bucket and the global cap are process-local. If you run\nmultiple API replicas, the global cap multiplies by replica count.\nFor unauthenticated public deployments at scale, replace the\nin-memory counter with Redis or a DB row with atomic increment\n(tracked in TODOS.md as a P3).\n\n## Trust Tiers\n\nSkyTwin uses a progressive trust model. Autonomy is earned, not assumed.\n\n| Tier | What It Means |\n|------|---------------|\n| `observer` | Default for new users. The twin proposes actions and surfaces them as approval requests — you approve, reject, or edit. Never auto-executes. |\n| `suggest` | Drafts actions for your review. You approve or edit before anything happens. |\n| `low_autonomy` | Auto-executes low-risk, reversible actions in trusted domains. Escalates everything else. |\n| `moderate_autonomy` | Handles most routine decisions. Escalates novel situations and high-cost actions. |\n| `high_autonomy` | Acts on your behalf across domains. Still respects hard limits and irreversibility checks. |\n\nTrust is **domain-specific**. You might be at `moderate_autonomy` for email but `suggest` for calendar. A bad decision in one domain can reduce trust in that domain without affecting others.\n\n## Documentation\n\n| Document | What's Inside |\n|----------|---------------|\n| [Product Spec](./docs/product-spec.md) | Vision, target user, operating principles, example workflows |\n| [Technical Spec](./docs/technical-spec.md) | Architecture, data flow, API endpoints, database schema |\n| [Safety Model](./docs/safety-model.md) | Threat model, trust tiers, defense layers, safety philosophy |\n| [Decision Engine](./docs/decision-engine.md) | Situation interpretation, risk assessment, confidence scoring |\n| [IronClaw Integration](./docs/ironclaw-integration.md) | Execution adapter, HMAC auth, failure handling |\n| [CockroachDB Architecture](./docs/cockroach-architecture.md) | Schema design (18+ tables), query patterns, versioning |\n| [Evals](./docs/evals.md) | Evaluation harness, scenario simulation, calibration metrics |\n| [Launch Plan](./docs/launch-plan.md) | Procurement + sequencing to public download links |\n| [Launch-Readiness Report](./docs/launch-readiness-report.md) | Current launch-blocker status: what's code-done vs. external |\n| [Release Procedure](./docs/release-procedure.md) | How to cut a release (tag → build.yml → draft → publish) + the signing/auto-update gaps |\n\n## Project Status\n\nSkyTwin is in **Tier 1 launch polish** (see [`docs/launch-plan.md`](./docs/launch-plan.md)) — Tier 0 (bundled installer, in-app OAuth setup, Gmail wizard) shipped; Tier 1 (cold-load demo, signed binaries, mobile cut, safety + privacy debt) is the active pre-launch sprint tracked under epic [#357](https://github.com/jayzalowitz/skytwin/issues/357). As of the 2026-06-14 audit ([`docs/launch-readiness-report.md`](./docs/launch-readiness-report.md)) the product is **launch-ready on the engineering side** — every code-writable launch criterion has shipped and the full suite (3,800+ tests) is green. The remaining blockers are external: code-signing certs (#368/#359), Google OAuth verification (#351), and mobile store assets + accounts (#369). The current shipped version is in the badge above and in [`CHANGELOG.md`](./CHANGELOG.md). Core decision pipeline, twin model, policy engine, and swappable memory layer are functional; Gmail and Google Calendar connectors run with real OAuth; desktop builds ship for all three platforms; the mobile app pairs via QR code and captures voice. v0.5.0.0 brought the one-command installer and a non-technical-user UX overhaul; the v0.6 series added the embedded local LLM (#187), tier-aware memory retrieval (#251), per-Lifebook surfaces (#193), the voice loop (mobile capture + Piper TTS), Epic A's cold-load demo unblocker (#358), and the Inbox-Intelligence briefing — a source-cited daily/weekly digest that splits to-dos from FYIs and now persists, routes, and reports memory-derived action opportunities (#484).\n\n**Free and open-source forever for personal use.** Team and hosted tiers are planned for organizations that need shared policies, audit logs, or managed infrastructure — see [`docs/launch-plan.md`](./docs/launch-plan.md) for the split.\n\n**What works today:**\n- One-command install (`curl | bash`) on macOS, Linux, and WSL — installs every dependency, clones the repo, starts the services, opens the dashboard\n- \"Ask your twin\" widget on the dashboard — type any situation, get a predicted action with reasoning and confidence, no accounts required\n- Tour mode with a fully populated sample profile so you can poke at decisions, learnings, and approvals before connecting your own accounts\n- Inbox-Intelligence briefing — a daily/weekly digest that splits **to-dos (act)** from **topics (FYI)**, cites the source signal behind every item, persists memory-derived action opportunities, routes them through policy plus IronClaw/OpenClaw/Direct execution, reports queued/executed/blocked/learning-needed outcomes, and offers a \"Power view\" toggle for the technical detail behind each call\n- Full decision pipeline: signal → interpret → decide → policy check → execute/escalate → explain → learn\n- LLM-powered decisions via configurable provider chain (Claude, GPT, Gemini, Ollama) with automatic fallback to built-in rules\n- Twin model with versioned profiles, confidence scoring, and preference learning\n- Policy engine with spend limits, trust tiers, and domain-specific rules\n- Swappable memory backend: gbrain (default — vector + tsvector RRF on CRDB) plus optional hybrid mode that adds the legacy spatial Memory Palace (#197). Selectable per-installation via `MEMORY_BACKEND` and per-user via the dashboard. See [`docs/memory-swap.md`](./docs/memory-swap.md).\n- Web dashboard for reviewing decisions, managing preferences, configuring AI providers, and auditing\n- Desktop app (macOS, Windows, Linux) with system-browser OAuth for Google accounts\n- Mobile app (iOS, Android) with QR pairing, push notifications, and voice capture that ships audio to the paired desktop for transcription\n- Embedded local LLM stack: llama.cpp text, whisper.cpp STT, Piper TTS (`/api/voice/transcribe` and `/api/voice/synthesize`) — runs entirely on-device when binaries + models are present\n- SSRF-safe URL validation for all LLM provider endpoints, with DNS rebinding protection\n- Dynamic adapter discovery for third-party execution plugins\n- 3,800+ tests with CI/CD on GitHub Actions\n\n**What's next:**\n- More connectors (Slack, Notion, bank feeds)\n- Hosted version with multi-tenant support\n- Improved preference learning from implicit signals\n\n## Contributing\n\nWe welcome contributions. See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on getting started, running tests, and submitting pull requests.\n\n## Security\n\nFound a vulnerability? See [SECURITY.md](./SECURITY.md) for responsible disclosure instructions.\n\n## License\n\n[Apache License 2.0](./LICENSE) — use it, modify it, build on it.\n\n## How this stays alive\n\n**Free and open source forever for personal use.** Future Team and Hosted tiers are planned for organizations that need shared policies, audit logs, or managed infrastructure. Personal features will never be paywalled.\n\nNo prices today — we're not ready to commit numbers, and overpromising on a backlog you haven't shipped is the easiest trust to lose. The shape of the future, not the price list.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjayzalowitz%2Fskytwin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjayzalowitz%2Fskytwin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjayzalowitz%2Fskytwin/lists"}