Inspiration

The idea for Liftoff originated from Rokkit200 co-founder Gareth Kropman and a very ordinary problem he was facing: a small-business owner losing an hour a day stitching together tools he already had. Custom GPTs knew his sales pipeline, product frameworks, and pricing logic. Other bots produced LinkedIn content and banner art. Gmail nudged him about follow-ups. Everything worked, but nothing was connected, nothing cohesive. Every day he had to remember to copy content out of one system and paste it into another, and every day client calls interrupted him mid-post.

He tried the "real" answer: Microsoft Dynamics 365 lasted a day or two before he gave up. The pattern he suspected is that most small businesses either abandon a serious CRM or fall back to a spreadsheet-shaped one, and neither option turns marketing into sales without human glue. He wanted to "click one button." No Hermes setup, no admin panel, no state-machine diagramming session with a consultant. Just a chat with something that knows the business, and a pipeline that runs itself between conversations.

That framing became Liftoff: an AI-powered CRM you talk to, not one you configure.

What it does

Liftoff is a chat-first CRM for small businesses. Instead of just a settings surface, the user has a conversation with an AI assistant that runs their sales and marketing pipeline end-to-end.

Core surfaces built

  • AI-guided onboarding: the user's first interaction is a chat that discovers target audience, channels, cadence, and brand voice, then writes it back to the business profile.
  • Chat panel, everywhere: a persistent AI Elements assistant lives inside the app shell. Every screen has the same assistant, powered by streaming markdown, with approval-gated tools for anything that mutates data.
  • Leads pipeline with drag-and-drop swimlanes: a Kanban board over the lead state machine, wired to real server actions.
  • Campaigns and campaign assets, with dedicated compose-and-author tools per channel: Instagram, Facebook, LinkedIn, WhatsApp, and Email. Each renders as its own confirmation card in the chat, respecting the character-count and formatting quirks of the target platform.
  • Actions: the assistant can propose actions (reminders, follow-ups, next steps) that a user approves or dismisses from either the chat or the Actions screen.
  • Offers, dashboard, business profile: all rendered from live data, all editable by tools.
  • Paystack billing: full subscription lifecycle, including schema, sync foundation, webhook + replay + fixtures, client wrapper, server actions, auth gate, callbacks, pricing page, and renewal handling with atomic conditional updates.
  • AI usage tracking: every inference call is metered against a per-workspace budget with cost fields and rate tracking for controlling margin.

The whole product uses two identities in tension by design. Clerk holds the client-visible identity; Supabase holds a surrogate UUID the client never sees. Right-to-be-forgotten works because nothing on the browser side ever holds the real primary key.

How we built it

Stack

  • Next.js 16 App Router, React 19, TypeScript strict
  • Tailwind v4 CSS-first
  • shadcn on @base-ui/react
  • Clerk for identity, Supabase (Postgres) + Drizzle ORM for data, RLS as the security boundary
  • AI SDK v7 (ai, @ai-sdk/react) with Google Vertex as the inference backend, Streamdown for streaming markdown
  • TanStack Query on the client, dnd-kit for the pipeline board
  • Paystack for billing, Cloudflare (opennext) for deploy
  • Vendored components/ai-elements/ treated like components/ui/ and edited in place

Timeline

  • 2026-06-18: first commit, "Adding shadcn base with nova"
  • 2026-06-24 → 30: design system, service scaffolding, Clerk + Supabase wiring, initial prototype
  • 2026-07-07 → 09: AI SDK chat streaming with tool approvals, DB schema, Cloudflare deployment
  • 2026-07-10 → 22: server actions across every domain (actions, offers, campaigns, campaign assets, pipeline, leads, global, dashboard, AI) rolled out in a single feature blitz, Paystack schema + webhooks landed in parallel
  • 2026-07-23 → 31: the tool layer: Ask Questions, date/time, leads, campaigns, campaign assets, offers, actions, then platform-specific asset composers for Instagram, Facebook, LinkedIn, WhatsApp
  • 2026-08-04 → 12: polish and integration bugs (sidebar counters, escape-character rendering, pipeline drop-back, Actions tab counts), then pricing page + FAQ, then dev→main release

Delivery cadence: 65 merged PRs across ~8 weeks, four human contributors, with GitHub Copilot as an assistant reviewer.

Working method

The Kanban board was the source of truth. Tickets were written in enough detail to feed directly into Claude Code, and Claude did the drafting. Nicole and Danielle's canonical moment: they took a Figma design output, fed it straight to the AI, and got a working implementation with mock data on the first pass. The team's CLAUDE.md and AGENTS.md codified the non-obvious rules (Next.js 16 breaking changes, the Clerk-id-vs-uuid boundary, Drizzle snapshot drift, middleware.ts not proxy.ts) so the AI would stop rediscovering them each session.

