Skip to main content
Viber’s surgical edit system makes precise changes to existing code while preserving all unmodified content. Unlike regenerating entire files, surgical edits update only what’s necessary.

How surgical edits work

Surgical editing is enabled by Viber’s component-based architecture combined with context-aware AI prompting:
1

User requests edit

User says: “Make the header background blue”
2

Identify target files

Viber determines which file(s) need editing:
  • “header” → src/components/Header.tsx
  • “hero” → src/components/Hero.tsx
  • “footer” → src/components/Footer.tsx
3

Read current content

Viber reads the current file contents from the sandbox:
const fileContents = await getSandboxFileContents([
  "src/components/Header.tsx"
], sandboxId);
4

Generate with context

AI receives the edit prompt PLUS current file contents:
const systemPrompt = buildSystemPrompt(true, fileContents);
5

AI makes surgical change

AI outputs the COMPLETE file with ONLY the requested change:
<file path="src/components/Header.tsx">
// Same imports
// Same structure
// Changed: bg-gray-900 → bg-blue-500
// Everything else preserved
</file>
6

Apply to sandbox

Updated file overwrites the old version, HMR updates preview instantly.

Component-based architecture

Surgical edits rely on breaking apps into separate component files:
// src/App.tsx
import Header from "./components/Header";
import Hero from "./components/Hero";
import Features from "./components/Features";

function App() {
  return (
    <div>
      <Header />
      <Hero />
      <Features />
    </div>
  );
}
Why modular? If header is in Header.tsx, editing the header only touches that one file. If everything is in App.tsx, editing the header requires regenerating the entire app.

Edit mode prompt

The AI receives special instructions for surgical editing:
src/lib/ai/prompts.ts
KEY PRINCIPLES (CRITICAL):
1. **Minimal Changes**: Only modify what's necessary - preserve 99% of existing code
2. **Preserve Functionality**: Keep all existing features, imports, and structure
3. **Respect Structure**: Follow existing patterns and code style
4. **Target Precision**: Edit specific files/components, not everything
5. **Context Awareness**: Use imports/exports to understand component relationships

EDIT STRATEGY EXAMPLES:

### Example 1: Update Single Style (CRITICAL)
USER: "update the hero to bg blue"

CORRECT APPROACH:
1. Identify Hero component: src/components/Hero.tsx
2. Locate the background color class (e.g., 'bg-gray-900')
3. Replace ONLY that class with 'bg-blue-500'
4. Return the ENTIRE file unchanged except for that single class

INCORRECT APPROACH:
- Regenerating entire file
- Changing other styles
- Reformatting or "improving" code
- Modifying unrelated components
The prompt explicitly shows the AI what NOT to do, preventing over-eager “improvements” that break existing code.

File context injection

Viber injects current file contents into the AI prompt:
src/lib/ai/prompts.ts
export function buildSystemPrompt(
  isEdit: boolean,
  fileContext?: Record<string, string>
): string {
  let prompt = isEdit ? EDIT_MODE_PROMPT : INITIAL_GENERATION_PROMPT;
  
  if (fileContext && Object.keys(fileContext).length > 0) {
    prompt += FILE_CONTEXT_PROMPT;
    for (const [path, content] of Object.entries(fileContext)) {
      if (content.length < 5000) {
        prompt += `\n<file path="${path}">\n${content}\n</file>\n`;
      } else {
        prompt += `\n<file path="${path}">[File too large - ${content.length} chars]</file>\n`;
      }
    }
  }
  
  return prompt;
}
This gives the AI:
  • The exact current state of each file
  • All imports and dependencies
  • Existing code structure and style
  • Context about what should NOT change

Edit examples

Example 1: Style change

“Make the header background blue”

Example 2: Add element

“Add a search bar to the header”

Example 3: Remove element

“Remove the menu button from the header”

File identification

Viber maps user intent to specific files:

header

src/components/Header.tsx

navigation / nav

src/components/Nav.tsx or Header.tsx

hero

src/components/Hero.tsx

footer

src/components/Footer.tsx

features

src/components/Features.tsx

testimonials

src/components/Testimonials.tsx

about

src/components/About.tsx

global styles

src/index.css
If the file doesn’t exist (e.g., no Testimonials.tsx), the AI may create it or suggest it can’t find the component.

Reading sandbox files

Before editing, Viber fetches current file contents:
// In generation flow
if (isEdit && sandboxId) {
  const fileList = await getSandboxFileList(sandboxId);
  
  // Read all .tsx and .ts files for context
  const relevantFiles = fileList.filter(f => 
    f.endsWith(".tsx") || f.endsWith(".ts")
  );
  
  const fileContext = await getSandboxFileContents(
    relevantFiles,
    sandboxId
  );
  
  // Pass to AI
  await generateCode({
    prompt,
    isEdit: true,
    fileContext: fileContext.files,
  });
}
This ensures the AI sees the current state before making changes.

Preserving imports

One critical aspect of surgical edits is import hygiene:
// Before
import { Menu } from "lucide-react";

// After (added Search icon)
import { Menu, Search } from "lucide-react";
Viber’s prompts explicitly remind the AI: “IMPORT HYGIENE: When adding new elements, add corresponding imports at the top.”

Multi-file edits

Some edits require changing multiple files:
User: “Add a newsletter signup to the footer”AI outputs:
<file path="src/components/Newsletter.tsx">
// New component
export default function Newsletter() {
  return (
    <div className="bg-gray-100 p-6 rounded-lg">
      <h3 className="text-xl font-bold mb-2">Subscribe to our newsletter</h3>
      <input type="email" placeholder="Your email" />
      <button>Subscribe</button>
    </div>
  );
}
</file>

<file path="src/components/Footer.tsx">
import Newsletter from "./Newsletter";

// ... existing Footer code ...
// Added Newsletter component inside Footer
</file>
Result: Newsletter.tsx created, Footer.tsx updated to import and render it.

Edge cases

If user asks to edit a file that doesn’t exist:
User: "Update the pricing section"
If Pricing.tsx doesn’t exist, AI may:
  • Create it from scratch
  • Explain it doesn’t exist
  • Ask for clarification
If the request is unclear:
User: "Change the color"
AI may:
  • Ask which component
  • Ask which color (text, background, border)
  • Make a best guess based on recent context
If the request requires major changes:
User: "Rebuild the entire header with a new design"
This becomes a full regeneration, not a surgical edit. The AI recreates Header.tsx from scratch.

Limitations

File size limits: Files larger than 5000 characters are truncated when passed to the AI. For very large files, surgical edits may not have full context.
Token limits: If the project has many files, not all can fit in the context window. Viber prioritizes relevant files based on the edit request.
Complexity: Very complex edits (e.g., “Refactor to use a different state management library”) may require manual intervention.

Best practices

Be specific

“Make the header background blue” is better than “Change the header.”

Reference components

Use component names: “Edit the Hero” instead of “Change the top section.”

One change at a time

“Make the header blue, add a search bar, and remove the logo” is harder than 3 separate requests.

Check the preview

After each edit, verify the change looks correct before the next edit.

Use voice naturally

Voice interaction handles context better. Say: “Now make it darker” after “Make the header blue.”

Modular structure

Keep components small and focused. Easier to edit Hero.tsx than a 500-line App.tsx.

Debugging failed edits

If an edit doesn’t work as expected:
1

Check the code view

Look at the generated code to see what actually changed.
2

Look for console errors

Open browser DevTools to check for import errors or runtime errors.
3

Try a more specific prompt

Rephrase: “Change the background of the header to blue-600” instead of “Make it blue.”
4

Regenerate if needed

Say: “Rebuild the header component” to start fresh.

Comparing to full regeneration

Pros:
  • Fast (only edits one file)
  • Preserves all unchanged code
  • Maintains user customizations
  • Less prone to introducing bugs
Cons:
  • May not handle large refactors well
  • Requires good component modularity
Viber defaults to surgical edits whenever possible. Say “start over” or “rebuild everything” to force full regeneration.

Build docs developers (and LLMs) love