---
name: kiteghost-setup
description: Set up KiteGhost on this machine so an agent can drive the user's own Chrome — installs the native host, pairs the machine with their account, points the agent's client at the MCP server, and verifies it works. Covers a brand-new account, an existing account, and the one step a script cannot do. Fetch this document from https://kiteghost.lbframe.com/SKILL.md — it is always current for the deployed service.
---

# KiteGhost — set up a machine

KiteGhost lets an agent drive the user's real Chrome profile: open tabs, read
pages as an accessibility tree, click, type, screenshot. The extension never
listens on the network — a native host dials out.

**You are expected to run this yourself.** Only one step needs the human, and it
is stated below. Once you are done, driving the browser happens through the MCP
tools, which carry their own instructions.

## 1. Ask the human two things, then install

You need an email address, and whether they already have a KiteGhost account.

⚠️ **Never run the bare form yourself.**

```
curl -fsSL https://kiteghost.lbframe.com/install.sh | sh      # human at a terminal only
```

With no `--email` it asks on `/dev/tty`. You have no `/dev/tty`, so no session is
established, and the script falls back to waiting for a browser confirmation that
will never come — it hangs until the pairing code expires, about 15 minutes.
**Always pass `--email`.** Give the bare form to the human only if they prefer to
type things themselves.

**New account** — the installer creates it and prints a generated password. Tell
the human to save it:

```
curl -fsSL https://kiteghost.lbframe.com/install.sh | sh -s -- --email THEM@example.com
```

**Existing account** — pass the password so no browser step is needed:

```
curl -fsSL https://kiteghost.lbframe.com/install.sh | sh -s -- \
  --email THEM@example.com --password 'THEIR_PASSWORD'
```

Both are non-interactive and safe to run from a tool call. The installer
downloads the native host, registers it with Chrome/Chromium/Brave, signs the
user in (or up), pairs this machine automatically, registers OAuth clients for
the machine and the agent, and unpacks the extension.

**Name the machine and the agent.** These names are what the human sees on
`/devices`, so propose something meaningful rather than accepting the default:

```
… --label 'Marie's MacBook' --agent-label 'agent-marie'
```

Without them the installer suggests the hostname (and `agent-<hostname>`), and
uses that suggestion silently when there is no terminal to ask on — which is your
case. Names are capped at 32 characters.

If it prints `Bridge injoignable`, the service is unreachable — stop and report
it. If it falls back to asking for a browser confirmation, the session could not
be established: check the password.

## 2. The one step you cannot do

Chrome forbids scripted installation of unpacked extensions. Ask the human to:

1. open `chrome://extensions`
2. enable **Developer mode** (top right)
3. click **Load unpacked** and select `~/.kiteghost/extension`

The extension id must be `ohbidhpignbjbeppgkabalefifphenpi`. The toolbar badge
turns green once the machine is connected. Do not try to automate this — there is
no supported path, and attempts to fake it will not work.

## 3. Point the client at the MCP server

Two ways in. Prefer the hosted URL when the agent client speaks OAuth and you
do not want Node on the machine. Prefer the npm package when the installer
already ran on this machine and a local `npx` is fine.

### Hosted (URL + OAuth) — no Node required

Give the client this URL:

```
https://kiteghost.lbframe.com/mcp
```

The client opens a browser, you sign in to KiteGhost and consent, and it
receives a bearer token. Nothing to paste. Config key must still be
`kiteghost` so tool names match the server's instructions.

Example (Cursor / Claude Code style):

```json
{
  "mcpServers": {
    "kiteghost": {
      "url": "https://kiteghost.lbframe.com/mcp"
    }
  }
}
```

Codex speaks TOML, not JSON — the file is `~/.codex/config.toml` and the root
key is `mcp_servers` with an underscore (pasting a `mcpServers` JSON block
there silently does nothing):

```toml
[mcp_servers.kiteghost]
url = "https://kiteghost.lbframe.com/mcp"
```

Codex does not start the OAuth flow by itself: run `codex mcp login kiteghost`
once and sign in and consent in the browser it opens.

Use this when the human has no Node, or when pasting secrets is the wrong shape
for the client.

