Status: unsupported experimental. These surfaces are source-available but outside the supported v3 product contract. They are hidden from default
hack --help(seehack help --all) and print a warning when invoked.
Internal SDK helpers for the control plane and gateway clients.
Create a typed HTTP/WS client for gateway orchestration:
import { createGatewayClient } from "./gateway-client.ts"
const client = createGatewayClient({
baseUrl: "http://127.0.0.1:7788",
token: process.env.HACK_GATEWAY_TOKEN ?? ""
})
const status = await client.getStatus()
if (status.ok) {
console.log(status.data.status, status.data.uptime_ms)
}Shells (write token + allowWrites required):
const created = await client.createShell({ projectId, cols: 120, rows: 30 })
if (!created.ok) throw new Error(created.error.message)
const ws = client.openShellStream({
projectId,
shellId: created.data.shell.shellId
})
ws.addEventListener("open", () => {
ws.send(JSON.stringify({ type: "hello", cols: 120, rows: 30 }))
})createGatewayClient accepts:
| Field | Type | Required | Description |
|---|---|---|---|
baseUrl |
string | yes | Gateway base URL (e.g. http://127.0.0.1:7788) |
token |
string | yes | Gateway token (read or write scope) |
timeoutMs |
number | no | Request timeout in ms (default: 5000) |
| Method | HTTP/WS | Args | Returns | Notes |
|---|---|---|---|---|
getStatus() |
GET /v1/status |
- | GatewayResponse<GatewayStatus> |
- |
getMetrics() |
GET /v1/metrics |
- | GatewayResponse<GatewayMetrics> |
- |
getNodeStatus() |
GET /v1/node/status |
- | GatewayResponse<GatewayNodeStatus> |
Node metadata/capabilities |
getProjects(opts?) |
GET /v1/projects |
{ filter?, includeGlobal?, includeUnregistered? } |
GatewayResponse<GatewayProjectsPayload> |
Gateway ignores includeUnregistered |
getPs(opts) |
GET /v1/ps |
{ composeProject, project?, branch? } |
GatewayResponse<GatewayPsPayload> |
- |
ensureNodeWorkspace(opts) |
POST /v1/node/workspaces/ensure |
{ project?, projectId?, path?, branch?, bootstrap? } |
GatewayResponse<GatewayNodeWorkspaceResponse> |
bootstrap accepts { repoUrl, projectName?, projectRoot? } for fresh-node clone/register |
devcontainerUp(opts) |
POST /v1/node/devcontainers/up |
{ project?, projectId?, path?, branch? } |
GatewayResponse<GatewayNodeDevcontainerResponse> |
Start tracked devcontainer session |
devcontainerDown(opts) |
POST /v1/node/devcontainers/down |
{ id } |
GatewayResponse<GatewayNodeDevcontainerResponse> |
Stop tracked session |
getDevcontainer(opts) |
GET /v1/node/devcontainers/:id |
{ id } |
GatewayResponse<GatewayNodeDevcontainerResponse> |
Fetch tracked session state |
listJobs(opts) |
GET /control-plane/projects/:id/jobs |
{ projectId } |
GatewayResponse<GatewayJobListResponse> |
- |
getJob(opts) |
GET /control-plane/projects/:id/jobs/:jobId |
{ projectId, jobId } |
GatewayResponse<GatewayJobResponse> |
- |
createJob(opts) |
POST /control-plane/projects/:id/jobs |
{ projectId, runner?, command, cwd?, env? } |
GatewayResponse<GatewayJobResponse> |
Write token + allowWrites |
cancelJob(opts) |
POST /control-plane/projects/:id/jobs/:jobId/cancel |
{ projectId, jobId } |
GatewayResponse<GatewayCancelResponse> |
Write token + allowWrites |
createShell(opts) |
POST /control-plane/projects/:id/shells |
{ projectId, shell?, cwd?, env?, cols?, rows? } |
GatewayResponse<GatewayShellResponse> |
Write token + allowWrites |
getShell(opts) |
GET /control-plane/projects/:id/shells/:shellId |
{ projectId, shellId } |
GatewayResponse<GatewayShellResponse> |
- |
openJobStream(opts) |
WS /control-plane/projects/:id/jobs/:jobId/stream |
{ projectId, jobId } |
WebSocket |
Uses ?token= query string |
openShellStream(opts) |
WS /control-plane/projects/:id/shells/:shellId/stream |
{ projectId, shellId } |
WebSocket |
Uses ?token= query string |
GatewayResponse<T>:
| Field | Type | Description |
|---|---|---|
ok |
boolean | Success flag |
status |
number | HTTP status code |
data |
T | Present when ok: true |
error |
GatewayError | Present when ok: false |
GatewayError:
| Field | Type | Description |
|---|---|---|
message |
string | Error message |
code |
string (optional) | Error code (e.g. writes_disabled) |
raw |
object (optional) | Raw response payload |
For payload schemas (GatewayStatus, GatewayMetrics, GatewayProjectsPayload, GatewayPsPayload,
JobMeta, ShellMeta), see docs/gateway-api.md.
Read control-plane configuration (global config + project overrides):
import { readControlPlaneConfig } from "./config.ts"
const config = await readControlPlaneConfig({ projectDir: "/path/to/repo/.hack" })
console.log(config.config.gateway.enabled)- Global config lives at
~/.hack/hack.config.json(override withHACK_GLOBAL_CONFIG_PATH). - Gateway write operations require global
controlPlane.gateway.allowWrites = trueand a write-scoped token. - See
gateway-api.mdfor endpoint details and structured workflows.