Skip to main content

Task SDK and local API

The @aipoch/open-science Node.js client connects to an authenticated local application service to manage tasks, sessions, Connectors and shared credentials. Public SDK methods are separate from Electron preload calls and the agent's internal host APIs.

Connect, run a task and download its output

Example Save and download a connection-check note

Use Node.js 22.5 or later. Open the installed desktop application on the same machine, finish model setup and keep it running. The SDK uses local service discovery and its locally stored token. For a separate daemon, first follow Headless service.

In an empty working folder, install the client:

npm init -y
npm install @aipoch/open-science

Save the following as connection-check.mjs. Run node connection-check.mjs to list project IDs, then node connection-check.mjs PROJECT_ID with one returned ID. The first invocation deliberately stops after listing projects; the second creates a small task.

import {connectToOpenScience} from '@aipoch/open-science';
import {writeFile} from 'node:fs/promises';

const client = await connectToOpenScience();
const projects = await client.listProjects();
const projectId = process.argv[2];
if (!projects.some((project) => project.id === projectId)) {
console.table(projects.map(({id, name}) => ({id, name})));
console.log('Run again with a project ID from this list. Create a project in the app if the list is empty.');
process.exit(projectId ? 1 : 0);
}
const run = await client.startRun({
project: projectId,
prompt: 'Save a short Markdown file named project-note.md explaining that this is a connection check. Do not read project inputs or use the network.',
permissionProfile: 'ask',
});
console.log('Run:', run.id, 'Session:', run.sessionId);
const result = await client.waitForRun(run.id, {timeoutMs: 120000});
console.log(result.status, result.output ?? result.error ?? '');
if (result.status !== 'completed') {
throw new Error('Inspect the run in the application before continuing.');
}
const artifacts = await client.listArtifacts(run.sessionId);
console.table(artifacts.map(({id, name, path}) => ({id, name, path})));
const artifact = artifacts.find((item) =>
item.name === 'project-note.md' || item.path.endsWith('/project-note.md'));
if (!artifact) throw new Error('No matching saved artifact; inspect the response.');
const response = await client.downloadArtifact(artifact.id);
await writeFile('project-note.download.md', new Uint8Array(await response.arrayBuffer()));
console.log('Saved project-note.download.md; open and check its contents.');

Keep the desktop session open. Respond there if Ask for approval pauses the task. A wait timeout stops client polling; it does not cancel the run. Inspect the printed run ID with getRun, continue waiting after resolving the request, or call cancelRun when you intend to stop it. The download succeeds only when a matching saved artifact exists; open the downloaded Markdown to finish the check.

This program demonstrates the public API contract. It does not assume that a model will always save the requested file. If the npm package cannot be installed, use the SDK folder shipped with the matching source checkout as the local package; confirm its package metadata before installation.

A completed task whose file will not download

A cause of this error—lost artifact version identity in completed Task records—was fixed in the download update. On an older app, update before retrying the same saved file. Other HTTP 500 causes still require diagnosis.

Task completion and artifact download are separate checks. If downloadArtifact returns HTTP 500 / internal_error, call getRun and listArtifacts to confirm the task state and retain the exact returned artifact ID. Do not start the same research task again just to retry a download.

Open the artifact in the application and check whether its content is available. A working preview does not establish that the SDK download succeeded. Include the run ID, artifact ID and download error in a diagnostic report; omit authentication tokens. The same failure can affect the CLI's artifacts download command.

Inspect readiness and prepare Codex

SDK methodHTTP resourcePurpose
doctor()GET /api/v1/doctorInspect readiness and next actions.
listRuntimes()GET /api/v1/runtimesList framework, status, optional version and managed/external source.
bootstrap({action: "status"})POST /api/v1/bootstrapInspect first-run setup state.
bootstrap({action: "runtime"})POST /api/v1/bootstrapPrepare or repair the managed Codex runtime through the supported bootstrap flow.
installCli()POST /api/v1/cli/installInstall the local PATH launcher.

Setup mutations require the authenticated local service. Check the returned ok and error code; configuration conflicts must be resolved before retrying. A client timeout does not establish that an accepted installation was cancelled. Recheck readiness before starting another install. For subscription login or named-environment-variable credential input, use the terminal setup flow.

Methods and HTTP resources

SDK methodHTTP resourcePurpose
listProjects, createProjectGET/POST /api/v1/projectsRead/create projects
updateProjectPATCH /api/v1/projects/:idUpdate project metadata/context
getProjectSessionDefaults, updateProjectSessionDefaultsGET/PATCH /api/v1/projects/:id/session-defaultsDefaults for newly created sessions
listSessionsGET /api/v1/sessions?project=IDRead session summaries
getSessionGET /api/v1/sessions/:idRead one session
getSessionConfiguration, updateSessionConfigurationGET/PATCH /api/v1/sessions/:id/configRead/update session configuration
getAgentRouting, updateAgentRoutingGET/PATCH /api/v1/settings/agent-routingGlobal framework/Reviewer/Subagent routing
getSessionPlanGET /api/v1/sessions/:id/planRead active plan state
respondSessionPlanPOST /api/v1/sessions/:id/plan/respondRespond with the exact decision/version/revision
startRunPOST /api/v1/runsAdmit a run
getRun, cancelRunGET /api/v1/runs/:id, POST /api/v1/runs/:id/cancelInspect/cancel execution
listArtifactsGET /api/v1/sessions/:id/artifactsRead managed output descriptors
downloadArtifactArtifact download responseStream a saved output; consume the returned Response body
waitForRunSDK polling over run statusWait with cancellation/deadline options
eventsSDK event iteratorObserve ordered activity and reconnect/resync signals

