Skip to main content

extension

  • The extension source code is located at chrome/browser/resources/vibe
  • The extension is registered as component extension by calling void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages()
  • The extension is whitelisted at bool IsComponentExtensionAllowlisted(int manifest_resource_id)

Vibe Extension Manifest: chrome/browser/resources/vibe/manifest.json Extension main parts: Worker:

  • chrome/browser/resources/vibe/background.js
  • chrome/browser/resources/vibe/ai_agent.js
  • chrome/browser/resources/vibe/ai_tools.extension.js Content injected script: chrome/browser/resources/vibe/content.js Sidepanel and Homepage
  • chrome/browser/resources/vibe/apps/chat2/

Component extension resources/files are declared there: chrome/browser/resources/component_extension_resources.grd

Extension build script that is called from ninja: chrome/browser/resources/vibe/build.py

How the extension is built:

  1. ninja calls node build.js that bundles scripts into 3 scripts: content.js, background.js, sidepanel.js
  2. chromium build system builds the component extensions from files declared at chrome/browser/resources/component_extension_resources.grd, for example

<include name="IDR_VIBE_MANIFEST" file="${root_gen_dir}/chrome/browser/resources/vibe/manifest.json" use_base_dir="false" resource_path="vibe/manifest.json" type="BINDATA" />
...

Files a packed onto component_extension_resources.pak 3. When chromium starts, it loads the component extension from manifest, that is registered at chrome/browser/extensions/component_loader.cc:


Add(IDR_VIBE_MANIFEST,
base::FilePath(FILE_PATH_LITERAL("vibe")));
  1. We use AI agent chat page as a home and sidepanel pages.
  "side_panel": {
"default_path": "chat.html"
},
"chrome_url_overrides": {
"newtab": "chat.html"
},

Settings Integration

The extension integrates with Chrome browser settings through the chrome.settingsPrivate API for manual API key configuration. Users configure API keys through the browser's settings UI at chrome://settings/ai.

Manual API Key Configuration

User Configuration Workflow:

  1. User opens chrome://settings/ai/vibeConfig in browser
  2. User selects provider (OpenAI, Gemini, etc.)
  3. User enters API key in secure input field
  4. Settings are saved to browser preferences
  5. Extension automatically reads updated preferences

Browser Preferences Access

The extension accesses configuration through Chrome's browser preferences system via the chrome.settingsPrivate API.

How the Extension Gets Preferences

  1. Permission Required: The extension manifest includes "settingsPrivate" permission
  2. Direct Preference Access: Extension reads browser preferences directly using chrome.settingsPrivate.getAllPrefs()
  3. Preference Key Filtering: Filters for keys starting with vibe_ai.
  4. No WebUI Messaging: Does NOT use chrome.runtime.sendMessage() to communicate with WebUI pages

Browser Settings Storage

User settings are stored in Chromium preferences defined in vibe_ai_prefs.h/cc:

  • vibe_ai.provider - AI provider selection (openai, gemini, etc.)
  • vibe_ai.model - Model selection (gpt-5-mini, gemini-1.5-flash, etc.)
  • vibe_ai.temperature - Response creativity (0.0-2.0)
  • vibe_ai.max_tokens - Maximum response length
  • vibe_ai.agent_timeout - Request timeout in milliseconds
  • vibe_ai.openai_api_key - OpenAI API key (encrypted storage)
  • vibe_ai.gemini_api_key - Gemini API key (encrypted storage)
  • vibe_ai.openai_configured - Boolean flag for OpenAI configuration
  • vibe_ai.gemini_configured - Boolean flag for Gemini configuration

Settings UI Integration

The browser settings page chrome://settings/ai is handled by VibeAIHandler in chrome/browser/ui/webui/settings/:

  1. Registration: Handler registered in settings_ui.cc
  2. API Methods: Handles getVibeAIState, setVibeAIProvider, setVibeAIApiKey
  3. Manual Configuration: Users enter API keys through secure input fields
  4. Preference Storage: Stores user API keys in encrypted browser preferences
  5. Status Updates: Automatically updates configuration flags when keys are saved