The two doors take different identities, and they are not interchangeable. The
hosted URL authenticates a **human** through OAuth — its tokens carry the
account. The npm package authenticates a **machine** — client credentials from
`agent-client.json` or `KITEGHOST_*`. A 401 on `/mcp` with machine credentials
is the design working, not a failure: use the other door.

### Local package (`npx`) — credentials already on disk

The installer wrote `~/.kiteghost/agent-client.json`. The MCP package reads it
itself — the client config carries no secret:

```json
{
  "mcpServers": {
    "kiteghost": {
      "command": "npx",
      "args": ["-y", "@lbframe/kiteghost-mcp"]
    }
  }
}
```

In Codex the same server is a TOML table in `~/.codex/config.toml`:

```toml
[mcp_servers.kiteghost]
command = "npx"
args = ["-y", "@lbframe/kiteghost-mcp"]
```

Optional overrides when the installer never touched this machine:
`KITEGHOST_CLIENT_ID`, `KITEGHOST_CLIENT_SECRET`, `KITEGHOST_URL`, `KITEGHOST_HOME`
(in Codex, set them under `[mcp_servers.kiteghost.env]`).

Use this when the installer already ran on this machine and the client expects
a stdio MCP subprocess.

Where that configuration lives depends on the client — ask the human if you
cannot tell. Clients read their configuration once, at startup: adding the
server is not enough, and neither is editing it later — **every change to the
configuration needs the client quit and relaunched** before it takes effect.
Codex is no exception; its `codex mcp list` re-reads the file fresh, so use it
to confirm an edit parsed and see connection state.

## 4. Verify before claiming success

The acceptance test is a call made by you, the agent — not a curl. Call
`listBrowsers` through the **KiteGhost** MCP tools (`mcp__kiteghost__*`; in
Codex they ride the `kiteghost` server — run `codex mcp list` first if they are
missing). The machine must appear with `online: true`, and `newTab` succeeding
is the live check. `listTabs` may be empty: agents do not see the human's other
tabs. That is privacy, not a failed setup.

`curl -s https://kiteghost.lbframe.com/healthz` proves only that the service is
up — nothing about whether your client is wired to it. Never stop there: it is
merely the first rung of the ladder below.

An empty device list, or `online: false`, means the extension is not loaded or the badge
is not green. That is step 2, not a bug. If the tools are not there at all, the
client has not picked up the configuration — restart it. Do **not** fall back to
Chrome DevTools MCP (`mcp__chrome-devtools__*`) or spawn another Chrome: that is
a different browser, and the user will see a weird extra window.

### If the device does not show up

Work down the list; stop at the first step that fails.

1. `curl -s https://kiteghost.lbframe.com/healthz`. `devices: 0` means this
   machine is not connected at all: the extension is unloaded, the browser is
   closed, or the machine is asleep. A machine that slept reconnects by itself
   within a minute of waking — wait, do not fix.
2. `devices: 1` or more but `listBrowsers` is empty — an **account mismatch**.
   The device is paired under one account and the agent's client belongs to
   another. Everything can look fine while this is broken: green badge, device
   online, still an empty list. Fix by pairing the machine again from the
   account the agent belongs to, or by creating agent credentials under the
   right account on `/devices`.
3. The panel says `auth failed` — the stored client was revoked or rotated.
   Open the side panel from the toolbar icon, disconnect, and pair again; the
   panel walks the same code flow as the installer.
4. The panel shows an old version, or the device reports `outdated: true` —
   the installed extension is older than the service. Re-run the installer to
   refresh `~/.kiteghost/extension`, then Load unpacked that folder again.
   Removing the extension wipes its pairing: the panel will show "not paired",
   which is expected — pair once more and carry on.
5. Commands worked, then `no device online` minutes later — the machine slept
   or the browser restarted. Call `listBrowsers` again before anything else;
   this recovers on its own.

## 5. Read the rest if you need it

https://kiteghost.lbframe.com/llms.txt describes what KiteGhost is, how the
pieces fit and what it cannot do. It is not needed to finish a setup — fetch it
when something here is not enough.

Driving the browser is not covered here: the MCP server ships its own operating
instructions, and every tool carries its parameters and failure modes.

## 6. Detaching

The human can cut any machine off at https://kiteghost.lbframe.com/devices at any
time. Mention it — revocation should be as findable as pairing.
