From install to an approved plan in five minutes.
No account, no API-key relationship to set up. ONTO defaults to a free open-weight model, so the fastest path to a running agent is a single install and one env var.
The four steps
- 1
Install the SDK
Install onto-core with pip (Python), @onto/core with npm (TypeScript), or onto-runtime with cargo (Rust). All three bind to the same Rust core.
- 2
Point at a model
ONTO defaults to a free open-weight model on Ollama Cloud. Export OLLAMA_API_KEY to use it, or set ANTHROPIC_API_KEY / OPENAI_API_KEY to swap providers with no code change.
- 3
Run with consent scopes
Call run_sync with the consent scopes you want to grant and extract=True to capture typed facts. The agent proposes; nothing side-effectful runs without the scope.
- 4
Review the plan, then approve
Run again in plan_only mode to get a reviewable task list. Approve it, then run once more with execute scopes to do the work and commit facts to UPO.
Get started in 60 seconds.
No account needed. ONTO defaults to free open-weight models on Ollama Cloud, so you can run your first agent with a single pip install and an env var.
- No API key relationship needed to start — defaults to free open-weight models.
- Same primitives in Python, TypeScript, Rust, and over HTTP.
- On-prem path uses Sled or Postgres + pgvector. No data has to leave your network.
pip install onto-coreThen export OLLAMA_API_KEY to use the free open-weight default. Or set ANTHROPIC_API_KEY / OPENAI_API_KEY to swap providers.
Run an agent — the agent proposes, you granted one scope.
The run below is allowed to write memory and nothing else. It extracts typed facts and routes each to the right level. No web fetch, no side effect — you did not grant those scopes.
from onto import Onto, Models, BuiltinTools
onto = Onto(
model=Models.GPT_OSS_20B, # free open-weight default
builtin_tools=BuiltinTools.STANDARD,
)
# The agent reads state and PROPOSES. extract=True captures typed facts.
result = onto.run_sync(
"Hi, I'm Alice. UTC, mornings. Plan a 3-day trip to Lyon.",
user_id="alice",
consent_scopes=["memory:write"], # nothing else is permitted
extract=True,
)
for ea in result.extracted_assertions:
print(f"{ea.level:8} {ea.subject}.{ea.predicate} = {ea.object!r}")
# profile alice.timezone = "UTC"
# profile alice.prefers = "mornings"
# session alice.location = "Lyon" Halt before execution. Approve. Then run.
Plan Mode is a runtime invariant. The first run proposes a task list and stops. The human reviews it and grants execute scopes for a second run — the model never approves its own work.
# 1. Plan only — the agent proposes tasks; no tool fires, no write happens.
plan = onto.run_sync(
"Plan the trip.",
user_id="alice",
mode="plan_only",
)
for task in plan.tasks:
print(task.summary) # human reads the proposed steps
# 2. Human approves and grants EXECUTE scopes for a second run.
if approve(plan): # your own review gate
onto.run_sync(
"Run the approved plan.",
user_id="alice",
consent_scopes=["tools:web.fetch", "memory:write"],
) Same agent, in TypeScript
The Node binding is built with napi-rs on the same Rust core, so semantics are identical.
import { Onto, Models, BuiltinTools } from "@onto/core";
const onto = new Onto({
model: Models.GPT_OSS_20B,
builtinTools: BuiltinTools.STANDARD,
});
const result = await onto.run(
"I'm Alice. UTC, mornings. Plan a trip to Lyon.",
{ userId: "alice", consentScopes: ["memory:write"], extract: true },
);
for (const ea of result.extractedAssertions) {
console.log(ea.level, ea.subject, ea.predicate, ea.object);
} Star the repo and build in the open.
ONTO is MIT or Apache-2.0. Pre-1.0, with 238 tests across the Rust core and the Python and TypeScript SDKs.