Control Plane Beta
An optional telemetry endpoint and dashboard for inspecting allow/deny decisions from your running Arcis middleware. The SDKs and CLI work fully offline without it. The control plane is currently in beta and under active development; this page describes the design so you can plan integrations.
Beta — under development and testing. The control plane is not generally available yet. APIs may change before the stable release. The middleware works without it — telemetry is strictly opt-in. This page documents the current shape so you can preview the integration; check the release notes for the general-availability announcement.
What it is
The control plane is a small backend + dashboard that receives the security events your Arcis middleware emits in production. It shows you:
- What attacks were blocked, by vector and by route
- Per-IP request patterns over time
- Top offenders, top targeted endpoints, top attack categories
- Supply-chain scan results uploaded from
arcis scain CI - Audit findings uploaded from
arcis audit - The current health and version of each Arcis SDK instance in your fleet
It is not required to use Arcis. The SDK middleware makes its own allow/deny decisions locally; the control plane is observability on top.
Architecture
- Ingest service. A small Fastify server with a SQLite backing store, exposing
POST /v1/eventsfor the SDKs. Suitable for a single machine; an event-store driver abstraction sits underneath so larger deployments can swap in Postgres when GA lands. - Dashboard UI. A React + TanStack Router single-page app served by the ingest service. Visualizations for events, findings, fleet health, and intel feed.
- Auth. Per-workspace tokens issued by
arcis login. Tokens scope events to a workspace and prevent cross-tenant data leaks.
Everything runs on infrastructure you control. The control plane is designed to be self-hostable end to end; there is no requirement to send your data to any third party.
When it makes sense
- You run Arcis in production and want a visual record of what was blocked.
- You want CI to upload audit/SCA findings centrally so they show up next to the runtime events from the same workspace.
- You want to spot scanner activity across your fleet without grepping logs from N hosts.
If you only need local protection without a dashboard, skip this entirely. app.use(arcis()) works without any control-plane configuration.
Environment variables
Three variables wire the SDK middleware up to a control plane. Drop them in .env; the middleware reads them on startup.
| Variable | Purpose |
|---|---|
ARCIS_ENDPOINT | HTTPS URL of the ingest service (e.g. https://arcis.your-company.internal). |
ARCIS_WORKSPACE_ID | UUID of the workspace this app belongs to. Created in the dashboard. |
ARCIS_KEY | API key issued by arcis login against the control plane. Scoped to a workspace. |
No env vars set, no telemetry sent. The SDK middleware checks for these on startup. If any are missing it runs in local-only mode and never opens a connection. There is no fallback endpoint, no phone-home behavior, no anonymous metrics.
arcis login
The CLI command for issuing a workspace-scoped API key.
# Authenticate against your control plane
arcis login --endpoint https://arcis.your-company.internal
# Now arcis sca and arcis audit can upload results to the dashboard
arcis sca . --upload
arcis audit . --upload
The login flow is browser-based: arcis login opens a URL in your browser, you authenticate against your control plane, and a short-lived token is written to ~/.arcis/credentials.json. Long-lived API keys for CI are issued from the dashboard.
Event shape
The SDKs emit one event per allow/deny decision. The shape (subject to change before GA):
{
"workspace_id": "5f6c2...",
"app_id": "web-api-prod",
"sdk": "@arcis/node",
"sdk_version": "1.6.0",
"decision": "deny", // "allow" | "deny"
"vector": "xss",
"rule": "patterns.xss.script-tag",
"matched": "<script>...", // truncated, never the full payload
"route": "/api/comments",
"method": "POST",
"ip_hash": "a91b...", // hashed by default; raw IP opt-in
"timestamp": "2026-05-21T14:22:15Z"
}
The middleware batches events client-side and POSTs them with a bounded queue. If the ingest service is down, events drop oldest-first rather than blocking the request path or filling memory. Pattern 4 (fail-open on infrastructure errors) applies here too.
Privacy posture
- Payloads never sent in full. The
matchedfield is truncated to the first 80 characters of the offending substring. Request bodies are not transmitted. - IPs are hashed by default. Raw IP transmission is an explicit opt-in (
raw_ip: truein the middleware config) for teams that need it for incident response. - You own the data. Self-host the control plane and the database stays on infrastructure you control. No third party in the path.
Dashboard surfaces
The web UI that ships with the ingest service has these top-level surfaces:
- Overview — events / day, top vectors, top routes, top offenders.
- Events — paginated, filterable feed of every allow/deny decision.
- Findings — uploaded results from
arcis auditandarcis sca, grouped by repo. - Fleet — every Arcis SDK instance in the workspace, last-seen version, last-seen event.
- Intel — supply-chain advisories that match anything in your fleet's lockfiles. CVSS scoring + remediation links.
- Settings — workspaces, API keys, custom rules, sharing, environments.
Uploading CI results
When the control plane is configured, arcis sca and arcis audit can upload their JSON output into the dashboard:
# In your CI pipeline
export ARCIS_ENDPOINT=https://arcis.your-company.internal
export ARCIS_KEY=${{ secrets.ARCIS_KEY }}
export ARCIS_WORKSPACE_ID=${{ vars.ARCIS_WORKSPACE_ID }}
arcis sca . --upload --sarif
arcis audit . --upload --sarif
Without these env vars the same commands write SARIF to stdout for GitHub Code Scanning as usual; --upload additionally POSTs the result to POST /v1/findings.
Roadmap
- Status today. Beta. APIs may change. Documentation is being built out as features stabilize.
- What is stable. The event ingest shape, the env-var contract, the basic dashboard surfaces (events / findings / fleet).
- What is moving. Custom rules, sharing tokens, the intel feed UI, alerting integrations.
Want early access? Open an issue at github.com/Gagancm/arcis/issues with the label control-plane. The control plane has a separate release cadence from the SDKs; this docs page will get the announcement when it goes GA.
Using Arcis without the control plane
Arcis works fully without a control plane. The SDK middleware makes its own decisions locally, and the CLI runs entirely offline (except arcis sca --osv). If you want a log of decisions, configure your normal Node / Python / Go logger to capture from arcis events:
// Node example: subscribe to allow/deny events without a control plane
import { arcis } from '@arcis/node';
app.use(arcis({
block: true,
onDecision: (event) => {
logger.info('arcis decision', event);
},
}));