-
+
# LynxPrompt
diff --git a/cli/src/commands/wizard.ts b/cli/src/commands/wizard.ts
index 3b8996ec..7ea04741 100644
--- a/cli/src/commands/wizard.ts
+++ b/cli/src/commands/wizard.ts
@@ -9,6 +9,12 @@ import { detectProject, detectFromRemoteUrl, isGitUrl } from "../utils/detect.js
import { generateConfig, GenerateOptions, parseVariablesString } from "../utils/generator.js";
import { isAuthenticated, getUser } from "../config.js";
import { api, ApiRequestError } from "../api.js";
+import {
+ LANGUAGES as SHARED_LANGUAGES,
+ FRAMEWORKS as SHARED_FRAMEWORKS,
+ DATABASES as SHARED_DATABASES,
+ TEST_FRAMEWORKS as SHARED_TEST_FRAMEWORKS,
+} from "../utils/wizard-options.js";
// Draft management - local storage in .lynxprompt/drafts/
const DRAFTS_DIR = ".lynxprompt/drafts";
@@ -238,52 +244,10 @@ const ALL_PLATFORMS = [
];
-// Languages
-const LANGUAGES = [
- { title: "π· TypeScript", value: "typescript" },
- { title: "π‘ JavaScript", value: "javascript" },
- { title: "π Python", value: "python" },
- { title: "π΅ Go", value: "go" },
- { title: "π¦ Rust", value: "rust" },
- { title: "β Java", value: "java" },
- { title: "π C#/.NET", value: "csharp" },
- { title: "π Ruby", value: "ruby" },
- { title: "π PHP", value: "php" },
- { title: "π Swift", value: "swift" },
- { title: "πΆ Kotlin", value: "kotlin" },
- { title: "β¬ C/C++", value: "cpp" },
-];
-
-// Frameworks
-const FRAMEWORKS = [
- { title: "βοΈ React", value: "react" },
- { title: "β² Next.js", value: "nextjs" },
- { title: "π Vue.js", value: "vue" },
- { title: "π
°οΈ Angular", value: "angular" },
- { title: "π₯ Svelte", value: "svelte" },
- { title: "π Express", value: "express" },
- { title: "β‘ FastAPI", value: "fastapi" },
- { title: "πΈ Django", value: "django" },
- { title: "π§ͺ Flask", value: "flask" },
- { title: "π Spring", value: "spring" },
- { title: "π Rails", value: "rails" },
- { title: "π΄ Laravel", value: "laravel" },
- { title: "ποΈ NestJS", value: "nestjs" },
- { title: "β‘ Vite", value: "vite" },
- { title: "π± React Native", value: "react-native" },
-];
-
-// Databases
-const DATABASES = [
- { title: "π PostgreSQL", value: "postgresql" },
- { title: "π¬ MySQL", value: "mysql" },
- { title: "π MongoDB", value: "mongodb" },
- { title: "π΄ Redis", value: "redis" },
- { title: "π SQLite", value: "sqlite" },
- { title: "βοΈ Supabase", value: "supabase" },
- { title: "π₯ Firebase", value: "firebase" },
- { title: "π Prisma", value: "prisma" },
-];
+// Languages, frameworks, and databases imported from shared package (wizard-options.ts)
+const LANGUAGES = SHARED_LANGUAGES;
+const FRAMEWORKS = SHARED_FRAMEWORKS;
+const DATABASES = SHARED_DATABASES;
// Package managers (JS/TS only)
const PACKAGE_MANAGERS = [
@@ -641,6 +605,12 @@ const AI_BEHAVIOR_RULES = [
{ id: "run_tests_before_commit", label: "Run Tests Before Commit", description: "AI must run the test suite and ensure all tests pass before suggesting a commit", recommended: true },
{ id: "follow_existing_patterns", label: "Follow Existing Patterns", description: "AI should study existing code and follow the same naming, structure, and conventions used in the codebase", recommended: true },
{ id: "ask_before_large_refactors", label: "Ask Before Large Refactors", description: "AI should always ask for explicit approval before making significant architectural changes or refactoring multiple files", recommended: true },
+ // Burke Holland-inspired rules
+ { id: "code_for_llms", label: "Code for LLMs", description: "Optimize code for LLM reasoning: flat/explicit patterns, minimal abstractions, structured logging" },
+ { id: "self_improving", label: "Self-Improving Config", description: "AI updates this config file when it learns new project patterns or conventions" },
+ { id: "verify_work", label: "Always Verify Work", description: "Run tests, check builds, and confirm changes work before returning control", recommended: true },
+ { id: "terminal_management", label: "Terminal Management", description: "Reuse existing terminals and close unused ones" },
+ { id: "check_docs_first", label: "Check Docs First", description: "Check documentation via MCP or project docs before assuming knowledge about APIs" },
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
@@ -789,49 +759,8 @@ const BOUNDARY_OPTIONS = [
"Skip tests temporarily",
];
-// Testing frameworks - expanded to match WebUI
-const TEST_FRAMEWORKS = [
- // JavaScript/TypeScript
- "jest", "vitest", "mocha", "ava", "tap", "bun:test",
- // E2E/Integration
- "playwright", "cypress", "puppeteer", "selenium", "webdriverio", "testcafe",
- // React/Frontend
- "rtl", "enzyme", "storybook", "chromatic",
- // API/Mocking
- "msw", "supertest", "pact", "dredd", "karate", "postman", "insomnia",
- // Python
- "pytest", "unittest", "nose2", "hypothesis", "behave", "robot",
- // Go
- "go-test", "testify", "ginkgo", "gomega",
- // Java/JVM
- "junit", "testng", "mockito", "spock", "cucumber-jvm",
- // Ruby
- "rspec", "minitest", "capybara", "factory_bot",
- // .NET
- "xunit", "nunit", "mstest", "specflow",
- // Infrastructure/DevOps
- "terratest", "conftest", "opa", "inspec", "serverspec", "molecule", "kitchen", "goss",
- // Kubernetes
- "kubetest", "kuttl", "chainsaw", "helm-unittest",
- // Security
- "owasp-zap", "burpsuite", "nuclei", "semgrep",
- // Load/Performance
- "k6", "locust", "jmeter", "artillery", "gatling", "vegeta", "wrk", "ab",
- // Chaos Engineering
- "chaos-mesh", "litmus", "gremlin", "toxiproxy",
- // Contract Testing
- "spring-cloud-contract", "specmatic",
- // BDD
- "cucumber", "gauge", "concordion",
- // Mutation Testing
- "stryker", "pitest", "mutmut",
- // Fuzzing
- "go-fuzz", "afl", "libfuzzer", "jazzer",
- // PHP
- "phpunit", "pest", "codeception",
- // Rust
- "cargo-test", "rstest", "proptest",
-];
+// Testing frameworks imported from shared package (includes XCTest, Espresso, etc.)
+const TEST_FRAMEWORKS: string[] = SHARED_TEST_FRAMEWORKS;
// Test levels
const TEST_LEVELS = [
@@ -2250,7 +2179,7 @@ async function runInteractiveWizard(
name: "useGitWorktrees",
message: chalk.white("π² Do you plan on working with several AI agent sessions in this repository?"),
initial: true,
- hint: "If yes, AI will be instructed to always use git worktrees for each task",
+ hint: "Enable if you use multiple AI agents (Cursor, Claude, Copilot) in parallel. Each task gets its own git worktree to prevent branch conflicts.",
}, promptConfig);
answers.useGitWorktrees = useGitWorktreesResponse.useGitWorktrees ?? true;
@@ -3163,6 +3092,17 @@ async function runInteractiveWizard(
}, promptConfig);
answers.explanationVerbosity = verbosityResponse.explanationVerbosity || "balanced";
+ // Workaround behavior
+ const workaroundResponse = await prompts({
+ type: "toggle",
+ name: "attemptWorkarounds",
+ message: chalk.white("When stuck, should the AI attempt workarounds?"),
+ initial: true,
+ active: "Yes, try workarounds",
+ inactive: "No, stop and ask",
+ }, promptConfig);
+ answers.attemptWorkarounds = workaroundResponse.attemptWorkarounds ?? true;
+
// Focus areas
const accessibilityResponse = await prompts({
type: "toggle",
@@ -3184,6 +3124,68 @@ async function runInteractiveWizard(
}, promptConfig);
answers.performanceFocus = performanceResponse.performanceFocus ?? false;
+ // MCP Servers
+ console.log();
+ console.log(chalk.gray(" π MCP (Model Context Protocol) servers let the AI interact with external tools"));
+ console.log(chalk.gray(" like databases, APIs, file systems, and more. List any you have configured."));
+ const mcpServersResponse = await prompts({
+ type: "text",
+ name: "mcpServers",
+ message: chalk.white("MCP servers (comma-separated, or leave empty):"),
+ hint: chalk.gray("e.g. filesystem, github, postgres, docker"),
+ }, promptConfig);
+ answers.mcpServers = mcpServersResponse.mcpServers || "";
+
+ // Server access
+ const serverAccessResponse = await prompts({
+ type: "toggle",
+ name: "serverAccess",
+ message: chalk.white("Does this project require logging into a server?"),
+ initial: false,
+ active: "Yes",
+ inactive: "No",
+ }, promptConfig);
+ answers.serverAccess = serverAccessResponse.serverAccess ?? false;
+
+ if (answers.serverAccess) {
+ const sshKeyPathResponse = await prompts({
+ type: "text",
+ name: "sshKeyPath",
+ message: chalk.white("SSH key path (leave empty for default ~/.ssh/):"),
+ hint: chalk.gray("e.g. ~/.ssh/id_ed25519"),
+ }, promptConfig);
+ answers.sshKeyPath = sshKeyPathResponse.sshKeyPath || "";
+ }
+
+ // Manual deployment (only ask if no CI/CD was selected)
+ const hasCicd = (answers.cicd as string[])?.length > 0;
+ if (!hasCicd) {
+ const manualDeployResponse = await prompts({
+ type: "toggle",
+ name: "manualDeployment",
+ message: chalk.white("Do you deploy manually (no CI/CD)?"),
+ initial: false,
+ active: "Yes",
+ inactive: "No",
+ }, promptConfig);
+ answers.manualDeployment = manualDeployResponse.manualDeployment ?? false;
+
+ if (answers.manualDeployment) {
+ const deployMethodResponse = await prompts({
+ type: "select",
+ name: "deploymentMethod",
+ message: chalk.white("How do you deploy?"),
+ choices: [
+ { title: "π³ Portainer (GitOps stacks)", value: "portainer" },
+ { title: "π¦ Docker Compose (manual)", value: "docker_compose" },
+ { title: "βΈοΈ Kubernetes (kubectl)", value: "kubernetes" },
+ { title: "π₯οΈ Bare metal (direct)", value: "bare_metal" },
+ ],
+ }, promptConfig);
+ answers.deploymentMethod = deployMethodResponse.deploymentMethod || "";
+ }
+ }
+
console.log();
console.log(chalk.gray(" π Select files the AI should read first to understand your project context."));
console.log(chalk.gray(" These help the AI understand your codebase, APIs, and conventions."));
@@ -3995,5 +3997,15 @@ async function runInteractiveWizard(
additionalLibraries: answers.additionalLibraries as string,
// Docker image names
dockerImageNames: answers.dockerImageNames as string,
+ // MCP servers
+ mcpServers: answers.mcpServers as string,
+ // Workaround behavior
+ attemptWorkarounds: answers.attemptWorkarounds as boolean,
+ // Server access
+ serverAccess: answers.serverAccess as boolean,
+ sshKeyPath: answers.sshKeyPath as string,
+ // Manual deployment
+ manualDeployment: answers.manualDeployment as boolean,
+ deploymentMethod: answers.deploymentMethod as string,
};
}
diff --git a/cli/src/utils/generator.ts b/cli/src/utils/generator.ts
index 788abe82..15326ca6 100644
--- a/cli/src/utils/generator.ts
+++ b/cli/src/utils/generator.ts
@@ -91,6 +91,16 @@ export interface GenerateOptions {
additionalLibraries?: string; // comma-separated (e.g., "Telethon, APScheduler, alembic")
// Docker image names
dockerImageNames?: string; // comma-separated (e.g., "myuser/myapp, myuser/myapp-viewer")
+ // MCP servers the developer uses (e.g., "filesystem, github, postgres")
+ mcpServers?: string;
+ // Whether AI should attempt workarounds when stuck, or stop and ask
+ attemptWorkarounds?: boolean;
+ // Server/SSH access
+ serverAccess?: boolean; // Whether the project requires server access
+ sshKeyPath?: string; // SSH key path (empty = default location)
+ // Manual deployment (when no CI/CD)
+ manualDeployment?: boolean; // Whether deployment is manual (no CI/CD)
+ deploymentMethod?: string; // portainer, docker_compose, kubernetes, bare_metal, etc.
}
/**
@@ -189,7 +199,7 @@ const PLATFORM_FILES: Record
- {blueprint.preview}
-
- {/* Overlay */}
- - Full content is locked. Purchase to access. -
- + <> +
+ {blueprint.preview}
+
+ {/* Overlay */}
+ + Full content is locked. Purchase to access. +
+ ++ This template includes variables you can customize after purchase: +
+
@@ -898,7 +918,7 @@ export default function BlueprintDetailPage() {
name: selectedVersion ? `${blueprint.name} (v${selectedVersion})` : blueprint.name,
description: blueprint.description,
content: selectedVersionContent || blueprint.content || "",
- variables: blueprint.variables,
+ variables: Array.isArray(blueprint.variables) ? undefined : blueprint.variables,
sensitiveFields: blueprint.sensitiveFields,
targetPlatform: blueprint.targetPlatform || blueprint.type,
compatibleWith: blueprint.compatibleWith,
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 33494212..6c5a0148 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -3,7 +3,7 @@ import { Inter, JetBrains_Mono } from "next/font/google";
import Script from "next/script";
import { ThemeProvider } from "@/components/providers/theme-provider";
import { SessionProvider } from "@/components/providers/session-provider";
-import { AnalyticsProvider } from "@/components/providers/analytics-provider";
+
import { SentryProvider } from "@/components/providers/sentry-provider";
import { Toaster } from "@/components/ui/sonner";
import { CookieBanner } from "@/components/cookie-banner";
@@ -140,7 +140,7 @@ export default function RootLayout({
disableTransitionOnChange
>
- {children}
+ {children}
diff --git a/src/app/wizard/page.tsx b/src/app/wizard/page.tsx
index 4c45985b..0f9aa0d9 100644
--- a/src/app/wizard/page.tsx
+++ b/src/app/wizard/page.tsx
@@ -283,6 +283,12 @@ const AI_BEHAVIOR_RULES = [
{ id: "run_tests_before_commit", label: "Run Tests Before Commit", description: "Ensure tests pass before committing", recommended: true },
{ id: "follow_existing_patterns", label: "Follow Existing Patterns", description: "Match the codebase's existing style", recommended: true },
{ id: "ask_before_large_refactors", label: "Ask Before Large Refactors", description: "Confirm before significant changes", recommended: true },
+ // Burke Holland-inspired rules
+ { id: "code_for_llms", label: "Code for LLMs", description: "Optimize for LLM reasoning: flat patterns, minimal abstractions" },
+ { id: "self_improving", label: "Self-Improving Config", description: "AI updates this config when it learns project patterns" },
+ { id: "verify_work", label: "Always Verify Work", description: "Run tests and check builds before returning control", recommended: true },
+ { id: "terminal_management", label: "Terminal Management", description: "Reuse existing terminals, close unused ones" },
+ { id: "check_docs_first", label: "Check Docs First", description: "Check docs via MCP before assuming API knowledge" },
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
@@ -684,6 +690,12 @@ type WizardConfig = {
explanationVerbosity: string; // concise, balanced, detailed
accessibilityFocus: boolean;
performanceFocus: boolean;
+ mcpServers: string; // Comma-separated list of MCP servers (e.g., "filesystem, github, postgres")
+ attemptWorkarounds: boolean; // Whether AI should attempt workarounds when stuck
+ serverAccess: boolean; // Whether project requires server login
+ sshKeyPath: string; // Custom SSH key path (empty = default)
+ manualDeployment: boolean; // Whether deployment is manual (no CI/CD)
+ deploymentMethod: string; // portainer, docker_compose, kubernetes, bare_metal
importantFiles: string[];
importantFilesOther: string;
enableAutoUpdate: boolean;
@@ -845,11 +857,17 @@ function WizardPageContent() {
containerRegistryOther: "",
dockerImageNames: "",
registryUsername: "",
- aiBehaviorRules: ["always_debug_after_build", "check_logs_after_build", "run_tests_before_commit", "follow_existing_patterns", "ask_before_large_refactors"],
+ aiBehaviorRules: ["always_debug_after_build", "check_logs_after_build", "run_tests_before_commit", "follow_existing_patterns", "ask_before_large_refactors", "verify_work"],
planModeFrequency: "complex_tasks",
explanationVerbosity: "balanced",
accessibilityFocus: false,
performanceFocus: false,
+ mcpServers: "",
+ attemptWorkarounds: true,
+ serverAccess: false,
+ sshKeyPath: "",
+ manualDeployment: false,
+ deploymentMethod: "",
importantFiles: [],
importantFilesOther: "",
enableAutoUpdate: false,
@@ -1490,6 +1508,12 @@ function WizardPageContent() {
// AI behavior
aiBehaviorRules: config.aiBehaviorRules,
+ mcpServers: config.mcpServers,
+ attemptWorkarounds: config.attemptWorkarounds,
+ serverAccess: config.serverAccess,
+ sshKeyPath: config.sshKeyPath,
+ manualDeployment: config.manualDeployment,
+ deploymentMethod: config.deploymentMethod,
importantFiles: config.importantFiles,
importantFilesOther: config.importantFilesOther,
enableAutoUpdate: config.enableAutoUpdate,
@@ -2732,6 +2756,19 @@ ${syncCommands}
onAccessibilityFocusChange={(v) => setConfig({ ...config, accessibilityFocus: v })}
performanceFocus={config.performanceFocus}
onPerformanceFocusChange={(v) => setConfig({ ...config, performanceFocus: v })}
+ mcpServers={config.mcpServers}
+ onMcpServersChange={(v) => setConfig({ ...config, mcpServers: v })}
+ attemptWorkarounds={config.attemptWorkarounds}
+ onAttemptWorkaroundsChange={(v) => setConfig({ ...config, attemptWorkarounds: v })}
+ serverAccess={config.serverAccess}
+ onServerAccessChange={(v) => setConfig({ ...config, serverAccess: v })}
+ sshKeyPath={config.sshKeyPath}
+ onSshKeyPathChange={(v) => setConfig({ ...config, sshKeyPath: v })}
+ manualDeployment={config.manualDeployment}
+ onManualDeploymentChange={(v) => setConfig({ ...config, manualDeployment: v })}
+ deploymentMethod={config.deploymentMethod}
+ onDeploymentMethodChange={(v) => setConfig({ ...config, deploymentMethod: v })}
+ hasCicd={(config.cicd?.length ?? 0) > 0}
importantFiles={config.importantFiles}
importantFilesOther={config.importantFilesOther}
onImportantFilesToggle={(v) => toggleArrayValue("importantFiles", v)}
@@ -5348,6 +5385,19 @@ function StepAIBehavior({
onAccessibilityFocusChange,
performanceFocus,
onPerformanceFocusChange,
+ mcpServers,
+ onMcpServersChange,
+ attemptWorkarounds,
+ onAttemptWorkaroundsChange,
+ serverAccess,
+ onServerAccessChange,
+ sshKeyPath,
+ onSshKeyPathChange,
+ manualDeployment,
+ onManualDeploymentChange,
+ deploymentMethod,
+ onDeploymentMethodChange,
+ hasCicd,
importantFiles,
importantFilesOther,
onImportantFilesToggle,
@@ -5371,6 +5421,19 @@ function StepAIBehavior({
onAccessibilityFocusChange: (v: boolean) => void;
performanceFocus: boolean;
onPerformanceFocusChange: (v: boolean) => void;
+ mcpServers: string;
+ onMcpServersChange: (v: string) => void;
+ attemptWorkarounds: boolean;
+ onAttemptWorkaroundsChange: (v: boolean) => void;
+ serverAccess: boolean;
+ onServerAccessChange: (v: boolean) => void;
+ sshKeyPath: string;
+ onSshKeyPathChange: (v: string) => void;
+ manualDeployment: boolean;
+ onManualDeploymentChange: (v: boolean) => void;
+ deploymentMethod: string;
+ onDeploymentMethodChange: (v: string) => void;
+ hasCicd: boolean;
importantFiles: string[];
importantFilesOther: string;
onImportantFilesToggle: (v: string) => void;
@@ -5538,6 +5601,84 @@ function StepAIBehavior({
checked={performanceFocus}
onChange={onPerformanceFocusChange}
/>
+
+ + List any Model Context Protocol servers you have configured. The AI will know to use them when relevant. +
+ onMcpServersChange(e.target.value)} + placeholder="e.g. filesystem, github, postgres, docker" + className="mt-2 w-full rounded-md border bg-background px-3 py-2 text-sm" + /> +