Challenges we ran into

The PR bottleneck

Reviews were the single biggest source of friction. Back-and-forth caused merge conflicts, PRs stacked on unseen dependencies, and Copilot's inline comments sometimes arrived slowly enough that a whole cycle stalled. We experimented with AI-generated risk labels (high/critical) but they created confusion about who was supposed to review. Eventually we dropped the strictness.

Duplicate confirmation cards

Approval-gated tools were streaming into brand-new assistant messages instead of merging back into the existing one, producing a duplicate card next to the original. The bug only surfaced after a tool approval, so it was invisible on fresh turns. The fix (passing originalMessages to createUIMessageStream) was called out in AGENTS.md so no future caller reintroduces it.

Definition of done was implicit, not explicit

Ticket wording implied acceptance criteria, but "implied" wasn't tight enough for AI-assisted implementation; Claude/Copilot would technically complete a ticket and still miss the intent. The team's retro conclusion was to make definition-of-done explicit and to trim the template that felt overwrought.

Token limits, not model quality

Once the accelerated dev pattern hit stride, output quality was rarely the bottleneck; context window was. Long agent runs were more likely to run out of tokens than to produce bad code.

Cloudflare + Next.js 16

Deployment succeeded and the free preview links were a genuine boon, but Next.js 16 on Cloudflare isn't quite first-class yet: for compatibility with opennext, we had to keep the routing convention at middleware.ts even though Next 16 renamed it. That's the kind of decision that only shows up when you try to ship, and it took tedious trial and error to resolve.

Accomplishments we're proud of

A working, chat-first CRM in ~8 weeks

Well over 100 completed Kanban cards, 65 chunky PRs merged, full auth, billing, RLS, streaming AI, five platform-specific asset composers, and a live Cloudflare deploy, all on an unfamiliar frontier.

A defensible identity boundary

No workspace UUID ever crosses to the client. Cache keys use the Clerk id, requireWorkspace() gates every domain action server-side, and RLS in Postgres is the actual security boundary, not app code.

AI-accelerated development that actually accelerated

Nicole and Danielle's Figma-to-implementation demo, tickets that fed directly into Claude, and reusable AGENTS.md files that let the team solve a domain once and then move fast.

Approval-gated tools done properly

The full AI SDK v7 flow with sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses, correctly-threaded message ids, and per-channel compose tools that respect Instagram's character limits, WhatsApp's markdown rules, and LinkedIn's formatting.

What we learned

  • Nestable agent files are a compounding asset. Solve a domain once, document it clearly in an AGENTS.md, and every future AI session in that area gets faster and more correct. This is the single practice we're carrying into everything we build next.
  • Kanban-first works with AI. When the ticket is detailed enough, Claude can implement it. When it isn't, the AI produces something plausible that misses the point and leads to thrash. The rate-limiting resource on an AI-native team isn't just AI; it's also ticket clarity.
  • PR review order matters. The team's forward plan is to have Copilot review first and resolve all low-hanging comments before human review, so humans aren't double-commenting on the same lint-shaped issues or letting Copilot comments drag.
  • Domain isolation reduces friction. Assigning one domain per developer would have cut merge conflicts and stacked PRs. The tradeoff is less cross-stack exposure: a real cost, but a manageable one.
  • Some auth choices are worth revisiting. Clerk did the job, but we flagged Auth0 as potentially swappable if we hit a wall on customization or pricing.
  • Design-to-code is now genuinely fast. The Figma → AI → working screen loop is short enough that it changes how much upfront design matters, potentially even cutting out Figma, with Claude Design/OpenDesign becoming more and more capable.

What's next

The MVP proves the loop; the roadmap is about making the pipeline genuinely run itself.

Delivering the core promise

  • Connections at scale: solving the "connections" problem Gareth flagged in the original conversation, with OAuth to LinkedIn, Facebook, Instagram, and WhatsApp, so users don't have to hand over credentials or file uploads. Until then, the MVP fallback (output copy, images, and HTML for manual posting) is a real user-facing feature, not a shortcoming.
  • Two-way channel sync: once OAuth lands, ingest replies, DMs, and comments back into the pipeline so an inbound message auto-creates or advances a lead, closing the loop from post to conversation to sale.
  • Between-session autonomy: the assistant does real work while the user is away, drafting the week's content, queuing follow-ups, and flagging stalled leads, then handing it back as a digest to approve. This is the tagline made literal.
  • Proactive insights: turn the pipeline and AI-usage data we already meter into recommendations ("your LinkedIn posts convert 3× better than Instagram. Want to shift cadence?"), so the assistant advises rather than only executing.

