Local-first runtime service plane for domain agents and build agents. The package exposes a TypeScript library and a localhost JSON-RPC service for model, artifact, record, vector, resource, and secret-backed infrastructure.
Runtime home defaults to ~/.agent-runtime-services.
agent-runtime-services is a project-neutral runtime service plane. Domain
agents and build agents consume it through typed capabilities or local JSON-RPC;
they do not own provider clients, model catalogs, artifact stores, record
stores, vector indexes, or generic secret resolution.
Secrets remain operator-configurable per runtime home. Model catalogs, capability operations, artifact storage, record storage, vector storage, and resource discovery are shared implementation capabilities that domain-agent and build-agent projects can reuse without maintaining duplicate provider/storage code.
This README is the product-facing entrypoint for Product Development. It describes what the runtime service does for users and contributors, the main run path, public capabilities, storage boundaries, package contents, and operator commands.
Product Development includes src/, bin/, README.md, architecture/,
examples/, public contracts, tests, harnesses, and package metadata. These
files must stay publishable and must not depend on repository-maintenance
material.
Repository-maintenance material may read and index this product surface from a source checkout. It is not part of the runtime service or package payload. Product runtime code must not import from it.
capabilities/: CapabilityRegistry, the single source for capability ids, request/output schemas, effects, risk class, consumers, and authority.models/: provider catalog, module selection, provider runtime resolution, and provider API clients.resources/: capability/resource catalog and availability overlays.storage/: artifact store, JSON record store, and vector indexes.rpc/: localhost JSON-RPC server/client that mirrors the library capability interface.mcp/: MCP adapter mapping helpers over the same CapabilityRegistry. Full remote transport is intentionally not duplicated as a second business layer.config/: runtime home paths, secret refs, encrypted keystore, and generic secret resolver.
pnpm install
pnpm test
pnpm build
agent-runtime-services models install-volcengine-agent-plan
agent-runtime-services secrets set --id ARK_API_KEY
agent-runtime-services serve --host 127.0.0.1 --port 8765The library entrypoint is createRuntimeServices(config). It exposes typed
capabilities for:
language.completeembedding.createvision.generateImageartifact.save/get/list/cleanupExpiredrecord.upsert/get/query/deletevector.upsert/searchresources.list/doctor/smoke/status
The RPC service mirrors those capabilities over localhost JSON-RPC and also
supports health, version, capabilities.list, and
capabilities.describe. The descriptor endpoint is intentionally
agent-friendly: it returns intended consumers, machine-readable request shapes,
result shapes, side-effect categories, transport hints, and authority
boundaries rather than human-facing help text.
Provider port assembly is configured separately from the model catalog. The
local model catalog remains model-providers.json; runtime provider port
selection lives in runtime-providers.json under the runtime home. If
runtime-providers.json is absent, serve uses local defaults. If present, it
can point model, artifact object, artifact manifest, record, and vector ports at
remote HTTP/JSON adapters without changing any /rpc method or request shape.
Use agent-runtime-services serve --provider-config <path> to override the
default <runtime-home>/runtime-providers.json. The resources, doctor,
storage, and models smoke commands accept the same --runtime-home and
--provider-config options so operator checks inspect the same runtime provider
assembly as the running RPC process. models smoke also accepts --config to
override the model provider config used for the smoke call. These files are
local operator configuration and must not be committed.
Use runtime-providers.json when the stable /rpc surface should route through
remote provider services instead of local defaults. The shape is stable at the
Runtime Services boundary; provider implementations behind the endpoints remain
replaceable:
{
"model": {
"kind": "remote-http-json",
"endpoint": "https://runtime.example/internal",
"providerId": "remote-model"
},
"artifact": {
"object": {
"kind": "remote-http-json",
"endpoint": "https://runtime.example/internal",
"providerId": "remote-object"
},
"manifest": {
"kind": "remote-http-json",
"endpoint": "https://runtime.example/internal",
"providerId": "remote-rds-manifest"
}
},
"record": {
"kind": "remote-http-json",
"endpoint": "https://runtime.example/internal",
"providerId": "remote-record"
},
"vector": {
"kind": "remote-http-json",
"endpoint": "https://runtime.example/internal",
"providerId": "remote-vector"
}
}Each remote adapter is a JSON-over-HTTP POST contract relative to endpoint.
The current adapter routes are:
/resources/probe/models/complete/models/embedding/models/image/objects/put/objects/get/objects/delete/artifacts/insert/artifacts/list/artifacts/get/artifacts/delete/records/upsert/records/get/records/query/records/delete/vectors/upsert/vectors/search
Storage routes carry caller-owned isolation keys:
/objects/put:{ namespace, key, bodyBase64, mimeType? }/objects/get:{ path }/objects/delete:{ path }/artifacts/list:{ namespace }/artifacts/get:{ namespace, id }/artifacts/delete:{ namespace, id }/records/upsert:{ namespace, tableName, id, data, metadata? }/records/get:{ namespace, tableName, id }/records/query:{ namespace, tableName, limit? }/records/delete:{ namespace, tableName, id }/vectors/upsert:{ tableName, record }/vectors/search:{ tableName, embedding, limit?, filter? }
/vectors/search accepts a minimal structured hybrid retrieval filter:
{ filter: { metadata: { key: string | number | boolean } } }. This is not a
caller-provided SQL DSL. The local LanceDB implementation compiles it to a
pre-filtering where(...) predicate only when filter is present; unfiltered
vector search stays on the plain vector-search path.
Explicit headers are supported for trusted local/operator configuration.
headersSecretId is reserved and currently rejected so secret indirection does
not silently appear in provider calls before it has a verified contract.
/rpc is the local surface for domain-agent and build-agent consumers. /mcp
is reserved as the remote MCP Streamable HTTP adapter surface and must map from
CapabilityRegistry with explicit scoped exposure rather than reimplementing the
same capability logic.
Runtime service outputs use a common envelope with status, capabilityId,
providerId, modelId, and evidence. Model outputs are typed proposals,
embeddings, or artifacts; they are not execution-agent decisions.
Operator CLI commands must not format failed Runtime Services envelopes as
successful empty output. models smoke prints per-module status and exits
non-zero when any model envelope is missing_resource or failed; resource and
doctor commands keep resource availability in the report while still surfacing a
non-ok Runtime Services envelope as a CLI error.
User data operations must carry explicit isolation keys. Artifact operations
require namespace; record operations require namespace plus tableName;
vector upsert/search requires tableName. Missing keys are returned as failed
Runtime Services envelopes instead of falling back to a shared default bucket.
The local artifact implementation stores bytes under artifacts/<namespace>/
and keeps only manifest metadata in SQLite (id, namespace, path, MIME type,
size, hash, timestamps, and source metadata). SQLite is not used for vector
storage or retrieval; local vectors are stored and searched through LanceDB
tables named by the caller-provided tableName.
Artifact retrieval is artifact.get by explicit namespace plus id. It
returns the manifest and object bytes as bodyBase64; SQLite remains the
manifest/RDS-style metadata store and does not store artifact bodies.
Record storage is exposed as record.upsert/get/query/delete for JSON metadata
records. Each call uses explicit namespace, tableName, and record id
where applicable; record.query only lists records from one namespace/table in
stable createdAt/id order. A record.query limit of 0 returns an empty
record set. Binary or large object bodies stay in artifact.*.
Vector search can combine similarity with exact top-level metadata prefilters.
Use filter.metadata for high-frequency scalar constraints such as source,
project, kind, or tenant labels. Values are limited to strings, finite numbers,
and booleans; nested JSON filters, raw SQL predicates, null semantics, range
queries, and boolean expression DSLs are intentionally outside P0.
Start the local service, then run or adapt the TypeScript sample in
examples/client-sample.ts:
agent-runtime-services serve --host 127.0.0.1 --port 8765The sample uses createRuntimeServicesRpcClient with
http://127.0.0.1:8765/rpc, calls capabilities.describe for agent-facing
discovery, then exercises model, artifact, record, vector, and
resources.list/doctor/smoke/status flows through the public RPC surface.
Consumers that want the typed RuntimeServices shape over RPC can use
createRuntimeServicesRpcRuntime({ endpoint }). Lower-level callers can use
createRuntimeServicesRpcClient({ endpoint }) and call capability ids directly.
For upstream domain-agent and build-agent integration, use the pasteable sample
in examples/upstream-agent-sample.md. It shows the shared RuntimeServicesPort,
local /rpc adapter, and the deferred /mcp boundary that keeps future remote
exposure separate while sharing the same internal Runtime Services
capabilities.
Consumer agents that need to discover and judge available capabilities should
read examples/consumer-agent-capability-guide.md. It documents the startup
sequence through health, version, capabilities.describe, and
resources.status. Consumers can compare capabilityRevision from /rpc
responses to detect public capability changes online without reading this
repository, then refresh their local capability cache.