Method definitions and exact routes are the authoritative lookup for request signatures. The table is not permission to call arbitrary Electron/internal endpoints.

Connector management methods

SDK methodHTTP resource
listConnectors()GET /api/v1/connectors
getConnector(id)GET /api/v1/connectors/:id
setConnectorEnabled(id, enabled)PUT /api/v1/connectors/:id/enabled
addConnector(request)POST /api/v1/connectors
updateConnector(id, request)PATCH /api/v1/connectors/:id
removeConnector(id)DELETE /api/v1/connectors/:id
testConnector(id)POST /api/v1/connectors/:id/test
listCredentials()GET /api/v1/credentials
createCredential(request)POST /api/v1/credentials
updateCredential(id, request)PATCH /api/v1/credentials/:id

Methods accept request options as the final argument. Use returned stable IDs. Only custom MCP definitions support create/edit/remove; updates require transport and preserve omitted credential bindings. Read exact request types before constructing a mutation.

Example Test a configured Connector

const connectors = await client.listConnectors();
console.log(connectors);
// Use an actual returned custom Connector ID:
const result = await client.testConnector(connectorId);
console.log(result.success, result.toolCount, result.message);

testConnector opens an isolated connection, discovers tools and closes it. It does not invoke a research tool, enable the Connector or initiate first-time OAuth sign-in. Custom MCP/credential changes require local authentication; credential metadata omits raw secrets.

Run and configuration identity

Example Start a task that pauses for plan approval

const run = await client.startRun({
project: projectId, // a returned ID
prompt: 'Inspect the available project inputs and propose an analysis plan.',
permissionProfile: 'ask',
turnIntent: 'plan-first',
});
const state = await client.waitForRun(run.id, {
timeoutMs: 120000,
returnOnAttention: true,
});
console.log(state);

A waiting plan can return a still-running object with attention.kind === 'plan-approval'. Read the active plan and its version/revision before responding. To review visually, open the printed session in the application, approve or revise the plan there, then resume waitForRun(run.id). For API-only decisions, use getSessionPlan and respondSessionPlan with that exact version/revision; see plan commands. An ordinary permission prompt does not become the same structured attention state.

Input/stateRule
cwdIf supplied through SDK/HTTP, must be absolute; server canonicalizes and checks an existing readable/writable directory
Existing sessionId + cwdMust resolve to that session's recorded directory
Omitted cwdUse an application-managed workspace
External workspaceRemains caller-owned and is not deleted by the application
Session configuration writeUses expectedRevision; reject stale writes
Project-default writeUses expectedUpdatedAt plus patch; reject concurrent edits
New-session precedenceExplicit run request → project defaults → application settings → provider default
Changed project defaultsAffect new sessions; do not rewrite existing sessions

Read configuration before editing it. A provider/model/effort change is a compound configuration, and referenced resources must be available to the selected framework. Preserve omitted settings unless deliberately clearing them.

Deadlines and retry identity

The client request deadline defaults to 30 seconds and remains active while consuming the response body. Set requestTimeoutMs at connection/client setup, or {signal, timeoutMs} in a supported method's final options argument. downloadArtifact retains its deadline while the returned body streams.

waitForRun has its own overall timeout and signal, applied to polling requests and delays. A wait timeout does not cancel the server run. Call cancelRun(run.id) explicitly when cancellation is intended and wait for finalization before treating artifacts as settled.

For retry-safe project creation and run admission, pass an idempotencyKey in the final options argument and reuse the same key with the same body. Replay is bounded and process-local, retained for up to 24 hours while the daemon stays running. Changed bodies return idempotency_conflict; an exhausted replay registry can return idempotency_unavailable. A daemon restart is not a durable cross-restart replay guarantee.

Event stream boundaries

Subscribe and await events.ready before starting work if you need the earliest run events. The iterator carries sequence and run/session/project identifiers. run.progress includes provider-neutral phases and ten-second liveness updates before first visible provider output; session preparation before run registration is outside that stream.

SignalInterpretationResponse
events.ready rejectionConnection failed before usable livenessReconnect after resolving the cause
Default 30-second idle timeoutNo event/control heartbeat arrivedCheck connection; this is not a model execution timeout
event_stream_invalid_messageMalformed event frameStop consuming that stream and reestablish state
event_stream_overflowConsumer backlog exceeds 1,024 eventsHandle backpressure and reread authoritative state
stream.resync-requiredReplay suffix expired or stream changedFetch current Run/Session through HTTP

Connection heartbeats are control frames and are not yielded as ordinary research events. Reconnect replay is bounded and belongs to the current process. Persist the artifact IDs and final run state needed by your own integration.

SDK source, SDK contract notes. See CLI for shell automation and Headless service for discovery/lifecycle.

Sources: signatures, routes. See CLI management fields for configuration and diagnostic boundaries.