Bolt.new

repository·main·Indexed 12 days ago

https://github.com/stackblitz/bolt.new

An AI-powered, browser-based full-stack development agent that uses StackBlitz WebContainers to run Node.js environments. It allows users to build, run, edit, and deploy applications through natural language prompts with direct control over the filesystem, package managers, and terminal.

Tokens
8.6K
Snippets
31
Records
39
Agent score
97%

What's inside Bolt.new

  1. Overview of Bolt.new

    main
    Bolt.new is an AI-powered web development agent that enables users to prompt, run, edit, and deploy full-stack applications directly within a browser environment. It eliminates the need for local setup by integrating AI models with StackBlitz's WebContainers, providing a complete development lifecycle from initial scaffolding to production deployment.
  2. How Bolt.new manages the development environment

    main

    Unlike standard AI code assistants, Bolt.new provides AI models with complete control over the development environment. This includes direct interaction with:

    • Filesystem: Creating and editing files.
    • Node.js Servers: Running backend processes.
    • Package Manager: Installing npm tools and libraries (e.g., Vite, Next.js).
    • Terminal: Executing commands.
    • Browser Console: Monitoring and interacting with the runtime.

    This architecture allows the AI to handle the entire application lifecycle, including interacting with third-party APIs and deploying to production via chat.

  3. Best practices for prompting in Bolt.new

    main

    To get the most effective results from the AI agent, follow these prompting strategies:

    • Specify your stack: Explicitly mention preferred frameworks or libraries (e.g., Astro, Tailwind, ShadCN) in your initial prompt to ensure correct scaffolding.
    • Scaffold in stages: Build the basic application structure first before requesting advanced features. This ensures the foundation is correctly wired before complexity increases.
    • Batch instructions: Combine multiple simple tasks into a single message (e.g., "change the color scheme, add mobile responsiveness, and restart the dev server") to save time and reduce API credit consumption.
    • Use the 'enhance' icon: Click the enhance icon before sending a prompt to let the AI help refine and optimize your instructions.
  4. Manage workbench state with WorkbenchStore

    main

    WorkbenchStore is the central state management class for the Bolt.new workbench. It orchestrates the state for files, the code editor, terminal, previews, and AI-generated artifacts. It uses nanostores for reactive state management.

    Key responsibilities include:

    • File Management: Saving, resetting, and tracking unsaved files.
    • Editor State: Managing the current document, selected file, and scroll positions.
    • Terminal Control: Toggling visibility and attaching terminal instances.
    • Artifact Management: Handling AI-generated artifacts and their associated ActionRunner instances.
    • View Control: Managing whether the workbench is visible and switching between code and preview views.
    import { workbenchStore } from '~/lib/stores/workbench';
    
    // Example: Saving the current document
    await workbenchStore.saveCurrentDocument();
    
    // Example: Switching to preview view
    workbenchStore.currentView.set('preview');
    
    // Example: Checking for unsaved files
    const unsaved = workbenchStore.unsavedFiles.get();
    console.log(`You have ${unsaved.size} unsaved files.`);
  5. How StreamingMessageParser handles streaming text

    main

    The StreamingMessageParser is designed for incremental processing. It maintains a MessageState for every unique messageId provided to the .parse() method.

    Internal State Management

    • Position Tracking: The parser tracks the last processed character index (position) to ensure it doesn't re-process text or miss partial tags across chunks.
    • Nesting Logic: It tracks whether the parser is currently insideArtifact or insideAction to correctly handle nested tags.
    • Output Generation: The .parse() method returns a string containing the text that is not part of a tag. If an artifactElement factory is provided, the <boltArtifact> tags are replaced in the output with the string returned by that factory.

    Workflow

    1. Chunk 1: ... <boltArtifact id="a" title="t"> ...
      • onArtifactOpen is triggered.
      • Output contains the artifactElement placeholder.
    2. Chunk 2: ... <boltAction type="shell"> ...
      • onActionOpen is triggered.
    3. Chunk 3: ... </boltAction> </boltArtifact>
      • onActionClose and onArtifactClose are triggered.
    4. Chunk 4: ...
      • Parser returns the remaining text normally.
  6. Manage filesystem state with FilesStore

    main

    The FilesStore class manages the state of files and folders within a WebContainer environment. It synchronizes the in-memory file map with the actual filesystem using a path watcher.

    Key features include:

    • Reactive State: Uses nanostores to provide a files MapStore that can be subscribed to for UI updates.
    • File Tracking: Tracks file modifications to compute diffs, which is useful for informing AI models of changes.
    • Binary Detection: Automatically detects if a file is binary to prevent attempting to render or edit non-text content in the editor.

    Data Structures:

    • File: { type: 'file', content: string, isBinary: boolean }
    • Folder: { type: 'folder' }
    • FileMap: A record mapping file paths (strings) to File | Folder | undefined.
    import { FilesStore } from '~/lib/stores/files';
    
    // Initialize with a WebContainer promise
    const filesStore = new FilesStore(webcontainerPromise);
    
    // Access the reactive file map
    filesStore.files.listen((fileMap) => {
      console.log('Files updated:', fileMap);
    });
  7. Configure StreamingMessageParserOptions

    main

    When instantiating StreamingMessageParser, you can provide a StreamingMessageParserOptions object to control callback behavior and UI rendering.

    Options

    • callbacks?: ParserCallbacks: An object containing lifecycle hooks:
      • onArtifactOpen?: (data: ArtifactCallbackData) => void
      • onArtifactClose?: (data: ArtifactCallbackData) => void
      • onActionOpen?: (data: ActionCallbackData) => void
      • onActionClose?: (data: ActionCallbackData) => void
    • artifactElement?: ElementFactory: A function used to generate a string representation of the artifact placeholder in the returned text. It receives { messageId: string } as an argument.

    Callback Data Shapes

    ArtifactCallbackData

    {
      id: string;
      title: string;
      messageId: string;
    }

    ActionCallbackData

    {
      artifactId: string;
      messageId: string;
      actionId: string;
      action: BoltAction; // Can be FileAction or ShellAction
    }
  8. Disable chat persistence via environment variable

    main

    Chat persistence can be globally disabled by setting the VITE_DISABLE_PERSISTENCE environment variable. When this variable is present, the database will not be opened, and useChatHistory will treat the session as non-persistent, showing a toast error if persistence was expected.

    # To disable persistence, ensure this env var is set in your environment
    VITE_DISABLE_PERSISTENCE=true
  9. Configure UnoCSS for Bolt.new

    main

    The project uses UnoCSS for styling. The configuration includes custom presets for icons, theme-aware dark mode, and a comprehensive set of design tokens (colors, shortcuts, and rules).

    Key configuration features:

    • Presets: Uses presetUno with dark mode support via [data-theme="light/dark"] and presetIcons for icon management.
    • Custom Icons: Icons are loaded from the ./icons/*.svg directory and registered under the bolt collection.
    • Transformers: Includes transformerDirectives() to support @apply and other CSS directives.
    • Theme Tokens: Extensive use of CSS variables (e.g., var(--bolt-elements-...)) for theme-aware components like buttons, sidebars, and terminals.
    import { defineConfig, presetIcons, presetUno, transformerDirectives } from 'unocss';
    
    export default defineConfig({
      presets: [
        presetUno({
          dark: {
            light: '[data-theme="light"]',
            dark: '[data-theme="dark"]',
          },
        }),
        presetIcons({
          warn: true,
          collections: {
            // custom collections
          },
        }),
      ],
      transformers: [transformerDirectives()],
    });
  10. Configure ESLint with @blitz/eslint-plugin

    main

    The project uses @blitz/eslint-plugin to provide recommended linting configurations. You can extend the recommended ruleset and apply specific overrides for TypeScript and React files. The configuration also enforces a project-wide rule against relative imports (e.g., ../), requiring the use of the ~/ alias instead.

    import blitzPlugin from '@blitz/eslint-plugin';
    
    export default [
      ...blitzPlugin.configs.recommended(),
      // Add custom rules or overrides below
    ];
  11. Retrieve specific chat messages with getMessages()

    main

    The getMessages(db, id) function attempts to find a chat session using two fallback strategies:

    1. It first tries to find the record by its primary id using getMessagesById.
    2. If not found, it attempts to find the record by its urlId using getMessagesByUrlId.

    Returns a ChatHistoryItem if a match is found, otherwise returns undefined.

    import { getMessages } from '~/lib/persistence/db';
    
    const chat = await getMessages(db, 'some-id-or-url-id');
    if (chat) {
      console.log(chat.messages);
    }