Configuration Architecture

┌─────────────────────┐    ┌──────────────────────┐    ┌─────────────────────┐
│ Settings UI │ │ Browser Preferences │ │ Extension │
│ chrome://settings │◄──►│ (Encrypted) │◄──►│ chrome.settings │
│ │ │ │ │ Private API │
└─────────────────────┘ └──────────────────────┘ └─────────────────────┘

Security Features

  • API keys stored in browser's encrypted preference storage
  • Keys masked in settings UI display (sk-***1234)
  • Extension requires settingsPrivate permission for access
  • No plaintext storage in extension or environment variables

Permissions

Granting Special Privileges to an Internal Extension

Instead of using the standard Chromium extension permissions system (manifest.json), this repository grants special privileges to the AI Side Panel extension by directly modifying the browser's underlying C++ source code.

The browser's code is altered to contain hard-coded exceptions and custom behaviors that are triggered only when it interacts with a specific, known extension ID.

The Key Identifier

The entire mechanism hinges on a unique, hard-coded extension ID defined in the C++ code:

  • Constant: kAISidePanelExtensionId
  • Value: opocihnfjcgcjecjhjjgifkbkgeeoonh

This ID acts as a key. The browser's modified C++ code constantly checks for this ID and changes its behavior accordingly.

The Mechanism: C++ Source Code Patching

The modifications are not made to the original Chromium source directly. Instead, they are stored in .patch files within the patches/nxtscape/ directory. During the build process, these patches are applied to the Chromium source code, injecting the custom logic.

Concrete Examples of Special Privileges

  1. Bypassing API Restrictions

    Normal extensions are subject to strict rules. For example, opening a side panel typically requires a direct user action (like a click). The AI extension bypasses this.

    • File Modified: chrome/browser/extensions/api/side_panel/side_panel_api.cc
    • Patch: disable-user-gesture-restriction-on-sidepanel.patch
    • Change: The C++ code that checks for a user gesture is commented out.

1 // sidePanel.open() requires a user gesture. 2 // if (!user_gesture()) { 3 // return RespondNow( 4 // Error("sidePanel.open() may only be called in " 5 // "response to a user gesture.")); 6 // }

  Result: The AI extension can programmatically open the side panel at any time, a privilege not granted to standard extensions.

2. Custom UI Integration and Behavior

  The browser's UI code is modified to give the AI extension a unique appearance and behavior, treating it as a core part of the

browser rather than a simple add-on.

   - Files Modified: ExtensionSidePanelManager.cc, SidePanelCoordinator.cc, etc.
- Patch: pin-nxtscape-agents-together.patch
- Change: The C++ code contains explicit if statements that check if an extension's ID matches kAISidePanelExtensionId.

1 // in ExtensionSidePanelManager.cc 2 if (browser_ && extension->id() == extension_misc::kAISidePanelExtensionId) { 3 // ... custom logic to automatically pin the extension to the toolbar 4 }

  Result: The AI extension is automatically pinned to the toolbar, can have a text label next to its icon, and is handled by the

"pinned" toolbar's logic instead of the standard extensions container.

Summary

In short, special permissions are not "granted" through a configuration file. They are injected by changing the fundamental C++ logic of the browser itself. This approach allows for deep integration, giving the extension capabilities that are impossible to achieve through the standard, sandboxed extension model.

The Core Concept: From Private Key to Public ID

The extension ID is a hash of the extension's public key. The public key, in turn, is derived from a private key (.pem file) that the developer controls.

This system ensures that the extension ID is unique and that only the developer holding the original private key can update the extension.


The Step-by-Step Generation Process

There are two scenarios for how an ID is created:

  1. Temporary ID (During Development)

