Move whole apps in and out of Gipity. One pipeline, three transports:

Import always creates a NEW project. It never merges into or overwrites an existing one - a bad import is undone by deleting the new project. Secrets, custom domains, chats, and database rows never travel in a bundle.

The import flow (agent)

Use the app_import tool, in this order:

  1. action: 'status' - is the user's GitHub connected? If not, the result contains the connect link. Send it to the user: GitHub's own screen lets them pick all-repos or specific repos (that IS the permission grant - don't ask them to create tokens or paste keys). Re-run status after they finish.
  2. action: 'list_repos' - when the user names a repo loosely ("my crm app"), list what's reachable and confirm the exact repo before importing. If the repo isn't listed, the user needs to re-run the connect link and grant it.
  3. action: 'inspect' with source: 'github:owner/repo' - preview files, deploy phases, and function permissions before importing. Show the user what the app will do (functions, tables, fetch domains) when the bundle came from someone else.
  4. action: 'import' - creates the new project and writes the files.
  5. Detect the source stack (table below) and port if needed.
  6. gipity deploy dev, verify with page inspect, then hand the user the dev URL and the "needs your attention" report.

Source syntax: github:owner/repo, github:owner/repo@branch-or-tag, github:owner/repo/sub/path@ref (monorepos), or a pasted https://github.com/... URL.

CLI equivalents

gipity github connect          # print the GitHub connect link (repo picker included)
gipity github repos            # list reachable repos
gipity load github:owner/repo  # import as a new project + link a local directory
gipity load app.gip            # import a .gip bundle
gipity load app.gip --inspect  # peek inside without creating anything
gipity save                    # export the current project to ./<slug>.gip

gipity save + gipity load is also the fork/backup loop: save, send the file to anyone, they load it and get their own copy (a fresh project with re-pointed references).

Detect what you imported

Check for these fingerprints (in this order - first match wins):

Fingerprint Source Deploys as-is?
gipity.yaml at root A Gipity app Yes - gipity deploy dev now
plain index.html at root or src/, no build step Static site Nearly - move to src/, add nothing
supabase/ dir, @supabase/supabase-js in package.json Lovable / Bolt (Supabase backend) No - port recipe A
.replit, replit.nix, or server/ + Express + Drizzle Replit (Agent app) No - port recipe B
vercel.json and/or api/ dir, no next.config.* Vercel (static/Vite + api functions) No - port recipe C
next.config.* with SSR/ISR/app-router server components Next.js server app No - this is a REBUILD, recipe D
vite.config.* / CRA / Astro / Svelte, frontend-only Vite-family SPA Mostly - build to static, recipe E

Always tell the user which kind you detected and what the port involves BEFORE spending a long time on it.

Porting recipes

General rules for every port:

A. Lovable / Bolt (Vite + React + Supabase)

The frontend ports cleanly; the backend is the work, because these apps usually query the database directly from the browser with supabase-js + RLS policies - there is often no API layer to port, you synthesize one.

  1. Build the frontend: npm run build output (via gipity sandbox run - there is no local runtime) → copy dist/ into src/.
  2. Schema: supabase/migrations/*.sql is plain Postgres - adapt into migrations/ (strip Supabase-specific extensions/schemas like auth.* references).
  3. Replace supabase.from('table')... browser calls with Gipity functions: one function per logical operation, with tables permissions declared in gipity.yaml. RLS policies become function-level auth checks (ctx.auth.userId + WHERE clauses) - port the intent of each policy, don't try to recreate RLS.
  4. supabase.auth.* → Gipity auth (load app-auth). Existing end-users must sign up again - flag it.
  5. Supabase Edge Functions (Deno) → Gipity functions (swap Deno APIs for the function runtime; service-role calls become declared-permission queries).
  6. Storage uploads → Gipity Storage (load app-files); Realtime channels → the realtime kit.
  7. Data: if the user wants their rows, they can export from Supabase (pg_dump/CSV) and you load via gipity db - guided, not automatic.

B. Replit (React + Express + Drizzle + Postgres)

Replit Agent apps follow a predictable template - client/ (Vite React), server/routes.ts (Express), shared/schema.ts (Drizzle):

  1. Frontend: build the Vite client → src/.
  2. Decompose Express into per-route functions: each app.get/post(...) handler becomes one file in functions/, request/response translated to the function signature. Middleware (auth, validation) inlines into the functions that used it.
  3. Drizzle schema → SQL migrations (drizzle-kit generate emits SQL, or translate shared/schema.ts by hand).
  4. Replit DB (key-value) → a simple table; Replit Auth → Gipity auth; Object Storage → Gipity Storage.
  5. Drop .replit, replit.nix, .upm/. If replit.nix declared system packages the app truly needs at runtime, flag it - that's a sign of a server-shaped app.
  6. Secrets: whatever the code reads from process.env goes on the report.

C. Vercel (static or Vite frontend + api/ functions)

  1. Frontend: if it's a framework app, build to static output → src/; if plain static, copy as-is.
  2. api/*.js|ts handlers → functions/: convert (req, res) or Web Request/Response handlers to the Gipity function signature; declare fetch_domains/tables in gipity.yaml.
  3. vercel.json rewrites/redirects/headers: client-side routing usually covers rewrites for SPAs; anything else, flag it.
  4. @vercel/postgres → Gipity DB (it's plain Postgres - queries mostly survive); @vercel/kv → a table; @vercel/blob → Gipity Storage. Vercel crons → Gipity workflows/Jobs.
  5. Env vars live only in Vercel's dashboard - the user re-enters them.

D. Next.js with server features (SSR / ISR / server components) - and v0 output

Be honest: this is a rebuild, not a file port. Gipity serves static frontends + serverless functions; there is no Node server rendering pages per-request. Two good paths:

Never import a server-rendered Next.js app and leave the user with something that half-works.

E. Vite-family SPA (no backend)

Build → src/ → deploy. The only real work is checking for hardcoded API URLs and env vars (import.meta.env.*), which become either Gipity functions or report items.

The "needs your attention" report

End every port with a short report to the user:

Imported <source> → project <name> (dev URL after deploy)

Working now: <what deploys green>
Secrets you need to provide: <NAMES the code references - never guess values>
Sign-ins: existing users must re-register (auth systems don't transfer)
Data: <how to bring rows over, if they want them>
Not ported (and why): <anything skipped - be specific>

Why port to Gipity (when the user asks)

Be honest and concrete - never trash-talk, but don't be shy either. The true pitch:

Common mistakes