DK Studio/Documentation
ProductChangelog

The agent pool

The agent pool is the set of DK Studio Agents the platform can address β€” one per bench, one per test rig, one per vehicle bench. It is the scheduling surface of the lab: every shell script, every system snapshot and every serial session is dispatched to one named agent from here. This page introduces what an agent is, how one joins the pool, who is online, how work is assigned, and how the pool scales.

What an agent is in the platform

An agent is the DK Studio Agent process running on the machine under test. The platform keeps one row per agent in the agents table:

FieldMeaning
idThe agent id, sent with every command, heartbeat and registration.
nameThe name the agent gave itself at registration.
capabilitiesJSON array of what the agent reports it can do.
workstationJSON description of the host: hostname, platform, architecture.
statusThe stored status. active marks an agent the pool may address.
scope, owner_user_idWho the machine belongs to, derived from the licence type it claimed.
api_key, agent_secretCredentials: a 32-character key returned once at registration, and the secret that authenticates the socket.
license_idThe licence the agent claimed.
registration_countHow many times it has registered.
last_registered_at, last_seen_atRegistration and last-contact timestamps.

The agent dials out to the studio and holds a Socket.IO connection open; the studio never dials back, so a bench needs no public address. On the bench itself, the agent serves a small page at http://localhost:3001 where an operator can open a serial port directly.

Registering agents

Registration is a two-step handshake: somebody issues a licence, and the agent claims it.

  1. A licence is issued

    A person applies for a personal licence in their Personal Center, or an administrator issues a lab licence from Admin β†’ Licences. POST /api/licenses creates the licence and returns its code.

  2. The agent claims it

    POST /api/agent/register presents the code together with the agent's name, the studio URL, its workstation description and its capabilities. The platform validates the licence, registers the machine in the scope the licence type dictates, and returns the agent's permanent identity: agentId, apiKey and agentSecret.

  3. The agent authenticates on the socket

    The agent sends an auth request with its agentId, agentSecret and protocolVersion; the platform answers with an auth response β€” ok: true and the agent's identity, or ok: false with the code AUTH_FAILED, after which it closes the socket.

POST/api/licensesIssue a licence.
{ "type": "lab", "location": "A-12", "label": "Bench A" }
POST/api/agent/registerRegister an agent with a licence code.
{
  "code": "dk_l_…",
  "name": "bench-01",
  "studioUrl": "http://studio.lab.example:3000",
  "workstation": { "hostname": "bench-01", "platform": "linux", "arch": "x64" },
  "capabilities": ["shell", "serial"]
}

The response gives back agentId, apiKey and agentSecret, along with licenseType and scope. A licence is claimed once: registering the same code again is refused. To bring an agent back after a reinstall, register with the agent's own agentId and agentSecret β€” the platform updates it in place, same id, same apiKey.

The code is the ticket

The licence code is returned once, at creation, and only its owner and an administrator can read it. A licence is spent on the registration it authorises. The full procedure is in Agent Registration.

Seeing who is online

GET/api/agentsList the agents that are connected right now.

It answers with {agents, timestamp}, where each agent carries id, name, status (always "online"), lastSeen and capabilities.

Two conditions have to hold for an agent to appear here: its stored status must be active, and it must have a live Socket.IO connection. Presence is derived from the socket map on every request, so the list is a live view of the lab.

ViewEndpointWhat it answers
LiveGET /api/agentsThe agents that are connected right now, each reported with status: "online".
InventoryGET /api/admin/agentsEvery registered agent, with status, connectionStatus (online or offline), capabilities, workstation, lastSeen and registrationCount.
Online is not the same as addressable

An agent can be active and offline β€” powered down, on a flaky link, or waiting for the studio. The inventory view shows both states; the live view shows only what you can send a command to right now.

Assigning work

Work is a command addressed to one agent. The platform records it, delivers it, and keeps the outcome.

POST/api/agents/commandSend one command to one agent.
{
  "agentId": "0f2c…",
  "command": "shell",
  "args": { "script": "uname -a" },
  "timeout": 30000
}

The command is written to agent_commands as pending, pushed down the socket, and answered with the new commandId. The agent claims it β€” in_progress β€” and posts the result back, which moves the row to completed:

pending  ──▢  in_progress  ──▢  completed

If the socket is down, the same rows are served by the agent's polling path, GET /api/agent/commands?agentId=, and the agent answers with POST /api/agent/commands/result. Read the finished record back with GET /api/agents/commands/{id}, which returns id, agentId, commandType, status, result, startedAt and completedAt β€” with result holding stdout, stderr, exitCode and durationMs.

The command vocabulary the pool can dispatch:

CommandArgumentsWhat it does on the bench
shellscript, cwd, timeoutWrites the script and runs it with /bin/bash.
get_system_infoβ€”Returns a snapshot of the machine.
get_serial_portsβ€”Lists the serial ports available.
open_serialpath, baudRateOpens a serial port.
close_serialpathCloses a port the agent has open.
serial_writepath, dataWrites to a port the agent has open.

The full contract for each one is in Command Reference.

ResponseMeaning
400 Agent is offlineThe agent has no live connection.
400 Agent is not activeThe agent is registered but not in the pool.
404 Agent not foundNo agent carries that id.

Health and capacity

  • last_seen_at is the liveness timestamp the platform keeps. The agent reports in with POST /api/agent/heartbeat and the platform updates last_seen_at; the status in that request is advisory, because presence comes from the socket.
  • registration_count rises each time an agent registers again with the credentials it already holds. A count above one usually means the machine was reinstalled or re-pointed β€” the agent kept its id.
  • The licence is the entitlement. .studio-license.json carries edition, maxAgents and features, and the platform enforces them: the pool will not take more agents than maxAgents allows, and features decides which parts of the platform the licence unlocks.
EditionLicence key prefixmaxAgentsfeatures
StarterSTR03core, agents
ProfessionalPRF010adds analytics, api
ProPR0025adds advanced
EnterpriseENT0999adds enterprise

Scaling the pool across a lab

Give every bench its own agent and name it after the bench it sits on β€” bench-01, bench-02, rig-hil-a. The name is what your team will read in the agent list and in the command log, and it is the handle you use when you write a test that targets a particular machine.

From there the pool scales along three lines:

  • More benches. Register another agent up to the licence's maxAgents allowance. Each agent carries its own credentials and its own licence, so a bench can be swapped without touching the others.
  • More per bench. An agent reports its capabilities, so you can tell a rig with serial control from one that only offers a shell, and route work to the right one.
  • More throughput. Commands are addressed to a named agent, so spreading a campaign across several agents spreads the load across several benches β€” send the same script to bench-01 and bench-02 and compare the two results.

The Agents screen in the studio is the working view of the pool: the live list of connected agents, a shell console on each, and the socket status of the ones that are away.

How to verify

  • GET /api/agents β€” the live list, with lastSeen on every entry.
  • GET /api/admin/agents β€” the full inventory, with connectionStatus and registrationCount.
  • GET /api/agents/commands/{id} β€” the result of a command you dispatched.