Host integration guide
This guide is for a product or benchmark that wants to run agents through
SharedOS. It describes the production boundary; the complete executable example
is in examples/quickstart.
What you are integrating
SharedOS is the permission and one-turn execution layer between an agent and the state it wants to use. A host keeps its existing product, storage, model provider, credentials, and scheduler, then supplies those capabilities through SharedOS ports.
host identity + policy + state
|
v
trusted AccessContext
|
v
SharedOS kernel + TurnExecutor
| |
v v
files / live tools agent driver
SharedOS does not become the source of truth for users or data. It owns the portable contracts and the decision that a particular actor may perform a particular action for a particular purpose. The host owns the facts used to construct that decision.
Current package status
The intended one-install entry point is @aicoo/sharedos, with individual
@aicoo/sharedos-* packages available for hosts that need a smaller dependency
surface. The packages are public 0.x prereleases under npm's next dist-tag;
the contracts are not yet stable or production-hardened.
For development, clone this repository and either use workspace dependencies or create verified local tarballs:
pnpm install
pnpm pack:preview
The tarballs are written to artifacts/npm/. Public consumers install the
explicit prerelease tag with npm install @aicoo/sharedos@next; the remaining
production gates are tracked in release readiness.
Choose an integration shape
Embedded runtime
Use the packages in the host process. This is the preferred shape for products that already own transactions, persistence, and model calls. There is no extra network hop, and the host can implement providers directly over its existing services.
Remote runtime
Expose the same kernel through @aicoo/sharedos-http and call it with
@aicoo/sharedos-client. Use this when process or language isolation matters more
than the additional deployment boundary. Transport authentication identifies
the caller; it does not replace SharedOS capability authorization.
Evaluation harnesses use a third, related shape: the runner owns the experiment loop and calls an embedded or remote SharedOS adapter once per tick. SharedOS still executes only one bounded turn.
Embedded integration, step by step
1. Resolve a trusted access context
For every request, the host resolves identity, grants, namespace settings, and time from trusted server-side state:
import type { AccessContext } from "@aicoo/sharedos";
const context: AccessContext = {
namespaceId: "tenant-acme",
actor: { kind: "agent", agentId: "researcher" },
authority: { kind: "human", userId: "owner-1" },
owner: { kind: "human", userId: "owner-1" },
purpose: "prepare-investor-update",
traceId: crypto.randomUUID(),
enabledToolNamespaces: ["files", "calendar"],
grants: await grantStore.resolveEffectiveGrants(/* trusted identity */),
now: new Date().toISOString(),
};
Do not deserialize an AccessContext supplied by a model, message payload, or
untrusted client and treat it as authority. In particular:
actoris the principal performing the operation;authorityis the issuer whose grants are being exercised;ownerscopes the target resources;namespaceIdisolates the tenant or benchmark world;purpose, time, expiry, and usage limits participate in authorization;enabledToolNamespacescomes from host-owned settings;grantscome from a trusted grant store and may require signature or revocation verification.
2. Adapt host state to the files resource plane
SharedOS uses one canonical files namespace. Memory, workspace, identity,
history, raw evidence, and curated knowledge are roles or roots inside that
file tree—not separate permission systems.
Implement ResourceProvider over the host's existing storage:
import type { ResourceProvider } from "@aicoo/sharedos";
const files: ResourceProvider = {
namespace: "files",
async invoke(operation, signal) {
signal.throwIfAborted();
return hostFiles.invoke({
namespaceId: operation.context.namespaceId,
owner: operation.resource.owner ?? operation.context.owner,
path: operation.resource.path,
action: operation.action,
input: operation.input,
signal,
});
},
};
The provider maps SharedOS actions onto host behavior:
| Read surface | Mutation surface | Recovery surface |
|---|---|---|
list, stat, read, search, grep | create, replace, append, delete | snapshot:create, snapshot:list, snapshot:restore |
The provider must preserve tenant isolation, canonicalize paths beneath its
configured root, reject symlink or traversal escapes, implement version checks
for concurrent writes, and return JSON-safe ResourceResult values. Search
indexes and model context mounts must preserve the grants of their source files.
3. Build the kernel and register file tools
import { CapabilityAuthorizer, SharedOSKernel, registerStandardOsTools } from "@aicoo/sharedos";
const kernel = new SharedOSKernel({
authorizer: new CapabilityAuthorizer({
usageStore: durableGrantUsageStore,
grantVerifier: durableGrantVerifier,
}),
audit: durableAuditSink,
toolNamespaceSettings,
toolProviders: [userMcpToolProvider],
});
kernel.registerResourceProvider(files);
registerStandardOsTools(kernel, { files });
Registering the provider enables direct resource operations. Registering the
standard tools exposes the same operations as model-callable tools such as
files.search and files.append. Neither registration grants access.
The in-memory stores from @aicoo/sharedos-testkit are useful for tests and
isolated experiment worlds. They are not production persistence.
4. Grant the minimum authority
A grant binds subject, issuer, namespace, purpose, time constraints, resource scope, and actions. For example, this capability allows semantic search below one project root, but does not allow reading another root or changing a file:
const projectSearch = {
resource: {
namespace: "files",
path: ["Work", "Projects", "sharedos"],
owner: { kind: "human", userId: "owner-1" },
},
actions: ["search"],
scope: "descendants",
} as const;
Invoking the target agent is a separate capability. Use
agentExecutionCapability(targetAgent, owner) when issuing that grant. A
message addressed to the target agent is never sufficient by itself.
5. Add native, connector, or MCP tools
Live systems such as calendar, email, GitHub, and Notion remain tools because
their state must be observed—or changed—at execution time. The host owns OAuth,
credentials, MCP connections, and the implementation of each ToolHandler.
Use kernel.registerTool for static, process-wide tools. Use a
ContextToolProvider for user-specific or dynamically discovered catalogs so
one user's MCP reload cannot mutate another user's tool registry.
Every tool declares:
- a globally stable tool name, such as
notion.search; - a logical namespace, such as
notion; - a source, such as
nativeormcp; - a conservative read/write classification;
- an input schema;
- a capability ceiling for discovery;
- preferably,
resolveRequirement, which derives the exact resource and action from validated call arguments immediately before invocation.
A Notion MCP connection can therefore be mounted safely, but connecting it and authorizing it are different operations. A typical search call is usable only when all of the following are true:
the host registered this user's Notion handler
AND the `notion` namespace is enabled
AND a matching `notion` resource/action grant exists
AND the exact argument-selected page or database is still authorized
For example, the host can grant search on one database without granting page updates. Similarly, a calendar namespace can expose free/busy reads while event details, event creation, and event deletion remain separately scoped actions.
6. Select a runtime and execute exactly one bounded turn
For the reference loop, the host implements AgentTurnDriver, wraps it in
StandardRuntime, and places that plugin inside SharedOSExecutor:
import { SharedOSExecutor, StandardRuntime } from "@aicoo/sharedos";
const runtime = new StandardRuntime(agentDriver);
const turns = new SharedOSExecutor(kernel, runtime, {
defaultMaxSteps: 16,
defaultMaxToolCalls: 16,
defaultTimeoutMs: 120_000,
});
const visibleTools = await kernel.listTools(context);
const result = await turns.execute({
version: "1",
executionId: crypto.randomUUID(),
agent: targetAgent,
context,
message,
tools: [...visibleTools],
});
TurnExecutor(kernel, agentDriver) remains a compatibility shorthand for this
standard composition.
To install a complete Codex, DeepSeek, or private harness, implement
RuntimePlugin and register it from trusted host configuration:
import { RuntimeRegistry, SharedOSExecutor } from "@aicoo/sharedos";
const runtimes = new RuntimeRegistry([standardRuntime, codexRuntime, deepseekRuntime]);
const runtime = runtimes.resolve(serverPolicy.runtimeId);
const turns = new SharedOSExecutor(kernel, runtime);
Do not resolve runtimeId directly from a message, model output, or unverified
request metadata. A runtime receives a frozen, sanitized context without grants
or issuing authority. The envelope admits the target-agent invocation, filters
discovery, and re-authorizes every exact tool call through RuntimeHost. A turn
ends when the runtime completes or fails, the deadline expires, or the host
cancels it. The standard runtime additionally enforces its driver step limit.
SharedOS does not decide when an entire agent network is complete. Runtime coordination, adaptive routing, retries, budgets, and network-level stopping belong to the host scheduler, which may invoke another bounded turn after examining the result and events.
Why namespace enablement is not permission
Tool availability has three independent gates:
usable tool = registered for this context
AND namespace enabled
AND capability allowed
Namespace settings are the product control plane: they answer whether a family of tools should appear in this context. Capabilities are the authority plane: they answer which exact resources and actions the actor may use. SharedOS filters discovery and checks invocation again so neither a stale catalog nor a model-authored call can bypass the second gate.
If the product allows users to change namespace settings, implement
ToolNamespaceSettingsStore.applyUpdate as an atomic update over fresh state.
The store may narrow a request according to organization policy, but must not
widen it.
Remote integration
On the server, wrap the same kernel and turn executor:
import { createKernelSharedOSApi, createSharedOSHandler } from "@aicoo/sharedos";
const api = createKernelSharedOSApi({ kernel, turns });
const handle = createSharedOSHandler({
api,
resolveContext: async (request) => resolveTrustedContextFromSession(request),
});
On the caller, use SharedOSClient for /v1/tools, namespace settings,
resource and tool calls, messages, and /v1/turns:
import { SharedOSClient } from "@aicoo/sharedos";
const sharedos = new SharedOSClient({
baseUrl: "https://sharedos.internal.example",
token: () => serviceIdentityToken(),
});
The HTTP server must derive AccessContext from authenticated server-side
state. Never accept the authorization context from the remote JSON body.
Production responsibilities that remain in the host
Before production use, the host must provide:
- authenticated identity and tenant resolution;
- durable grants, revocation verification, and atomic bounded-grant usage;
- isolated file and tool providers with cancellation-safe side effects;
- durable tool namespace settings and credential isolation;
- durable, append-only audit storage and operational alerting;
- replay and idempotency controls around externally visible mutations;
- model-driver limits, product scheduling, retries, budgets, and stopping;
- consent, policy administration, retention, deletion, and incident response.
See the permission model and threat model before exposing writes or external tools.
Adoption checklist
- Select embedded or remote deployment and record the SharedOS version.
- Map product identities to structured addresses and choose the world or
tenant
namespaceIdboundary. - Implement the trusted
AccessContextresolver. - Adapt existing knowledge and working state to one
filesprovider. - Register built-in, native, and context-specific MCP tools.
- Persist enabled tool namespaces independently from grants.
- Issue least-authority grants, including a separate target-agent invocation grant.
- Select a trusted
RuntimePlugin; useStandardRuntimewith a boundedAgentTurnDriverwhen the reference loop is sufficient. - Add allowed and denied conformance tests for every permission-bearing path.
- Record runtime id/version separately from model and execution backend, and keep network scheduling outside SharedOS.
- Run
pnpm checkand test cancellation, replay, revocation, audit failure, broker closure, and tenant isolation before enabling production writes.
Host-specific mappings live outside this guide: they depend on how your product already models storage, identity, and tools.