API and usage
How admin exposes its capabilities — feature-gated HTTP routes and the one typed agent-core adapter — without shipping any tools or commands.
@neuralis/admin is unusual among the builtin packages: it ships no tools
and no commands. Its entire programmatic surface is its set of HTTP
routes — nineteen feature-gated route patterns —
plus exactly one narrow typed adapter it uses to read from
@neuralis/agent-core. Everything an administrator (or an admin skill, or the
Admin widget) can do passes through that route surface; nothing about admin is
hardcoded into the host.
If you are looking for the route-by-route table — every pattern, method, feature, and what it returns or mutates — that lives on Features and routes. This page is the higher-level shape: how the surface is organized, why it is routes rather than tools, and the single rule about how admin reaches agent-core.
No tools, no commands — routes are the API
Most packages put model-facing capabilities in tools/*.json (schema-first,
dispatched to a handler) and operator shortcuts in commands/*.json. admin has
neither folder. Its capabilities are privileged operations — read platform
usage, edit a role, set a credential, reset the vector store — that should be
exercised through authenticated, feature-gated, scope-aware HTTP requests, not
offered to the model as free-floating tools.
The package therefore declares only routes (discovered from src/routes/*.ts),
a singleton widget surface with its dock companion, six management skills, one
workflow template, and the declarative rest — a privileged source instance, its
uri-policy baselines, and two platform config settings.
The six skills are the model-facing layer: an agent operates the platform by
activating a skill whose scripts call these same routes with the per-stream
session ticket — never by calling a bespoke admin tool. See
Skills.
Every route module exports a pattern and a feature. The package route
dispatcher checks that feature server-side against the caller's granted
features before the handler runs; the general mechanism is described in
Routes. Because there is no tool surface, the
feature string on each route is the access boundary for that capability.
The route surface, grouped by capability
The admin routes fall into eleven capability groups. Each group is gated by a
feature, and each route reads userId / projectId (and, where relevant,
agentId) from the verified session — never from caller-supplied identity.
| Group | Routes | Gate |
|---|---|---|
| System overview | health, dashboard/stats, dashboard/usage, dashboard/codex-savings, packages, streams, projects / projects/:id | project.dashboard |
| Members | users | project.members |
| Logs | logs, logs/sources | project.audit (every platform-rooted source re-checks platform.audit in-handler: audit, routes, and a first-party package's own logs — system, sync, vector, and package/pkg with a bare slug; a project-installed _installed/<slug> log and the per-agent run log stay project-tier) |
| Platform audit | audit | platform.audit (no default grant — the log carries no project id, so the module feature is platform-tier and there is no second in-handler gate) |
| Roles & sources | config/roles, sources | project.roles / project.sources |
| Platform config | config, vector/status | platform.config / platform.vector |
| Package ops | cache/clear, rescan | packages.manage (live grant re-derived per call) |
| Credentials | credentials (read), credentials/scope-targets (the scope picker's target list), credentials/:id (write), credentials/use and credentials/use/:id (the platform-global use rules) | project.credentials / platform.scope / project.credentials.write |
| Vector reset | vector/reset | platform.vector.reset (no default grant) |
| Canvas | canvas/graph, canvas/agent/:id, canvas/user/:id | project.canvas |
| Governance | members-invite, projects-create, agents-assign, agents-admin/:id | project.members.invite / platform.projects.create / project.agents.assign / core.agents — every one of them stacks a second floor the feature alone does not satisfy: a role flag (canInvite, canManageRoles), an owner-strength check, or agent-core's own per-agent access check |
The full table — with HTTP methods, exact return shapes, the in-route privilege
escalations (for example dashboard/usage requiring platform.projects for
scope=platform or platform.users for groupBy=user), and the mutation
effects — is documented on
Features and routes.
Feature-gated and scope-aware
Two independent dimensions govern every admin route:
- Feature gating. The route's exported
featureis checked before its handler runs.project.dashboardis granted to every role by default (so any member can open the system overview), but everything beyond the baseline overview must be granted explicitly. Theownerrole holds the'*'wildcard and passes every gate; theadminrole holds every project-tier feature explicitly. Noplatform.*feature has a default grant. See Features and access. - Scope awareness (PROJECT vs PLATFORM). Most routes operate against the
session's project and refuse to fan out across projects on a missing
scope (deny-by-default — for example
sourcesreturns400rather than listing every project's sources). Crossing from the project tier to the platform tier is exactly what theplatform.*features authorize, one power per id: all-projects listings (platform.projects), per-user spend (platform.users), the platform-global audit source (platform.audit), and acting on someone else's scope (platform.scope). A route can therefore serve a project-scoped answer to a baseline caller and a platform-wide answer to a caller who holds the matching id, from the same endpoint, degrading gracefully by privilege.
This mirrors the PROJECT / PLATFORM split in the Admin widget's own sidebar: the UI shows the platform section only to callers whose grants pass the platform-tier gates, but the client-side hiding is a convenience — the server-side feature check is always authoritative. See UI.
Reaching agent-core: one typed adapter, never bypassed
Several admin routes need data that lives in @neuralis/agent-core — active
agent streams, connector status, the MCP server list, and usage aggregates for
the dashboard charts. Per the platform's
direct-internal-API rule, cross-package calls go through
typed package APIs (getPackageApi()), never through internal MCP calls.
admin funnels its entire agent-core dependency through one small adapter,
src/agentCoreApi.ts. It is a narrow structural mirror of just the members
admin reads:
usageStore.summarizeProject(projectId)— all-time totals for a project.usageStore.aggregate(filter)— the time-bucketed series behind the usage charts (the caller passes an explicitprojectIdsallow-list, so cross-project scope is always a deliberate decision, never implicit).usageStore.projectSpan(projectId)— earliest/latest recorded event, used to size the all-time chart window dynamically.listConnectorInstances()— connector status counts.listMcpServers(session)— the MCP server list for the dashboard and canvas.getActiveStreams()— running agent streams (every consumer filters by the session'sprojectId).agentService.delete(...)— the agent delete behindDELETE agents-admin/:id. Access is re-checked inside agent-core against the caller's real session; the admin route adds transport and an audit row, never authority.listCodexSubscriptions()— the connected Codex subscription snapshots (one per credential scope) behind the codex-savings card.refreshCodexUsage(session)— one fail-soft live refresh of the caller's own Codex usage scope, derived from the verified session; it never impersonates another user or project, and a failed upstream read falls back to the stored snapshot rather than erroring.
Every route that reads agent-core runtime state — the dashboard, streams and
canvas handlers and the agent delete — goes through
getAgentCoreAdapter(); nothing reaches into agent-core internals directly.
Package maintenance uses ctx.hostPorts.packageMaintenance directly: the
rescan and cache/clear routes pass the verified session's user/project ids,
require packages.manage, and audit each operation. The host rechecks current
package-management permission per call. A missing port returns503.
The silent-zero lesson
Every admin route and every admin test stub must use this adapter type.
A 2026-06 dashboard regression made Usage, Connectors, MCP, and stream counts
all silently read 0: the routes — and their test mocks — both invented
methods (getUsageStore(), getConnectorRegistry(), getMcpClientManager())
that the real agent-core API never had, and optional chaining swallowed the
mismatch into a misleading zero instead of an error. The fix was the single
typed adapter, used everywhere, so a member-name drift fails loudly instead of
degrading to zero. Do not add a second path to agent-core, and do not wrap the
adapter calls in a catch that turns a genuine mismatch back into a zero.
Brain-core is reached the same way (through getPackageApi('@neuralis/brain-core'))
for source health and the single validated upsertSourceConfig mutation point —
the sources route never writes source JSON directly. The credential catalog
uses the same narrow typed-shape form to ask agent-core which credential ids the
loaded packages, skills and project channel connections declare — ids and
labels only, never values.
Where admin sits among the three reach-paths
admin is an installed, first-party, in-process package, so its routes and
handlers run as native Node and are dispatched directly — the richest of the
three ways a package can reach the platform. The other two paths (a
WASM-sandboxed project _packages/ drop, and context-only source markdown)
expose narrower runtime surfaces. The
package-system overview is the public owner of the
full reach-path parity matrix; admin's route + adapter surface is the
first-party, in-process row of it.