> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usechar.com/llms.txt
> Use this file to discover all available pages before exploring further.

# User Scripts

> Write scripts that inject tools into applications

<Note>
  **Private Beta** — [Contact us](mailto:alex@mcp-b.ai?subject=Extension%20User%20Scripts) to get set up.
</Note>

User scripts inject tools into applications you don't control. They run in the context of a page and call `registerTool()` to expose functionality to the [Tool Hub](/explanation/tool-hub).

## The problem

You want to add a tool to a legacy portal. The tool needs to read data from the page, click buttons, fill forms. But you can't modify the application's source code.

## How it works

The [Char Extension](/guides/char-extension) injects scripts into matching pages via Chrome's user scripts API. The script runs in the page context—it can access the DOM, call page functions, interact with the application.

```mermaid theme={null}
graph LR
    subgraph Page
        Script[User Script]
    end

    subgraph Extension
        SW[Service Worker]
    end

    Hub[Tool Hub]

    Script -->|registerTool| SW
    SW <-->|Uplink| Hub
```

When the script calls `registerTool()`, that tool becomes available through the Hub. AI agents can call it like any other tool.

## Org-level scripts

Scripts are defined at the org level. An admin registers a script with domain matching rules. All users in the org get that script injected when visiting matching pages.

This means consistent tooling across your organization. Everyone gets the same tools for the same legacy applications. No per-user configuration.

## `char.config.json` schema (`version: 2`)

User scripts now use explicit script groups with native Chrome URL scoping fields.

```json theme={null}
{
  "version": 2,
  "script_groups": [
    {
      "group_id": "salesforce",
      "name": "Salesforce",
      "tool_prefix": "sf",
      "scope": {
        "match_patterns": ["https://*.my.salesforce.com/*"],
        "exclude_match_patterns": ["https://*.my.salesforce.com/setup/*"],
        "include_globs": ["*lightning*"],
        "all_frames": false,
        "run_at": "document_idle"
      },
      "scripts": [
        {
          "name": "lead_tools",
          "entry": "scripts/salesforce/lead-tools.ts",
          "description": "Lead tools for account pages"
        }
      ]
    }
  ]
}
```

### Scope resolution

* Base scope comes from `group.scope`.
* `script.scope_override` replaces only the fields it defines.
* Effective defaults:
  * `all_frames`: `false`
  * `run_at`: `document_idle`

### Native-first matching

The manifest maps directly to `chrome.userScripts.register`:

* `match_patterns` -> `matches`
* `exclude_match_patterns` -> `excludeMatches`
* `include_globs` -> `includeGlobs`
* `exclude_globs` -> `excludeGlobs`
* `all_frames` -> `allFrames`
* `run_at` -> `runAt`

No custom runtime URL predicate engine is used in v2.

<h3 id="tool-prefix-contract">Tool prefix contract</h3>

Each script gets an effective prefix:

* `group.tool_prefix + "_" + script.tool_prefix` (if script override exists)
* Otherwise `group.tool_prefix + "_" + script.name`

The extension prepends:

`globalThis.__CHAR_TOOL_PREFIX__ = "<effective_prefix>";`

Use that global in your script when naming tools to avoid collisions across sites/groups.

<h2 id="manifest-field-reference">Manifest Field Reference</h2>

This section matches the fields shown in the dashboard User Scripts table.

### Script fields

* `script_name`: Human-readable script name from config.
* `script_id`: Stable identifier (`repo:group:script`) used for sync and dedupe.
* `group_id`: Group key the script belongs to.
* `tool_prefix`: Effective prefix exposed to the runtime (`__CHAR_TOOL_PREFIX__`).

<h3 id="artifact-fields">Artifact Fields (<code>artifact\_url</code>, <code>artifact\_path</code>)</h3>

* `artifact_url`: Resolved source artifact URL (used for fetch and verification).
* `artifact_path`: Normalized repository-relative path used for display and GitHub links.

<h3 id="integrity-fields">Integrity Fields (<code>artifact\_sha256</code>, <code>script\_sha</code>)</h3>

* `artifact_sha256`: SHA-256 hash expected for downloaded artifact contents.
* `script_sha`: Commit SHA associated with the script revision.

<h3 id="sync-status">How Sync Status Is Computed</h3>

Dashboard `Sync Status` compares each `script_sha` to the repository `last_synced_sha`:

* `Current`: `script_sha === last_synced_sha`
* `Pending Sync`: `script_sha !== last_synced_sha`

<h2 id="scope-field-reference">Scope Field Reference</h2>

These fields map directly to native `chrome.userScripts.register` options.

<h3 id="match_patterns"><code>match\_patterns</code></h3>

Primary URL match patterns for script injection. Must be non-empty after scope resolution.

<h3 id="exclude_match_patterns"><code>exclude\_match\_patterns</code></h3>

Match patterns excluded from `match_patterns`.

<h3 id="include_globs"><code>include\_globs</code></h3>

Optional glob filters that further narrow matching URLs.

<h3 id="exclude_globs"><code>exclude\_globs</code></h3>

Optional glob filters that remove URLs after base matching.

<h3 id="all_frames"><code>all\_frames</code></h3>

When `true`, injects into matching iframes in addition to the top frame.

<h3 id="run_at"><code>run\_at</code></h3>

Injection timing:

* `document_start`
* `document_end`
* `document_idle`

## Development workflow

Scripts are developed the same way as regular WebMCP tools—using [Chrome DevTools MCP](/guides/mcp-servers) to iterate in a live browser.

```mermaid theme={null}
graph LR
    Claude[Claude Code] -->|Control browser| DevTools[Chrome DevTools MCP]
    DevTools -->|Test tools| Page[Legacy Portal]
    Page -->|Save script| Org[Org Script]
```

Navigate to the target application. Write `registerTool()` calls. Test them. When they work, save as an org-level script.

## What you get

**Tools where you couldn't have them.** Legacy applications become AI-accessible without source code changes.

**Shared across users.** Define once, deploy to everyone. Consistent tooling, centrally managed.

**Same governance.** Tool calls from injected scripts flow through the same [governance](/guides/governance/index) layer—access control, guardrails, approvals, audit.

## See also

<CardGroup cols={2}>
  <Card title="Char Extension" icon="puzzle" href="/guides/char-extension">
    The extension that runs user scripts
  </Card>

  <Card title="WebMCP Tools" icon="hammer" href="/guides/webmcp-tools">
    Tools in applications you control
  </Card>
</CardGroup>