When you load an "unpacked" extension (a folder with your code) in Chrome for local development, the browser generates a temporary ID for it.

  • What happens: Chrome creates a temporary key for the extension on the fly.
  • The problem: This ID is not stable. If you load the extension on a different machine or even into a different Chrome profile, it will get a new ID.
  • Conclusion: This method is only for quick testing and is not how the permanent ID opocihnfjcgcjecjhjjgifkbkgeeoonh was created.
  1. Permanent ID (For Production and Integration)

This is the process used to generate the permanent ID that is hard-coded into the browser's C++ source.

  1. Create a Private Key (One-Time Action): The developer first generates a reusable, private RSA key. This is typically done using a command-line tool like openssl. This key is a critical secret and must be kept safe.

1 # This creates a 2048-bit RSA private key and saves it as my-extension-key.pem 2 openssl genrsa -out my-extension-key.pem 2048

  1. Pack the Extension and Generate the .crx file: The developer then packs the extension using the Chrome browser's built-in utility (chrome://extensions > "Pack extension").

    • Extension root directory: They point to the folder containing the extension's code (e.g., resources/files/ai_side_panel/).
    • Private key file: They provide the path to the my-extension-key.pem file they just created.
  2. Chrome Generates the ID: When the "Pack Extension" button is clicked, Chrome performs the following steps internally:

    • It reads the private key (.pem file).
    • It derives the corresponding public key.
    • It calculates a SHA-256 hash of the public key data.
    • It takes the first 16 bytes (128 bits) of that hash.
    • It encodes those 16 bytes into a 32-character string using a special character set (the letters 'a' through 'p').

The result is the permanent, 32-character extension ID. For the AI Side Panel, this process resulted in opocihnfjcgcjecjhjjgifkbkgeeoonh.

Why This Is Critical for This Repository

  • Stability: Because the ID is derived from the private key, as long as the developers use the exact same .pem key every time they package a new version of the AI Side Panel, the extension ID will never change.
  • Integration: This stability is what allows them to hard-code the ID directly into the browser's C++ source code. The custom C++ logic that gives the extension special privileges relies on being able to identify it by this exact, unchanging ID.

If they were to lose the original .pem file, they would be unable to release updates to the extension that could interact with the custom C++ code, as any new key would generate a new ID.

Files

  • ai_page.html and ai_page.ts: These files create the main "AI" section in the settings page. It's a container for various AI-related subpages, including a new entry for "Vibe AI Agent" (vibeAiConfigRowV2). The code is clean and follows the existing structure of the settings page.
  • vibe_ai_config_subpage.html and vibe_ai_config_subpage.ts: This is the core of the new settings UI. * UI (.html): The HTML provides a comprehensive UI for configuring the Vibe AI agent, including a provider dropdown, model selection, API key input, and sliders for temperature, max tokens, and timeout. It also includes buttons for import/export and resetting to defaults. The layout is consistent with the rest of the Chrome settings. * Logic (.ts): The TypeScript file contains the logic for the UI. It defines the available providers and models, handles UI state changes (e.g., showing the API key field only for remote providers), and includes placeholder logic for saving and testing API keys. * No Duplication: The settings seem well-organized. There is no obvious duplication of information. The separation of concerns between the main AI page and the Vibe AI config subpage is good.
  • vibe_ai_handler.h and vibe_ai_handler.cc: This is the C++ backend for the settings page. * Current State: The handler is very basic right now. It only has a placeholder HandleGetVibeAIState function that doesn't do anything. This is expected for a new feature. * Needs Implementation: This handler will need to be significantly expanded to handle the logic for saving and retrieving settings, testing API keys, and communicating with the Vibe AI service.

NOTE: The extension is built as a component extension through the ninja build system. Files in /chrome/browser/resources/vibe/ are automatically included in the build. Do NOT use node esbuild.js - this creates an incorrect dist/ directory that should be deleted.