DK Studio/Documentation
ProductChangelog

Connect Your First Agent

An agent joins the studio in two steps: somebody issues a licence, and the agent claims that licence to register. The licence says what the machine will be — a personal machine or a bench in the lab — and it is spent the moment the machine registers. When both steps are done, the bench appears as online in the studio and accepts remote commands.

1. Get a licence

Every machine needs one licence, and there are two kinds.

KindWhere you get itWhat the machine becomes
A personal licencePersonal Center in the studio — you apply for your ownA machine that belongs to you
A lab licenceAdmin → Licences, issued by an administratorA bench that belongs to the shared lab

Sign in to the studio and open Personal Center. The Apply for a license action issues a personal licence and shows its code once. Copy the code — it is the only way into the studio.

A lab licence is issued by an administrator for a bench in the lab, and it carries the location and a label for the humans.

One licence, one machine

A licence authorises exactly one agent registration, and it is spent on that registration. Issue one licence per machine. See Agent Management.

2. Register the agent

On the machine under test, install the agent as a service and open http://localhost:3001:

./install.sh

The installer builds the agent, registers it with the operating system — launchd on macOS, systemd on Linux — so it comes back after every reboot, and opens its page for you. To run it in the foreground instead:

pnpm --filter @dkstudio/agent dev

The agent's home page shows a registration form with three fields:

FieldValue
Studio URLThe base URL of your studio, e.g. http://localhost:3000.
Agent nameHow this bench appears in the studio's agent list.
Licence codeThe code from the licence.

Press Check licence and the agent asks the studio what kind of licence it is. The answer appears before anything is registered:

  • Personal licence — this machine will be registered as yours.
  • Lab licence — this machine will be registered as part of the shared lab.

Submit the form. The agent calls POST /api/agent/register on the studio:

{
  "code": "dk_l_…40 hex characters…",
  "name": "Bench 01",
  "studioUrl": "http://localhost:3000",
  "workstation": { "hostname": "bench-01", "platform": "linux", "arch": "x64" },
  "capabilities": []
}

The studio checks the licence, registers the machine in the scope the licence type dictates, and answers with the agent's permanent identity:

{
  "success": true,
  "agentId": "0f2c…",
  "apiKey": "…32 alphanumeric characters…",
  "agentSecret": "…64 hex characters…",
  "licenseType": "personal",
  "scope": "personal",
  "ownerUserId": "9a1c…",
  "location": null,
  "reRegistered": false
}

The agent stores these in data/agent.json on its own machine and marks itself registered. It then opens its connection to the studio, so the bench comes online without a further step.

CredentialPurpose
Agent idThe identifier the agent sends in the socket handshake and on every polling request.
API keyThe secret presented to POST /api/agent/auth when the agent authenticates over the REST API.
Agent secretThe credential presented over the socket.

The licence's status flips from pending to consumed at the moment the agent row is created, and the machine now belongs to whoever the licence belonged to.

3. The agent authenticates on the socket

The agent opens a Socket.IO connection to the studio at /api/socket.io and sends an auth request with its identity:

{
  "v": 1,
  "type": "auth",
  "kind": "request",
  "id": "…",
  "timestamp": "2026-01-01T09:30:00.000Z",
  "payload": {
    "agentId": "0f2c…",
    "agentSecret": "…64 hex characters…",
    "protocolVersion": 1
  }
}

The studio validates the pair against the registered agent and answers on the same auth type:

{
  "v": 1,
  "type": "auth",
  "kind": "response",
  "id": "…",
  "timestamp": "2026-01-01T09:30:00.010Z",
  "payload": {
    "ok": true,
    "data": {
      "agentId": "0f2c…",
      "name": "Bench 01",
      "capabilities": [],
      "protocolVersion": 1
    }
  }
}

If the pair does not match, the studio answers with ok: false and the code AUTH_FAILED, then closes the connection.

4. Confirm the connection

From that moment the studio shows the agent as online in the agent list. That status is derived from the live socket, not from a stored flag, so it is accurate as soon as the handshake completes.

The studio's agent list also shows the agent's name, its last-seen timestamp and its registration count. While the agent is connected the studio keeps that timestamp fresh from the agent's presence on the socket, and GET /api/agents returns the same picture for scripts.

An agent that restarts reconnects on its own, using the credentials in data/agent.json. If the studio is not up yet, the agent keeps retrying, so restarting the bench does not need anyone at the keyboard.

Where the machine shows up

A machine registered with a personal licence appears under My Computer in the studio, and only its owner sees it. A machine registered with a lab licence appears under Lab, where the whole team sees it.

The licence type decides this, not where the machine sits. A personal licence used on a bench in the lab still gives you a personal machine.

Re-registering

A licence is spent on the first registration, so it cannot be used to register a second time. To bring an agent back after a reinstall, register with the credentials the agent already holds — its agentId and agentSecret:

{
  "agentId": "0f2c…",
  "agentSecret": "…64 hex characters…",
  "name": "Bench 01",
  "studioUrl": "http://localhost:3000",
  "workstation": { "hostname": "bench-01", "platform": "linux", "arch": "x64" },
  "capabilities": []
}

The studio updates the agent in place rather than creating a second one:

  • the agent id and API key stay the same,
  • the name, workstation and capabilities are updated,
  • the response carries reRegistered: true.

This is the intended way to move a bench to a new machine, or to re-point an agent after reinstalling it, without leaving a stale agent behind in the list.

Do not register one licence on two machines

A licence authorises one machine and is spent on it. If a second machine presents the same code, the studio refuses it. Issue a second licence instead.

If registration fails

The studio answers with 403 and one of these messages:

MessageCause
invalid_codeThe code does not match any licence. Check for a truncated paste.
usedThe licence was already spent on another machine. Apply for a new one.
revokedThe licence was revoked. Apply for a new one.
expiredThe licence had an expiry date and it has passed. Apply for a new one.

To retire an agent, revoke its licence with POST /api/licenses/{id}/revoke. A revoked licence blocks further registrations. A licence that has already been consumed cannot be revoked — delete the agent itself instead.

Next steps