Expanding the product

  • Content calendar and scheduling: plan and schedule a week across channels at once instead of one post at a time, so client calls stop interrupting the work mid-post.
  • Lead enrichment: pull public company and role context to personalise outreach automatically.
  • Vertical onboarding templates: preloaded playbooks for coaches, agencies, real-estate agents, and the like, so the onboarding chat starts from a warmer default.

Scaling the platform

  • Team workspaces: move beyond org-of-one to multi-user workspaces with roles; the RLS boundary is already in place, so this is a natural next step.
  • Broader billing: expand past ZAR-only to more currencies (and, if needed, a second processor) to open markets beyond South Africa.
  • Agent eval and tracing: an evaluation and observability layer to keep long agent runs reliable as features grow, a direct response to the "token limits, not model quality" lesson.

Hardening the prototype

  • Smooth the rough edges of the rapid hackathon prototype.
  • Dogfood Liftoff on Rokkit200's own sales pipeline.

Built With

Share this project:

Updates

posted an update

Update 9 - Submission prep (2026-08-13 → 17)

With the release cut, the last week is about the submission itself. No more significant feature commits - the codebase is mostly frozen, with some bug fixes and final outstanding feature finalization. The team has shifted to writing, gathering, and coordinating.

The story surface got divided up. Gareth is contributing the product origin narrative (the "click one button" conversation that started this) so we don't have to reconstruct it from memory. Chris is compiling the technical timeline from git history and the Kanban. Deshen is pulling screenshots of the key surfaces - the onboarding chat, the leads pipeline mid-drag, a Confirmation card, composer output for each channel. Video capture for a walkthrough is in progress; Google Flow was flagged in the retro as worth exploring for a higher-fidelity product demo cut.

Honest note on process: we didn't keep a running log during the build. This update sequence is being written now, from git history, PR bodies, the Kanban board's Done column, and the retro transcript, with Claude Code helping stitch the picture together. It feels like a fitting way to close out a project where the working method itself was the thing we learned most from.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 8 - Release (2026-08-12)

Pricing page and FAQ, then dev→main release. That closes the loop end to end: waitlist → auth → AI-guided onboarding → business profile → leads pipeline → campaigns → per-channel asset composers → approval → Paystack subscription. Live on Cloudflare.

Final numbers: 65 merged PRs across roughly eight weeks, well over 100 Kanban cards done, four human contributors plus Copilot as an assistant reviewer. Full Clerk auth with the workspace-uuid boundary intact, RLS as the actual security boundary in Postgres, Paystack billing lifecycle, streaming AI with approval-gated tools, five platform-specific asset composers, drag-and-drop lead pipeline, AI usage metering per workspace.

Retro consensus: nestable AGENTS.md files were the single most compounding practice we picked up. Solve a domain once, document it clearly, and every future AI session in that area gets faster and more correct. The rate-limiting resource on an AI-native team isn't just AI - it's ticket clarity. Everything we're building next carries that forward.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 7 - Composers complete + polish pass (2026-08-04 → 06)

WhatsApp compose tool shipped with a stripChannelMarkup helper for WhatsApp-style heading formatting. Email compose tool followed. All five channels - Instagram, Facebook, LinkedIn, WhatsApp, Email - are now first-class citizens of the chat.

Dashboard wired to real server actions, with null lead state getting its own neutral badge instead of "info", overdue-count text hidden when the count is zero, and toast noise suppressed on silent background dashboard counts. Sidebar Leads/Actions badges now show real counts. Conversation tracking merged.

A subtle bug caught here: approval-gated tools were streaming into brand-new assistant messages instead of merging back into the existing one, producing a duplicate Confirmation card next to the original. The bug only surfaced after a tool approval, so it was invisible on fresh turns. Fix: pass originalMessages to createUIMessageStream so the SDK reuses the assistant message id. Documented in AGENTS.md so no future caller reintroduces it.

Also fixed this cycle: Actions screen tab counts, pipeline leads flashing back to the previous column on drop, markdown escape characters bleeding through the raw-text tool UI. Default GitHub PR template added.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 6 - The tool layer (2026-07-23 → 31)

The domain-tool layer took shape this fortnight. Campaign tools, offer tools, campaign asset tools, action tools, business profile server actions, lead server actions integration, campaign asset server actions integration, AI server actions integration. AI usage / cost table schemas improved with a types-generation follow-up. Date/time tool for the model. Tool Call Preamble.

Paystack renewal handling landed in two parts: DB updates, then code updates enforcing a one-way status rule and atomic conditional updates.

