Skip to main content

openclaw-ops — "Jarvis", the read-only infrastructure investigator

Jarvis is a dedicated, read-only ops bot for the Scanners platform. You @-mention it in a Slack alert thread and it investigates that alert against live AWS state plus a curated knowledge base of the platform, then posts a structured finding back in the thread. It can investigate and recommend — it can never act.

:::info Status Live in production (ECS Fargate, eu-north-1, account 429134227608). It runs as a 2-container service in the scanners cluster. See also Monitoring & Alerting and Logging & SIEM. :::

How it works (behaviour)

On-demand, mention-gated — not auto-investigate

Jarvis does not investigate every incoming alert. It stays silent until the owner explicitly @-mentions it in a thread. Two independent gates in the Slack channel config enforce this:

  • allowBots: "mentions" — bot-authored messages (Grafana, AWS Chatbot) reach Jarvis only if they @-mention it, which alerts never do, so an incoming alert never auto-triggers an investigation.
  • requireMention: true on all five alert channels — even a human message triggers Jarvis only when it @-mentions the bot.
  • groupPolicy: "allowlist" + allowFrom — only the owner can summon it.

When tagged, the reply is threaded under the message you tagged, and the alert text above is readable as context (allowBots gates inbound dispatch, not thread-history reads).

What a single investigation does

  1. You reply in an alert's thread: @Jarvis what's going on here?
  2. Jarvis treats the alert/log text as untrusted data, never instructions.
  3. It reads the alert metadata literally first (e.g. DatasourceNoDataDatasourceError), then gathers evidence with its read-only AWS tools and the check_loki probe — always confirming live state, never trusting memory.
  4. It produces a structured report: root_cause, severity (Sev1/2/3), confidence, evidence (specific log lines / metric deltas / a preceding deploy), suggested_fix (text only), correlated_alerts.
  5. It posts that as a threaded reply, with secrets/PII redacted from quotes.

Its investigation discipline (symptom ≠ root cause, disconfirm before asserting, don't diagnose what you can't observe, calibrate confidence to evidence) and its platform knowledge base are baked into the image as workspace files (SOUL.md and AGENTS.md).

How it was built (architecture)

Slack (Socket Mode, outbound WSS — no inbound)
│ @mention in a thread (owner only)

ECS Fargate task "openclaw-ops" (cluster: scanners, desired 1)
┌──────────────────────────────────────────────────────────────┐
│ container: openclaw-ops (OpenClaw gateway) │
│ • model: AWS Bedrock EU inference profile (task-role auth) │
│ • persona + KB: SOUL.md + AGENTS.md │
│ • tools: DENY-LIST (exec/fs/automation/... denied) │
│ │ localhost HTTP (127.0.0.1:8000) │
│ ▼ │
│ container: aws-readonly-mcp (FastMCP sidecar) │
│ • 9 read-only tools (boto3 + the Loki probe) │
│ • keeps the TASK-ROLE creds natively │
└──────────────────────────────────────────────────────────────┘
│ read-only AWS APIs │ HTTP GET (read) to Loki :3100
▼ ▼
CloudWatch · Logs · ECS · Loki on the private Grafana box
RDS · ElastiCache (auth-less, in-VPC)

Key decisions:

  • Official, pinned OpenClaw, fully locked down. Built FROM the official, pinned image (MIT). Only our MCP server + locked-down config + SOUL.md / AGENTS.md are added; the two official plugins used (Slack channel + Amazon Bedrock provider) are installed at build time. No community/ClawHub plugins, no runtime code pulls.
  • Model = AWS Bedrock, no API key. Claude runs via the EU cross-region inference profile, authenticated by the ECS task role through the AWS SDK chain — there is no Anthropic API key to store. (Claude 4.x has no on-demand model in eu-north-1, so the inference profile is required.)
  • AWS access is ONLY the MCP sidecar. All AWS reads go through a small FastMCP server (read APIs only, log redaction). It runs as a second container over localhost HTTP — not a gateway-spawned subprocess — so it keeps the ECS task-role credentials natively.
  • Tools are a deny-list. exec hard-denied, elevated off, filesystem / automation / browser / cron / gateway / nodes denied. What remains is read + web-search + the read-only MCP tools.

:::note The check_loki probe Jarvis's AWS tools see CloudWatch/ECS/RDS/Redis but not Loki/Grafana — so it used to guess "the log pipeline is broken" from a Grafana DatasourceNoData alert. check_loki closes that blind spot: it hits Loki directly (/ready, /labels, count_over_time for the alert's stream + heartbeats) and returns reachable / ready / match_count / heartbeat_count, so Jarvis can confirm whether Loki is down vs simply empty. The Grafana box SG allows port 3100 ingress from the openclaw-ops task SG; Jarvis has only a read (GET) tool, no push. :::

Security model

CAN ✅CANNOT ❌
Read AWS via the read-only MCP server onlyWrite / modify / delete anything
Read Loki (GET) via check_lokiPush to Loki / change Grafana
Search the web for knowledgeExecute code / shell
Post threaded Slack repliesPull/install external or community code
Run only the curated investigator agentTouch filesystem / cron / browser / gateway / nodes

Two enforcement layers: the OpenClaw config and a dedicated read-only IAM task role (allow-list + explicit Deny) — the hard backstop that physically denies every write even if an alert carries attacker-controlled text. Alert text is treated as untrusted input; no action tool is ever wired in; the alert channels are private and quoted excerpts are redacted before they leave the bot.

The 9 read-only tools

list_alarms, get_metric_stats, query_logs, list_log_groups, describe_services, service_events, describe_rds, describe_redis, and check_loki. Every function calls only read APIs, and the IAM role denies writes regardless.

How to use it

As an operator (the normal path): an alert lands in a #alerts-* channel and Jarvis stays silent. Reply in that alert's thread, mentioning the bot — @Jarvis is this real? what's the root cause? — and it investigates and replies in the thread. Only the owner can trigger it.

Read Grafana / Loki yourself: the box has no inbound path; tunnel in via AWS SSM Session Manager port-forwarding (port 3000 for Grafana, 3100 for ad-hoc Loki) — see Monitoring & Alerting.

What's deferred (deliberately)

  • Sev1 → WhatsApp paging — disabled for now (needs a paired WhatsApp session); on-call number on file. Enable in a follow-up if paging is wanted.
  • Vector-RAG + growing incident-history store — not built and not needed pre-launch: the curated SOUL.md + AGENTS.md knowledge base is sufficient at current scale, and an incident-write path would conflict with the read-only guarantee. Revisit once there is real incident volume.