Skip to content

TypeScript control-plane SDK

@siloga/magmell is a zero-runtime-dependency TypeScript client built on the global fetch API. It uses camel-case application types while mapping explicitly to the gateway’s wire format.

This is the control-plane client. Code running inside a Node handler uses the distinct @siloga/magmell-agent Agent SDK for secrets and telemetry.

Use an API key in a server or CI process:

import { MagmellClient } from '@siloga/magmell'
const magmell = new MagmellClient({
baseUrl: 'https://api.magmell.siloga.cloud',
apiKey: process.env.MAGMELL_API_KEY,
})

Never place an API key in public browser code. Browser operator tools should authenticate a user and pass accessToken, teamId, and a refresh callback.

From a Node.js directory:

const deployment = await magmell.deploy({
name: 'reviewer',
version: '1',
dir: './agents/reviewer',
requirements: ['httpx==0.28.1'],
setupSteps: ['apt-get update', 'apt-get install -y ffmpeg'],
})
await magmell.waitForBuild(deployment.deploymentId)

For a Node.js handler, select node-22 and do not provide Python requirements. The client first checks the gateway capability state and rejects creation while the staged runtime is disabled:

await magmell.deploy({
name: 'reviewer-node',
version: '1',
runtime: 'node-22',
dir: './agents/reviewer-node',
setupSteps: ['apt-get update', 'apt-get install -y ffmpeg'],
})

Or provide an explicit filename-to-source map:

await magmell.deploy({
name: 'greeter',
version: '1',
code: {
'handler.py': 'def handle(input):\n return {"hello": input.get("name")}\n',
},
})

To run your own process instead of a handler, set preset: 'command' and give the exact entrypoint argv. The client validates the entrypoint against the same contract as the gateway before sending it. See command deployments for the runtime contract.

await magmell.deploy({
name: 'reviewer-cmd',
version: '1',
dir: './agents/reviewer',
preset: 'command',
entrypoint: ['python', 'main.py'],
})
const created = await magmell.runByName(
'reviewer',
{ document: 'Text to review' },
{ version: '1', timeoutS: 120 },
)
const completed = await magmell.waitForRun(created.runId)
if (completed.status === 'failed') {
throw new Error(completed.error ?? 'agent run failed')
}
console.log(completed.result)

The waiting helpers default to a five-minute deadline and two-second polling interval. Override them when your application has different latency expectations.

let cursor: string | undefined
do {
const page = await magmell.listRuns({ limit: 50, cursor })
for (const run of page.items) console.log(run.runId, run.status)
cursor = page.nextCursor ?? undefined
} while (cursor)

Do not construct or interpret pagination cursors yourself; treat them as opaque values.

const deployment = await magmell.getDeploymentByName('reviewer', { version: '2' })
await magmell.putSecretsByName(
'reviewer',
{ MODEL_API_KEY: process.env.MODEL_API_KEY! },
{ version: '2' },
)
await magmell.runByName('reviewer', input, { version: '2' })

Carry the version through every version-sensitive operation during a rollout.

import { MagmellError } from '@siloga/magmell'
try {
await magmell.getRun(runId)
} catch (error) {
if (error instanceof MagmellError) {
console.error(error.status, error.message, error.body)
}
throw error
}

MagmellError.status contains the HTTP status for request failures. Waiting failures and timeouts use status 0 because they are client-side operational errors rather than HTTP responses.

Area Methods
Deployments deploy, getDeployment, getDeploymentByName, listDeployments, deleteDeployment, waitForBuild
Runs run, runByName, getRun, getRunByNumber, listRuns, listRunsByName, waitForRun
Events getRunEvents, getRunEventsByNumber
Secrets putSecrets, putSecretsByName, getSecretNames, getSecretNamesByName
Keys createKey, listKeys, revokeKey
Teams me, membership management methods, setTeamId