Platform-specific composer tools started rolling out. Each renders as its own Confirmation card in the chat and respects the target platform's formatting quirks. Instagram first, then Facebook with URL scheme enforcement on the request schema, then LinkedIn. Nicole and Danielle did the canonical AI-accelerated moment of the project this cycle: took a Figma design output, fed it straight to the AI, and got a working implementation with mock data on the first pass.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 5 - UI wired to live data (2026-07-16 → 22)

Global toast system in. Production setup. Pipeline board wired to live data with drag-and-drop persistence. Actions page and dashboard wired to live service calls. Offer server actions integrated into the FE. Campaign server actions integrated. AI server actions initial migration files. Ask Questions tool. Hydration console errors chased down and resolved. Lead tools - first entry in the domain-tool layer - merged.

We also promoted some fields to bigint once we thought seriously about long-tail workspace usage. Cheap to change now while empty, expensive to change later.

The bottleneck is now PR review, not implementation. Merge conflicts and stacked PRs on unseen dependencies are showing up. Copilot's inline comments sometimes lag long enough that a whole cycle stalls. We're experimenting with AI-generated risk labels but they're also causing confusion.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 4 - Server actions blitz + Paystack begins (2026-07-10 → 15)

Nine tickets in a single PR: actions, offers, campaigns, campaign assets, pipeline, leads, global, dashboard, and AI server actions all implemented in one blast. Pipeline drag-and-drop swimlanes. Business profiles schema verified against real fields.

Paystack kicked off in force. Schema, then a Paystack sync foundation with webhook + replay + fixtures, client wrapper, server actions, auth gate, callbacks, and pricing page all landing. Clerk waitlist page. First release to main. One production oddity found and fixed along the way: orgs weren't being inserted into the DB (oops).

The Drizzle snapshot bit us. AI usage tracking had originally been named differently, so its live Postgres constraints are still named that way even though the snapshot now reflects the new naming. A migration that dropped by the snapshot's name failed on dev and rolled everything back. New rule, now documented in AGENTS.md: introspect the real DB before writing destructive DDL, dry-run inside a rolled-back transaction, use IF EXISTS on every DROP.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 3 - First AI chat + Cloudflare deploy (2026-07-07 → 09)

The big week. AI SDK v7 chat streaming with tool approvals is live. The AI Elements assistant lives in the app shell on every screen. Approval-gated tools drive Confirmation cards; sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses handles resubmission after each approval. Assistant output streams as markdown via Streamdown, not plain text.

DB schema landed. Cloudflare deployment stood up (painful), and the free per-PR preview links are already earning their keep in review. AI usage cost + rate tracking table shipped early so we can meter every inference call against a per-workspace budget from day one and control the margins on inference.

Clerk component visuals refined. AI-guided onboarding flow and business profile scaffolding. Service call stabilization, plus a quality-of-life sweep. We now have the shape of the product - chat, business profile, and the plumbing to add domain surfaces on top.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 2 - Foundations (2026-06-24 → 30)

Design system foundation and component library merged. Thomas shipped Clerk identity + Supabase data layer wiring, with an unusual boundary decision that's turning out to be load-bearing: Clerk holds the client-visible id, Supabase holds a surrogate UUID that never leaves the server. Cache keys will use the Clerk id; every domain server action will guard. Right-to-be-forgotten works because nothing on the browser side ever holds the real primary key.

Basic Next.js service scaffolding in, Zod validation for request shapes, Danielle and Nicole shipped the initial app build, Prettier config sorted. GCP inference PoC was investigated and then deliberately torn back out once we settled the inference strategy (go fast, break things).

Working rhythm has emerged: tickets written detailed enough to feed straight into Claude Code, and Claude does the drafting. Early signs this is going to matter more than the individual stack choices.

Log in or sign up for Devpost to join the conversation.

posted an update

Update 1 - Project kick-off (2026-06-18)

We're building Liftoff - internal codename for an AI-powered CRM aimed at small businesses. Origin story: Rokkit200 co-founder Gareth is losing an hour a day stitching content between disconnected tools (custom GPTs for sales, other bots for content, Gemini + Gmail for follow-ups) and is frustrated with "real" CRMs like Dynamics 365 within a day or two. He wants a chat interface, not a settings panel - "I want to click one button."

First commit is in: Adding shadcn base with nova. Stack call: Next.js 16 App Router, React 19, TypeScript strict, Tailwind v4 (CSS-first, no config file), shadcn on @base-ui/react (not Radix, style "base-nova"). Cloudflare via opennext for deploy. Naming is done - Liftoff sticks (for now).

Kanban board is up. Investigations queued for billing/payment options, data retention, external Clerk billing, and inference on GCP. Next: design system, service scaffolding, and the identity story.

Log in or sign up for Devpost to join the conversation.