Skills
Six management skill bundles that let an agent operate the platform.
The admin package ships six skill bundles under its skills/ folder. Each is
a standard agentskills.io-aligned directory — a
SKILL.md with YAML frontmatter plus a scripts/ folder — activated through
the execute tool like any other skill (see
Skills). Together they make the entire
administrative surface scriptable by an agent: the same routes the dashboard
UI calls, wrapped in small shell scripts.
Authentication
Every script authenticates with the per-stream session ticket
(NEURALIS_SESSION_TOKEN), injected into the script environment at skill
activation. The ticket carries the caller's real identity — user, project,
role, granted features — and the model never sees its value. Each admin route
then enforces its declared feature server-side against that real identity,
deny-by-default. The prefix is the tier: a project.* id acts inside the
session project and reaches a project admin, while a platform.* id crosses
the project boundary and carries no default role grant, so it is
owner-strength unless an owner grants it explicitly. Scripts also send an
X-Neuralis-Skill header so audit events name the calling bundle. See
Sessions for the full mechanism.
Visibility
Each bundle declares requiredFeatures in its frontmatter, mirroring the
strongest route feature its scripts hit. A caller whose role lacks the
feature does not merely fail at execution time — the skill is never listed,
never injected into the system prompt, and not activatable at all. The
frontmatter declares the WEAKEST set that makes a bundle useful, so a bundle can
be visible while an individual script is refused — each script's own route
feature is the execution backstop. Since default role grants give non-admin
roles only project.dashboard, these bundles are invisible to ordinary member
streams.
The six bundles
| Bundle | Requires | What it does |
|---|---|---|
inspect-admin | project.audit, project.canvas, project.dashboard | Read-only diagnostics: logs, stats, usage, health, canvas (every platform-global source — the audit and route logs and the first-party packages' own file logs — additionally needs platform.audit) |
manage-platform-config | project.roles | Role map read (write needs the role-management flag); platform settings and vector status additionally need platform.config / platform.vector, the reset platform.vector.reset, and the embedder check both platform.vector and the filesystem search feature |
manage-projects-and-users | project.dashboard, project.members | Read-only inventory of your projects and their members |
create-projects-and-users | project.members.invite | Invite a user into the current project, create a new project, assign an agent to a member (each route stacks its own flag/strength floor) |
manage-cache-and-rescan | packages.manage | Cache clear and package rescan operations |
manage-credentials | project.credentials, project.credentials.write | Credential catalog plus scope-aware set/delete (a scope outside your session needs platform.scope) |
inspect-admin
Eleven read-only scripts covering every diagnostic route: audit events, package
and agent logs, log sources, dashboard stats, bucketed usage series, the health
probe, the Codex-savings series, active agent streams, the whole-organization
canvas graph, and per-agent / per-user canvas detail.
Optional environment variables tune the queries — SOURCE and LIMIT for logs
(plus PACKAGE_ID / AGENT_ID, which the per-package and per-agent sources
require) and LAST for audit; RANGE, GROUP_BY, SCOPE for usage (subject
to the same platform.projects / platform.users escalations as the route
itself); AGENT_ID / USER_ID
for the per-entity canvas scripts. There is no level filter on the API — the
Logs tab filters by level in the browser, over entries the route already
returned.
manage-platform-config
Nine scripts wrapping the config, source-config and vector routes: read and
patch the platform config, read and patch the role catalog, read and patch
this project's source configs, probe the vector store, reset it, and check
whether the configured embedder is actually answering. The reset
script requires the explicit RESET confirmation phrase, exactly like the
route it wraps. Useful for backing up config before a change, toggling
registration, or rotating role grants in bulk without opening the UI.
The embedder check is the one script in this bundle that crosses into another package's route: a semantic search is already the path that builds the real embedder and runs a real embedding, so it is the probe rather than a new endpoint. It therefore passes two gates in two packages, and reports a permission refusal as an explicit "blocked by <feature>" verdict instead of claiming the embedder is dead.
Two of those bodies replace rather than merge, and both examples in the
skill are read-then-resend round-trips for that reason: config/roles takes
the project's whole role map (a role you omit is deleted — and the read
returns an array of {name, definition} while the write wants a map keyed
by name), and sources replaces a source's whole permissions object.
Hand-writing either body succeeds with 200 and silently discards whatever
it left out.
manage-projects-and-users
Read-only inventory: list all projects with counts, and fetch one project's
detail (members and roles, PROJECT_ID required). The third script is a
discovery stub rather than a listing — it returns a pointer to the host's user
surface ({ href, mutable: false }), not a list of users, because user
inventory and lifecycle live on the host admin API and not in this package.
The mutations live in the sibling create-projects-and-users bundle.
create-projects-and-users
The mutation counterpart: invite-user.sh (EMAIL, NAME, optional ROLE)
invites a new user into the session project; add-project.sh (NAME,
optional DESCRIPTION) creates a new project; assign-agent.sh (AGENT_ID,
USER_ID, optional REMOVE=true) assigns or unassigns an agent to a member.
Each route stacks a second floor beyond its feature — the invite needs the
role's invite flag and caps the assigned role at the caller's strength,
project creation is owner-strength only, and assignment needs the
role-management flag (the same gate the Agents tab's save carries).
Passwords never pass through this path in either direction: an invite creates
the platform account without a usable first password, the response says
passwordDelivery: "admin-ui-reset", and an operator sets the first password
via the Users tab Reset password, delivered out-of-band (SSO users never
need one). Denied answers are uniform 403s — an unknown role, a too-strong
role, an unknown agent and a non-member target all answer identically.
manage-cache-and-rescan
Two operations scripts: clear the package caches and trigger a package
rescan. They are really wired to the package runtime — rescan eagerly
re-scans the session project's drop-zone and re-syncs, returning
{ ok, scanned, packageErrors? } (inspect packageErrors for any package
that failed to load); clear-cache is the lazy counterpart that drops the
caches so the next access re-reads disk. Installed packages
(node_modules/@neuralis/*) are read when the host boots; a changed installed
manifest needs a restart, not a rescan. Both act on your session's current
project and re-check the live package-management grant server-side. They
exist to make the host pick up packages dropped into the project's _packages/
folder while it is running; they are normally unnecessary in steady-state
operation.
manage-credentials
List, set, and delete encrypted credentials — the agent-facing counterpart of
the Credentials tab. The catalog lists package-declared, skill-declared, and custom
credential ids with a hasValue flag per scope; stored values are never
returned. A SCOPE variable (with PROJECT_ID / USER_ID / AGENT_ID
defaulting to the session's own scope) targets the platform, project, user,
or agent store, resolved most-specific-wins at use time. SCOPE itself
defaults to global — the platform store — when it is left unset, so pass it
explicitly for a session-scoped read or write. Writes require the
stricter project.credentials.write feature; acting on a scope outside your
own additionally requires platform.scope, which no role holds by default —
see Security. The broader credential model
is covered in Credentials.
Example invocations
From the model's perspective the scripts are plain shell commands rooted at the skill directory:
bash ${SKILL_DIR}/scripts/stats.sh | jq .
RANGE=7d GROUP_BY=agent bash ${SKILL_DIR}/scripts/usage.sh
bash ${SKILL_DIR}/scripts/list-projects.sh | jq '.projects | length'
# A credential write is blind: values are never read back, so this REPLACES
# whatever is stored at that scope. Check `hasValue` with list.sh first, and
# practise the lifecycle on a throwaway id rather than a live one.
ID=SCRATCH_DEMO_TOKEN VALUE=demo-not-a-real-secret SCOPE=project bash ${SKILL_DIR}/scripts/set.sh
ID=SCRATCH_DEMO_TOKEN SCOPE=project bash ${SKILL_DIR}/scripts/delete.shEvery mutating example in a shipped skill follows that rule: it either targets an object created for the example and removed by its own last line, or it says in place why it cannot — a platform-config key and a vector reset are instance-wide singletons with no throwaway equivalent.
Two things decide whether an example is mutating, and neither is obvious from reading the script folder:
- Classify from the invocation line, not the script file. A generic helper
that takes its HTTP verb as an argument — brain-core's
git.sh POST commit …is the shipped example — hides its own verb behind a positional parameter. Keyed on the file, all 18 of its routes look like reads. - A tier marker describes the gate, never the consequence.
platform.scope — expect 403 unless grantedtells you who is allowed to run a line; it says nothing about what lands when they are. The caller who holds the grant is exactly the caller such a marker reads as reassuring to, so a destructive example needs both: the gate and the blast radius, at the point of use.
No credentials: frontmatter is declared by any of the six bundles —
authentication to the host API needs no external secret, because the session
ticket is implicit in every skill activation.