@aipoch/open-science-darwin-x64
v1.0.6
Published
Open-Science standalone Node backend, CLI and SDK
Readme
@aipoch/open-science
AIPOCH Open-Science is an open-source, local-first, model-agnostic AI research workbench. Use scientific Agents, Python and R Notebooks, and scientific data connectors to turn research questions into reports, tables and figures.
This package provides the standalone CLI, local Web UI and Node.js SDK. npm installs the matching platform package with the backend and resources; the desktop app is not required.
Install
Install Node.js 22.13.0 or later, then run:
npm install --global @aipoch/open-science
open-science --helpSupported platforms are macOS Apple Silicon/Intel, Linux ARM64/x64 with glibc, and Windows x64.
Linux musl (including Alpine) and Windows ARM64 are not supported by the published native packages.
Keep npm optional dependencies enabled: they contain the platform runtime. If startup reports a
missing native package, reinstall with npm install --global @aipoch/open-science --include=optional.
Linux also needs working credential storage and Notebook sandbox prerequisites; see the Linux setup requirements. Python/R and an Agent runtime/model provider are configured separately during setup. For installations that include Node itself, see the Homebrew and Release archive options.
Get started
Start the local service and request its browser URL:
open-science start --no-open
open-science urlOpen the printed URL, complete the setup checks, configure an Agent runtime and model provider, and create your first research project. Set up a Python or R Notebook runtime if your work needs code execution. The URL contains a local authentication token; keep it private. For setup from the terminal, follow the CLI first-run guide.
After setup, submit a task from the terminal:
open-science doctor --json
open-science project create "First research" --json
open-science run --project "First research" --prompt "Draft a research plan for comparing two analysis methods." --wait --jsonlConfirm ready: true in the doctor output before submitting work. The CLI accepts a Project ID
or an exact, unambiguous name; SDK calls use IDs. Closing the browser does not stop the service:
open-science status --json
open-science stopStopping the service affects all connected clients. For automated tasks, review the permissions and output options and the safety guidance below.
Update or uninstall
Stop services started by this installation before replacing it. Use the same --config-root
when stopping and restarting a custom profile.
open-science stop
npm install --global @aipoch/open-science@latest
open-science start --no-openTo uninstall, stop the service and run npm uninstall --global @aipoch/open-science.
Uninstalling the npm package retains research data and credentials. Review
release compatibility
before changing versions; replacing program files does not reverse data migrations.
Documentation
- CLI guide - installation, daemon lifecycle, task automation, artifacts, and exit codes
- Product overview - research workflows, screenshots and desktop downloads
- Report an issue - bugs and feature requests
- Release compatibility - stable interfaces, versioning, and data upgrades
- Intended use and known limitations - workflow precautions, data disclosure, and execution boundaries
Safety and integration
- Scope: Authenticated control of a local Open-Science service; the client does not provide an independent execution sandbox or isolate the service's Agents and tools.
- Controls: Requests use the service's permission profiles, existing grants, and host-owned runtime controls. Disabling interactive permission prompts denies requests needing a human; it does not erase previously granted authority.
- Remaining risks: A successful automated run can modify allowed files, contact configured services, or start remote jobs. A timeout or aborted wait stops observation, not the underlying run. Research outputs still need scientific review.
- Safe integration: Protect local service credentials, review the effective profile/grants and recipients, and use isolated test data before unattended operation. Cancel explicitly and confirm the resulting task/job state. Inspect downloaded or exported artifacts before sharing.
Browser-held package import
Use @aipoch/open-science/browser-import to send a downloaded .science Blob to the desktop app.
See the browser integration guide for the click flow, API, security contract,
limits, and browser requirements. The desktop never downloads the online package URL.
SDK quick start
Install the package in your Node.js project (a global CLI install does not make it importable):
npm install @aipoch/open-scienceStart and configure the local service as above. Save the example in an .mjs file and run it
with Node.js. It creates a Project and uses its ID for subsequent requests:
import { connectToOpenScience } from '@aipoch/open-science'
const client = await connectToOpenScience()
const project = await client.createProject({ name: 'Evidence review' })
const run = await client.startRun({
project: project.id,
prompt: 'Summarize the evidence.',
permissionProfile: 'auto',
permissionPrompts: 'none' // Deny requests that would require a human; keep existing permission rules.
})
const result = await client.waitForRun(run.id)
console.log(result.output)Session, Project-default, and global Agent-routing configuration use the same authenticated local API:
const configuration = await client.getSessionConfiguration(run.sessionId)
await client.updateSessionConfiguration(run.sessionId, {
expectedRevision: configuration.revision,
memoryEnabled: false
})
const defaults = await client.getProjectSessionDefaults(project.id)
await client.updateProjectSessionDefaults(project.id, {
expectedUpdatedAt: defaults.updatedAt,
patch: { permissionProfile: 'auto' }
})
await client.updateAgentRouting({
framework: 'codex',
reviewer: { mode: 'inherit' },
subagent: { mode: 'inherit' }
})
const runtimes = await client.listRuntimes()Session updates use revision; Project-default updates use updatedAt. Both reject stale writes.
Project defaults are copied only when a Session is created, with precedence startRun request,
Project defaults, application settings, then provider default. Agent-routing updates are atomic and
never return provider credentials.
Agent runtime listings expose only framework, readiness, version, and managed/external source. They do not expose executable paths.
SDK requests have a 30-second default deadline that remains active while the response body is being
consumed. Override the client default with requestTimeoutMs, or pass { signal, timeoutMs } as the
final options argument to an individual request method. downloadArtifact keeps the deadline active
while its returned Response body is streaming. waitForRun applies its overall timeoutMs and
caller signal to every in-flight polling request as well as the delay between polls. Each poll is
bounded by the smaller of the client's requestTimeoutMs and the remaining total wait budget.
A request timeout fails the wait immediately; it does not silently retry. Without a total
timeoutMs, waiting has no overall deadline. pollIntervalMs defaults to 250 and must be a finite
positive number.
Aborting or timing out a wait stops only the local observation. The Run may continue on the host;
call getRun(run.id) to check it, or explicitly call cancelRun(run.id) to stop it. With
returnOnAttention: true, a returned Run may still have status: 'running' and need a Plan decision before it can finish. Ordinary permissions do not populate Run attention.
const waitController = new AbortController()
const result = await client.waitForRun(run.id, {
timeoutMs: 120_000, // Total wait budget; each poll still has the client request deadline.
pollIntervalMs: 500,
returnOnAttention: true,
signal: waitController.signal // Aborts observation; does not call cancelRun.
})
console.log(result.status, result.attention)For retry-safe project creation and Run starts, pass the same idempotencyKey in the final options
argument on every attempt. The daemon replays the first response for up to 24 hours while it remains
running; reusing a key with a different request body fails with idempotency_conflict. If the
bounded replay registry is full, a new unique key fails with idempotency_unavailable rather than
evicting an existing guarantee. A lost response after submission does not prove that the Run was
not started. Retry with the original key and identical request while that daemon is still running,
or query the known Run ID. The replay registry is process-local: a daemon restart loses it, so
reusing a key after restart is not a durable exactly-once guarantee.
The project request field and the listSessions(projectId) argument both require a Project ID.
Project display names are not accepted as routing identifiers.
SDK and HTTP callers must supply an absolute cwd. Open-Science canonicalizes and validates it,
persists it as the Session working directory, and returns the effective path on every Run. Supplying
cwd with sessionId is allowed only when both paths resolve to the same directory. Omit cwd to
use a managed workspace. External working directories remain caller-owned and are never removed by
Open-Science.
For live automation feedback, subscribe before starting the Run. run.progress reports ordered
provider-neutral phases and emits a progress heartbeat every ten seconds until the first visible
provider output. This progress heartbeat describes Run activity; it is separate from the filtered
connection heartbeat that keeps an otherwise-idle WebSocket alive. The timer starts after Task has
prepared the Session and registered its Run; Session creation or resume time before registration is
outside this event stream:
const abortController = new AbortController()
const events = client.events({ signal: abortController.signal })
await events.ready
const progress = (async () => {
for await (const event of events) {
if (event.type === 'run.progress') {
console.log(event.data.phase, event.data.elapsedMs, event.data.heartbeat)
}
}
})()
const observedRun = await client.startRun({
project: project.id,
prompt: 'Summarize the evidence.',
permissionProfile: 'auto'
})
const observedResult = await client.waitForRun(observedRun.id)
abortController.abort()
await progress
console.log(observedResult.output)events.ready rejects if the socket fails, closes, or receives no liveness frame before opening.
After opening, the iterator fails with timeout when no event or connection heartbeat arrives for
30 seconds. Pass idleTimeoutMs to change that connection-liveness window; it does not limit model,
Notebook, permission-approval, or other Run duration. Connection heartbeats are control frames and
are not yielded to consumers. Malformed frames and a consumer backlog above 1024 events terminate
the iterator with event_stream_invalid_message or event_stream_overflow instead of throwing
outside the iterator or growing memory without a bound.
Every Run event includes top-level sequence, runId, sessionId, and projectId fields in
addition to its existing type and data. After an established socket closes unexpectedly, the SDK
reconnects with its last sequence and the daemon replays the retained suffix. Replay is bounded and
process-local. If the daemon restarted or the suffix was evicted, the iterator yields
stream.resync-required with reason stream-changed or cursor-expired; read the Run or Session
through the HTTP API to restore authoritative state.
Plan First runs can opt into actionable waiting with returnOnAttention. When the returned Run has attention.kind equal to plan-approval, use getSessionPlan and respondSessionPlan. Calling waitForRun without returnOnAttention keeps the original terminal-only behavior.
Automatic review and Specialist binding reuse existing Session JSON fields. Delegation adds delegationPolicy with values allow or deny; an omitted historical value restores as allow.
To stop a still-running task instead of waiting for it, cancel it explicitly. Cancellation waits for provider work and application finalization to drain before returning the terminal Run:
const cancelled = await client.cancelRun(run.id)
console.log(cancelled.status) // cancelledThe client discovers the local daemon and reads its authentication token from the Open-Science config
directory. HTTP calls send the token in request headers. events() authenticates its WebSocket using
a token URL query parameter; treat WebSocket URLs and request logs as sensitive. Tokens are
not included in normal command output.
Automation new-session defaults
project session-defaults show|update manages defaults for new Sessions created through the
Task CLI/API. Explicit run options override these defaults. Existing Sessions and desktop New
conversation drafts are not changed.
--provider-default-model keeps following the provider-owned default instead of pinning the
first model in its catalog. An explicit --model stays fixed. If a saved selection becomes
unavailable, choose a replacement explicitly or wait for it to become available again.
