# Setup tracking hooks for the site lane

Add the two hook lines below to the setup instructions in the site's SKILL.md.
This lane deliberately does not edit SKILL.md. Run the started hook before
configuration and the finished hook only after configuration succeeds, before
starting the connector. Use the same shell environment for preparation and both
hooks. Set `EDGE_CLIENT` to `codex`, `claude-code`, or another supported host name.
Keep the optional Pro key in `EDGE_KEY`; never echo it or put it in curl arguments.
Do not enable shell tracing. These requests are best effort and must not interrupt setup.

Prepare the shared random identity once with Node.js (already required by the connector):

```sh
export EDGE_INSTALL_ID="$(node --input-type=module <<'JS'
import { randomBytes } from 'node:crypto';
import { mkdirSync, writeFileSync, linkSync, unlinkSync, readFileSync, chmodSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';
try {
  const dir = process.env.EDGE_INSTALL_STATE_DIR || join(homedir(), '.config', 'edge');
  mkdirSync(dir, { recursive: true, mode: 0o700 });
  const file = join(dir, 'install-id');
  const temporary = join(dir, '.install-' + randomBytes(16).toString('hex'));
  try {
    writeFileSync(temporary, randomBytes(16).toString('hex'), { flag: 'wx', mode: 0o600 });
    try { linkSync(temporary, file); } catch (e) { if (e.code !== 'EEXIST') throw e; }
  } finally { try { unlinkSync(temporary); } catch {} }
  chmodSync(file, 0o600);
  const id = readFileSync(file, 'utf8').trim();
  if (/^[a-f0-9]{32}$/.test(id)) process.stdout.write(id);
} catch {}
JS
)"
```

At setup start:

```sh
node -e 'process.stdout.write(JSON.stringify({step:"started",client:process.env.EDGE_CLIENT||"unknown",key:process.env.EDGE_KEY||undefined,install:process.env.EDGE_INSTALL_ID||undefined,ref:process.env.EDGE_REF||undefined}))' | curl --silent --output /dev/null --max-time 2 -H 'Content-Type: application/json' --data-binary @- https://getedge.cc/api/mcp/setup_ping || true
```

After successful configuration, before connector startup:

```sh
node -e 'process.stdout.write(JSON.stringify({step:"finished",client:process.env.EDGE_CLIENT||"unknown",key:process.env.EDGE_KEY||undefined,install:process.env.EDGE_INSTALL_ID||undefined,ref:process.env.EDGE_REF||undefined}))' | curl --silent --output /dev/null --max-time 2 -H 'Content-Type: application/json' --data-binary @- https://getedge.cc/api/mcp/setup_ping || true
```

If the user arrived from a `getedge.cc/?ref=<keyId>` link, the site can put
that value in `EDGE_REF`; the hooks above send it as `ref` (omitted when unset). The backend stores `ref` only when it is exactly 8 hex characters
and silently drops anything else; the setup event is still recorded. See
[identity-keyid.md](identity-keyid.md).

The backend accepts setup events without `install` for older hooks, but they
cannot join the all-installs funnel. A validated Pro key is linked only by its
SHA-256 prefix. Unknown payload fields and IP addresses are not written to the
event ledger. An in-memory per-IP limiter allows 20 activation requests per
minute; IP bucket identifiers are HMACs with a process-local random salt.
The existing `/api/mcp/` proxy forwards both routes. No deployment is performed here.
