Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Chromex Ai Chrome Assistant

ASecurity

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. Chromex is a Chrome MV3 side-panel extension that bridges the browser to OpenAI Codex through a local native messaging host. It supports chat with page content, selected tabs, uploaded files (PDF, DOCX, XLSX, images), voice transcription, live voice mode, screenshot workflows, and browser-control via content scripts — all without storing credentials in extension storage. ---

81 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmenttypescriptgoshellbashreactnodegitapisecurity

Works with

cliapi

Security Analysis

A96/100
mediumInstalls packages at runtime which could introduce malicious dependencies

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add reason-machines/trending-skills --skill chromex-ai-chrome-assistant --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Chromex Ai Chrome Assistant?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Chromex Ai Chrome Assistant
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/reason-machines-chromex-ai-chrome-assistant/badge)](https://www.skillsdirectory.com/skills/reason-machines-chromex-ai-chrome-assistant)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
```markdown
---
name: chromex-ai-chrome-assistant
description: Chromex is a Chrome MV3 side-panel assistant that connects Chrome to OpenAI Codex through a local native bridge, enabling page context, tab, voice, image, and browser-control workflows.
triggers:
  - set up chromex chrome extension
  - add chromex side panel assistant
  - connect codex to chrome extension
  - build chrome side panel with codex
  - chromex native bridge setup
  - install chromex local bridge
  - chromex page context workflow
  - chromex voice image tab assistant
---

# Chromex AI Chrome Assistant

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

Chromex is a Chrome MV3 side-panel extension that bridges the browser to OpenAI Codex through a local native messaging host. It supports chat with page content, selected tabs, uploaded files (PDF, DOCX, XLSX, images), voice transcription, live voice mode, screenshot workflows, and browser-control via content scripts — all without storing credentials in extension storage.

---

## Architecture

```
Chrome Extension (MV3 Side Panel)
  └─> Native Messaging Host  (packages/native-host)
        └─> Local Bridge Daemon  (packages/bridge)
              └─> codex app-server  (OpenAI Codex CLI)
```

**Packages:**

| Package | Purpose |
|---|---|
| `packages/extension` | Chrome MV3 side-panel UI (TypeScript + React) |
| `packages/bridge` | Local bridge daemon: Codex app-server, multimodal workflows |
| `packages/native-host` | Chrome Native Messaging relay process |
| `packages/shared` | Shared types, policies, profiles, helpers |

---

## Prerequisites

- Node.js 20 LTS or newer
- Google Chrome (stable or dev)
- OpenAI Codex CLI: `npm install -g @openai/codex`
- Verify: `codex --version`

---

## Install & Build

### Clone and Build

```bash
git clone https://github.com/GENEXIS-AI/chromex.git
cd chromex
npm install
npm run build
```

### Install the Native Messaging Host

```bash
# macOS / Linux
node scripts/install-native-host.mjs

# Windows (PowerShell)
node scripts/install-native-host.mjs --browser=chrome
```

If Chrome assigns a non-standard extension ID, pass it explicitly:

```bash
node scripts/install-native-host.mjs <extension-id> --browser=chrome
```

The expected public release extension ID is `menmlhahmendmkiicbjihgjhppkgaeom`.

### Load Extension in Chrome

1. Open `chrome://extensions`
2. Enable **Developer mode**
3. Click **Load unpacked**
4. Select `packages/extension/dist`

---

## Key CLI / NPM Commands

```bash
npm run build              # Build all packages
npm run typecheck          # TypeScript type-check all packages
npm run test               # Run unit tests
npm run release:audit      # Pre-release audit checks
npm run smoke              # Browser smoke test (Playwright)
npm run smoke:install-browser  # Install Playwright Chromium runtime
```

---

## Configuration

### Windows: Codex Binary Path

If `codex` is not found on PATH, set the executable path in Chromex Settings:

- **Codex binary path:** `%APPDATA%\npm\codex.cmd`
- **Codex binary folder:** `%APPDATA%\npm`

> Do not put your workspace folder in the Codex binary field. The workspace folder and executable path are separate settings.

### App UI Language

Chromex auto-detects the browser language. To override:
**Settings → General → App UI language**

Supported locales include: `en`, `ko`, `ja`, `zh-CN`, `ar`, `fr`, `de`, `es`, `pt`, `hi`, `vi`, `th`, `tr`, `uk`, and more.

### Chat History

Conversation history is **session-only by default**. Enable persistent local chat history in:
**Settings → Privacy → Persistent local chat history**

---

## Extension Package Structure

```
packages/extension/
├── src/
│   ├── background/          # Service worker, native messaging client
│   ├── sidepanel/           # React side-panel UI
│   │   ├── components/      # Chat, attachments, pickers, markdown
│   │   ├── hooks/           # Page context, voice, tab selection
│   │   └── pages/           # Main panel, onboarding, settings
│   ├── content/             # Content scripts for page context & browser control
│   └── shared/              # Extension-local shared utilities
├── manifest.json
└── dist/                    # Built output (load this in Chrome)
```

---

## Real Code Examples

### 1. Sending a Message to the Bridge (Native Messaging)

```typescript
// packages/extension/src/background/nativeClient.ts

interface BridgeMessage {
  type: string;
  payload: unknown;
  requestId: string;
}

class NativeClient {
  private port: chrome.runtime.Port | null = null;

  connect(): void {
    this.port = chrome.runtime.connectNative("com.genexisai.chromex.bridge");
    this.port.onMessage.addListener((msg) => this.handleMessage(msg));
    this.port.onDisconnect.addListener(() => {
      this.port = null;
      console.warn("Native host disconnected", chrome.runtime.lastError);
    });
  }

  send(message: BridgeMessage): void {
    if (!this.port) this.connect();
    this.port!.postMessage(message);
  }

  private handleMessage(msg: unknown): void {
    // Dispatch to side panel via chrome.runtime.sendMessage
    chrome.runtime.sendMessage({ source: "native", data: msg });
  }
}

export const nativeClient = new NativeClient();
```

### 2. Reading Page Context from a Content Script

```typescript
// packages/extension/src/content/pageContext.ts

export interface PageContext {
  url: string;
  title: string;
  textContent: string;
  selectedText: string;
  metaDescription: string;
}

export function extractPageContext(): PageContext {
  const selectedText = window.getSelection()?.toString() ?? "";

  return {
    url: location.href,
    title: document.title,
    textContent: document.body.innerText.slice(0, 20000), // truncate for context window
    selectedText,
    metaDescription:
      document
        .querySelector('meta[name="description"]')
        ?.getAttribute("content") ?? "",
  };
}

// Listen for context requests from the background service worker
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
  if (msg.type === "GET_PAGE_CONTEXT") {
    sendResponse(extractPageContext());
  }
  return true; // keep channel open for async
});
```

### 3. Requesting Page Context from the Background

```typescript
// packages/extension/src/background/contextBridge.ts

export async function getActiveTabContext(): Promise<PageContext | null> {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  if (!tab?.id) return null;

  try {
    const context = await chrome.tabs.sendMessage(tab.id, {
      type: "GET_PAGE_CONTEXT",
    });
    return context as PageContext;
  } catch {
    // Content script not injected yet — inject it
    await chrome.scripting.executeScript({
      target: { tabId: tab.id },
      files: ["content/pageContext.js"],
    });
    return chrome.tabs.sendMessage(tab.id, { type: "GET_PAGE_CONTEXT" });
  }
}
```

### 4. Tab Picker — Selecting Multiple Tabs

```typescript
// packages/extension/src/sidepanel/hooks/useTabPicker.ts
import { useState, useEffect } from "react";

export interface TabItem {
  id: number;
  title: string;
  url: string;
  favIconUrl?: string;
}

export function useTabPicker() {
  const [tabs, setTabs] = useState<TabItem[]>([]);
  const [selected, setSelected] = useState<Set<number>>(new Set());

  useEffect(() => {
    chrome.tabs.query({ currentWindow: true }, (chromeTabs) => {
      setTabs(
        chromeTabs
          .filter((t) => t.id !== undefined)
          .map((t) => ({
            id: t.id!,
            title: t.title ?? "",
            url: t.url ?? "",
            favIconUrl: t.favIconUrl,
          }))
      );
    });
  }, []);

  const toggle = (id: number) =>
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });

  return { tabs, selected, toggle };
}
```

### 5. Bridge Daemon — Starting the Codex App-Server

```typescript
// packages/bridge/src/codexServer.ts
import { spawn, ChildProcess } from "child_process";
import path from "path";

export interface CodexServerConfig {
  codexBin: string;       // e.g. "codex" or full path
  workspaceDir: string;   // user workspace directory
  port: number;
}

export class CodexAppServer {
  private proc: ChildProcess | null = null;

  start(config: CodexServerConfig): Promise<void> {
    return new Promise((resolve, reject) => {
      this.proc = spawn(
        config.codexBin,
        ["app-server", "--port", String(config.port)],
        {
          cwd: config.workspaceDir,
          env: {
            // Reduced environment allowlist — never pass full process.env
            PATH: process.env.PATH ?? "",
            HOME: process.env.HOME ?? "",
            USERPROFILE: process.env.USERPROFILE ?? "",
            OPENAI_API_KEY: process.env.OPENAI_API_KEY ?? "", // optional local fallback
          },
          stdio: ["pipe", "pipe", "pipe"],
        }
      );

      this.proc.stdout?.once("data", () => resolve());
      this.proc.on("error", reject);
      this.proc.stderr?.on("data", (d) =>
        console.error("[codex-server]", d.toString())
      );
    });
  }

  stop(): void {
    this.proc?.kill();
    this.proc = null;
  }
}
```

### 6. Shared Types — Chat Message

```typescript
// packages/shared/src/types/chat.ts

export type Role = "user" | "assistant" | "system";

export type AttachmentType =
  | "image"
  | "pdf"
  | "docx"
  | "xlsx"
  | "csv"
  | "text"
  | "screenshot";

export interface Attachment {
  type: AttachmentType;
  name: string;
  dataUrl?: string;      // base64 data URI for images/screenshots
  textContent?: string;  // extracted text for documents
  mimeType: string;
}

export interface ChatMessage {
  id: string;
  role: Role;
  content: string;
  attachments?: Attachment[];
  timestamp: number;
  pageContext?: {
    url: string;
    title: string;
  };
}
```

### 7. Profile Selection with `/` Picker

```typescript
// packages/shared/src/profiles/types.ts

export interface CodexProfile {
  id: string;
  name: string;
  systemPrompt: string;
  model: string;
  temperature?: number;
  skillsEnabled: boolean;
  skillPaths?: string[]; // paths to .codex/skills/*/SKILL.md
}

// packages/extension/src/sidepanel/hooks/useProfilePicker.ts
import { useState } from "react";
import type { CodexProfile } from "@chromex/shared/profiles/types";

export function useProfilePicker(profiles: CodexProfile[]) {
  const [active, setActive] = useState<CodexProfile>(profiles[0]);
  const [open, setOpen] = useState(false);

  const select = (id: string) => {
    const found = profiles.find((p) => p.id === id);
    if (found) setActive(found);
    setOpen(false);
  };

  return { active, open, setOpen, select };
}
```

### 8. Native Host Manifest (auto-generated by install script)

```json
{
  "name": "com.genexisai.chromex.bridge",
  "description": "Chromex local bridge native messaging host",
  "path": "/absolute/path/to/packages/native-host/dist/host.js",
  "type": "stdio",
  "allowed_origins": [
    "chrome-extension://menmlhahmendmkiicbjihgjhppkgaeom/"
  ]
}
```

On **macOS/Linux**, this file is placed at:
- `~/Library/Application Support/Google/Chrome/NativeMessagingHosts/` (macOS)
- `~/.config/google-chrome/NativeMessagingHosts/` (Linux)

On **Windows**, the path is written to the registry:
`HKCU\Software\Google\Chrome\NativeMessagingHosts\com.genexisai.chromex.bridge`

---

## Common Patterns

### Pattern: Page-Aware Chat Request

```typescript
// In the side-panel, combine page context with user message
async function sendPageAwareMessage(userText: string) {
  const context = await chrome.runtime.sendMessage({ type: "GET_PAGE_CONTEXT" });

  const payload = {
    type: "CHAT",
    messages: [
      {
        role: "system",
        content: `Current page: ${context.title} (${context.url})\n\n${context.textContent}`,
      },
      { role: "user", content: userText },
    ],
  };

  chrome.runtime.sendMessage({ type: "BRIDGE_SEND", payload });
}
```

### Pattern: Screenshot Attachment

```typescript
async function captureAndAttach(): Promise<Attachment> {
  const dataUrl = await chrome.tabs.captureVisibleTab({ format: "png" });
  return {
    type: "screenshot",
    name: "screenshot.png",
    dataUrl,
    mimeType: "image/png",
  };
}
```

### Pattern: YouTube Adapter — Timestamp Context

```typescript
// packages/extension/src/content/adapters/youtube.ts
export function getYouTubeContext() {
  const video = document.querySelector<HTMLVideoElement>("video");
  const title =
    document.querySelector("h1.ytd-video-primary-info-renderer")?.textContent ??
    document.title;

  return {
    site: "youtube",
    videoTitle: title.trim(),
    currentTime: video ? Math.floor(video.currentTime) : null,
    duration: video ? Math.floor(video.duration) : null,
    url: location.href,
  };
}

export function seekTo(seconds: number): void {
  const video = document.querySelector<HTMLVideoElement>("video");
  if (video) video.currentTime = seconds;
}
```

---

## Troubleshooting

| Problem | Fix |
|---|---|
| **Native host missing or forbidden** | Run `npm run build`, then `node scripts/install-native-host.mjs --browser=chrome`, reload extension in `chrome://extensions` |
| **Different extension ID** | Run `node scripts/install-native-host.mjs <your-extension-id> --browser=chrome` |
| **`Failed to start codex app-server`** | Run `codex --version`. On Windows, set Codex binary path to `%APPDATA%\npm\codex.cmd` in Chromex Settings |
| **Model list does not load** | Confirm native bridge is connected, then sign in through app-server login flow |
| **Page context unavailable** | Open Chromex from the target tab, approve the Chrome site permission prompt |
| **Old UI still showing** | Run `npm run build`, reload the extension card in `chrome://extensions` |
| **Smoke test fails: no browser** | Run `npm run smoke:install-browser`, then `npm run smoke` |
| **Windows: codex not found on PATH** | Set Codex binary folder to `%APPDATA%\npm` in Chromex Settings |

---

## Security Notes

- **Never** store raw `OPENAI_API_KEY` in Chrome extension storage or `manifest.json`.
- Credentials flow through the local Codex app-server OAuth/login, not extension storage.
- API-key login is an optional local fallback only, never automatic.
- Native-host child processes run with a **reduced environment allowlist** (see `CodexAppServer` example above).
- Page content, microphone input, and history are only accessed for user-requested workflows.
- Read [`SECURITY.md`](https://github.com/GENEXIS-AI/chromex/blob/main/SECURITY.md) and [`PRIVACY.md`](https://github.com/GENEXIS-AI/chromex/blob/main/PRIVACY.md) before deploying modified builds.

---

## Release & Contributing

- Versioning and PR flow: [`RELEASE.md`](https://github.com/GENEXIS-AI/chromex/blob/main/RELEASE.md)
- Pre-release check: `npm run release:audit`
- License: MIT
- Built extension output: `packages/extension/dist`
```

Attribution

reason-machinesreason-machines
View sourceMore from reason-machines →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →