OpsPilot is a code-first, safety-oriented operations agent implemented in Go. Its core runtime stays provider-neutral while adapters integrate with the Volcengine AI ecosystem.
Status: early development. The project includes a bounded Agent Runtime, an Ark Responses API adapter, an MCP stdio server, privacy-safe runtime events, optional OpenTelemetry tracing, and machine-readable, read-only network, Docker, Kubernetes, Prometheus, and Loki diagnostics.
- Go-first runtime suitable for containers, Kubernetes, OpenClaw, Hermes, and other agents.
- Volcengine Ark, VikingDB, AgentKit, and VKE integrations behind replaceable interfaces.
- Read-only diagnostics by default; state-changing operations require explicit policy and approval.
- Structured JSON inputs and outputs for reliable agent-to-tool communication.
- Timeouts, step limits, tests, and observable execution rather than prompt-only safety.
- Provider-neutral agent loop with bounded steps and structured tool errors.
- Volcengine Ark Responses API adapter through CloudWeGo Eino
agenticark. - Official MCP Go SDK stdio server backed by the same tool registry as the CLI and Agent Runtime.
- Strongly defined tool registry with duplicate and schema validation.
- Read-only
dns_lookup, SSRF-awarehttp_probe, and certificate-awaretls_inspecttools. - Read-only Docker Engine, container-list, and redacted container-inspect diagnostics over a local Unix socket.
- Read-only Kubernetes server, node, Pod-list, and redacted Pod-inspect diagnostics through client-go v0.36.2.
- Read-only Prometheus build/runtime, active-target, and constrained metric-snapshot diagnostics through fixed
/api/v1endpoints. - Read-only Loki readiness, build-info, and constrained stream-summary diagnostics without reading log lines.
- Shared network guard that resolves and validates every dial target before connecting.
- Machine-readable CLI intended for agents and automation.
- JSONL lifecycle events with run IDs, step numbers, durations, and sanitized error classes.
- Optional OTLP/HTTP traces for Agent runs, model calls, and tool executions.
- Configuration validation and provider-error secret redaction.
OpsPilot tracks the latest stable Go toolchain. The current baseline is Go 1.26.5.
go version
go mod tidy
go test ./...
go build ./cmd/opspilotCopy .env.example into your preferred secret-management workflow and provide at least:
export ARK_MODEL_ID='ep-xxxxxxxxxxxxxxxx'
export ARK_API_KEY='your-api-key'ARK_THINKING accepts auto, enabled, or disabled. Credentials are read from the environment and must not be committed.
go run ./cmd/opspilot agent run \
'Check Kubernetes Pods, Prometheus targets, and Loki stream availability.'The command writes the final structured result to stdout. The Ark model can select from the registered read-only tools.
go run ./cmd/opspilot agent run --events=jsonl \
'Inspect example.com.' \
2>events.jsonlJSONL events are written to stderr, so agents can consume the final result from stdout independently. Events intentionally omit prompts, tool arguments, tool results, credentials, and raw provider errors.
export OPSPILOT_OTEL_ENABLED=true
export OTEL_SERVICE_NAME=opspilot
export OTEL_EXPORTER_OTLP_ENDPOINT='http://localhost:4318'
go run ./cmd/opspilot agent run 'Inspect example.com.'The OTLP/HTTP exporter follows standard OpenTelemetry environment variables. Telemetry initialization or shutdown failures do not fail the diagnostic run.
Build the binary and expose the registered read-only tools over stdio:
go build -o ./bin/opspilot ./cmd/opspilot
./bin/opspilot mcp stdioA typical MCP client configuration is:
{
"mcpServers": {
"opspilot": {
"command": "/absolute/path/to/opspilot",
"args": ["mcp", "stdio"],
"env": {
"OPSPILOT_HTTP_ALLOW_PRIVATE": "false",
"OPSPILOT_TLS_ALLOW_PRIVATE": "false",
"OPSPILOT_DOCKER_SOCKET": "/var/run/docker.sock",
"OPSPILOT_KUBECONFIG": "/absolute/path/to/kubeconfig",
"OPSPILOT_KUBERNETES_CONTEXT": "production-readonly",
"OPSPILOT_PROMETHEUS_URL": "https://prometheus.example.com",
"OPSPILOT_PROMETHEUS_BEARER_TOKEN_FILE": "/absolute/path/to/prometheus-token",
"OPSPILOT_LOKI_URL": "https://loki.example.com",
"OPSPILOT_LOKI_BEARER_TOKEN_FILE": "/absolute/path/to/loki-token",
"OPSPILOT_LOKI_TENANT_ID": "operations"
}
}
}
}The server publishes each Registry tool with its existing JSON Schema and explicit read-only/idempotent annotations. Tool results are returned as text and, when the result is a JSON object, as MCP structured content. stdout is reserved exclusively for MCP protocol frames; warnings and failures go to stderr.
go run ./cmd/opspilot tool list
go run ./cmd/opspilot tool run dns_lookup \
'{"host":"example.com"}'
go run ./cmd/opspilot tool run http_probe \
'{"url":"https://example.com"}'
go run ./cmd/opspilot tool run tls_inspect \
'{"host":"example.com","port":443}'
go run ./cmd/opspilot tool run docker_engine_info '{}'
go run ./cmd/opspilot tool run docker_container_list \
'{"all":true,"limit":100}'
go run ./cmd/opspilot tool run docker_container_inspect \
'{"container":"web"}'
go run ./cmd/opspilot tool run kubernetes_cluster_info \
'{"node_limit":100}'
go run ./cmd/opspilot tool run kubernetes_pod_list \
'{"namespace":"operations","limit":100}'
go run ./cmd/opspilot tool run kubernetes_pod_inspect \
'{"namespace":"operations","pod":"web-0","event_limit":50}'
go run ./cmd/opspilot tool run prometheus_server_info '{}'
go run ./cmd/opspilot tool run prometheus_target_list \
'{"limit":100}'
go run ./cmd/opspilot tool run prometheus_metric_snapshot \
'{"metric":"up","matchers":{"job":"node"},"aggregation":"sum","group_by":["instance"],"limit":100}'
go run ./cmd/opspilot tool run loki_server_info '{}'
go run ./cmd/opspilot tool run loki_stream_summary \
'{"matchers":{"namespace":"operations","service_name":"api"},"lookback_minutes":60,"limit":100}'OPSPILOT_DOCKER_SOCKET defaults to /var/run/docker.sock. It accepts an absolute filesystem path or a unix:///absolute/path URI. Remote tcp://, http://, https://, ssh://, and relative targets are rejected.
The Docker client negotiates the daemon API through /version, then performs bounded GET requests. It does not invoke the Docker CLI and does not expose mutating operations.
docker_container_inspect returns a deliberate diagnostic projection rather than raw docker inspect output. It omits environment values, commands, arguments, raw labels, health-check output, Docker log paths, bind-mount and volume source paths, and free-text OCI/runtime errors.
Engine warning text is also omitted; only warning_count is returned. Container runtime errors are represented by error_present without returning the raw text.
Access to a Docker Unix socket is still a privileged host capability. OpsPilot's read-only implementation does not turn the socket itself into a read-only security boundary. Only grant the process access to a trusted local socket, and do not mount that socket into untrusted containers.
OpsPilot uses the official Kubernetes client-go v0.36.2. Kubernetes configuration is initialized lazily, so missing credentials do not prevent non-Kubernetes tools or the MCP server from starting.
When running outside a cluster, set OPSPILOT_KUBECONFIG to an absolute kubeconfig path. OPSPILOT_KUBERNETES_CONTEXT optionally selects a context. When running inside Kubernetes without an explicit kubeconfig, OpsPilot uses the mounted ServiceAccount token and CA.
Before constructing a Kubernetes client, OpsPilot rejects kubeconfigs that contain HTTP API servers, insecure-skip-tls-verify, proxy URLs, exec credential plugins, legacy auth-provider plugins, or user impersonation.
The model cannot provide a kubeconfig path, API server URL, arbitrary resource type, selector, API path, or HTTP method in tool arguments.
kubernetes_pod_inspect returns a deliberate projection rather than a raw Pod object. It omits environment values, commands, arguments, labels, annotations, volume source details, Secret and ConfigMap references, Pod logs, and all free-text condition, container-state, Pod-status, and Event messages. Event output is aggregated by type and reason only.
Apply the included minimum RBAC objects for an in-cluster deployment:
kubectl apply -f deploy/kubernetes/opspilot-readonly-rbac.yamlThe role grants GET on /version, GET/LIST on Nodes and Pods, and LIST on Events. It does not grant Secret access or the pods/log subresource.
Set OPSPILOT_PROMETHEUS_URL to the trusted Prometheus base URL. HTTPS is required by default. Internal HTTP endpoints require the explicit OPSPILOT_PROMETHEUS_ALLOW_HTTP=true opt-in. Optional bearer authentication uses an absolute path in OPSPILOT_PROMETHEUS_BEARER_TOKEN_FILE; the token is read for each request to support rotation and is never returned.
The client disables ambient proxies and redirects, requires TLS 1.2 or newer for HTTPS, bounds response bytes and timeouts, and only calls fixed read-only /api/v1 endpoints. It does not expose configuration, flags, rules, alerts, label enumeration, series enumeration, admin APIs, or arbitrary paths.
prometheus_metric_snapshot does not accept raw PromQL. OpsPilot generates a bounded instant query from a validated metric name, up to eight exact-match diagnostic labels, one of none, sum, avg, min, max, or count, up to five grouping labels, and a hard series limit. Query parameters are submitted in a POST form rather than the URL.
Prometheus output is projected before it reaches the Agent. Scrape URLs, discovered labels, arbitrary target and metric labels, target error text, runtime hostname and working directory, API warning/info text, and raw server errors are omitted. Only warning and info counts are retained.
Set OPSPILOT_LOKI_URL to a trusted Loki base URL. HTTPS is required by default. Internal HTTP requires OPSPILOT_LOKI_ALLOW_HTTP=true. Optional bearer authentication uses an absolute token file, and multi-tenant deployments may set one validated OPSPILOT_LOKI_TENANT_ID.
The client disables ambient proxies and redirects, requires TLS 1.2 or newer for HTTPS, and only calls /ready, /loki/api/v1/status/buildinfo, and POST /loki/api/v1/series. It does not expose log lines, arbitrary LogQL, query/query-range, tail, labels or label-value enumeration, push, delete, config, metrics, rings, rules, arbitrary paths, or arbitrary methods.
loki_stream_summary requires at least one exact-match label from a fixed diagnostic allowlist. Lookback is limited to 1–360 minutes, result count is limited to 1–500, and the selector plus timestamps are sent in a POST form rather than the URL. Returned streams are projected, deduplicated, deterministically sorted, and locally truncated. Unknown labels, file paths, and log content are omitted.
Private, loopback, link-local, multicast, and unspecified HTTP/TLS targets are blocked by the generic network tools by default. Prometheus and Loki use explicitly configured trusted endpoints and do not accept URLs from tool arguments.
- MCP client support and richer Agent skill packaging.
- PostgreSQL task state and VikingDB retrieval.
- Approval gates and policy evaluation for state-changing operations.
- AgentKit/VKE deployment and production evaluation.
See docs/architecture.md for the initial boundaries.