Skip to main content
Glama
AndersonVitaease

MemoryOS VPS Guardian

README.md
# MemoryOS VPS Guardian

> Give AI responsibility for your VPS — not unrestricted shell access.

Open-source, read-only MCP tools for VPS health, capacity, change observation, incident summary, deployment state, application health, deployment readiness, Docker container health, why-down signal synthesis and log signal explanations — designed so AI agents do not need unrestricted SSH or shell access.

## What is MemoryOS VPS Guardian?

MemoryOS VPS Guardian is a public MCP (Model Context Protocol) server for observing and understanding server state. Instead of handing an AI agent a raw shell, it exposes goal-oriented tools that return structured, evidence-based answers to practical operational questions such as:

- Is my application healthy?
- Is my VPS healthy?
- Why is something down?
- Is my deployment working?
- Is it safe to deploy right now?
- What changed recently?
- Are my containers healthy?
- What do these log errors mean?

## Why it exists

AI agents are increasingly used to operate infrastructure. Giving them unrestricted shell or SSH access is risky: a single wrong command can take production down, and audit trails become opaque. This project exists to narrow that gap with a small, auditable set of tools that answer operational questions and perform only explicitly bounded, validated operations.

## Key principle: goal-oriented safe tools instead of unrestricted shell

- Each tool answers one specific operational goal, not arbitrary power.
- All ten public Simple Tools are read-only; no mutation path exists in the current public tool set, and any future mutation path would be explicit, allowlisted and validated.
- Deterministic evidence comes first; interpretation is layered on top and must never fabricate findings.

See [docs/SECURITY-MODEL.md](docs/SECURITY-MODEL.md) for the full public security model.

## Public Simple Tools catalog

The ten tools below are implemented, registered unconditionally in the MCP server, and documented individually under [docs/tools/](docs/tools/).

| # | Tool | Answers |
|---:|------|---------|
| 1 | [`engineering.vps.health`](docs/tools/vps-health.md) | Is my VPS healthy? |
| 2 | [`engineering.vps.why_down`](docs/tools/vps-why-down.md) | Why is my VPS or application having a problem? |
| 3 | [`engineering.deploy.status`](docs/tools/deploy-status.md) | Is my deployment working? |
| 4 | [`engineering.vps.capacity`](docs/tools/vps-capacity.md) | Is my VPS close to its limits? |
| 5 | [`engineering.vps.what_changed`](docs/tools/vps-what-changed.md) | What changed recently? |
| 6 | [`engineering.app.health`](docs/tools/app-health.md) | What application health state is reported? |
| 7 | [`engineering.vps.incident.summary`](docs/tools/vps-incident-summary.md) | What is happening with my VPS right now? |
| 8 | [`engineering.deploy.ready`](docs/tools/deploy-ready.md) | Are the minimum deterministic deployment prerequisites currently met? |
| 9 | [`engineering.docker.health`](docs/tools/docker-health.md) | Are my containers healthy? |
| 10 | [`engineering.logs.explain`](docs/tools/logs-explain.md) | What do these errors/logs mean? |

## Security model

The public tool surface follows a least-privilege, evidence-first model:

- No unrestricted shell or SSH channel is exposed to AI agents by default.
- Tools are read-only wherever possible; changing operations are explicit, bounded and validated afterwards.
- Evidence gaps are reported as such (for example UNKNOWN or insufficient evidence) and findings are never invented.

Full principles: [docs/SECURITY-MODEL.md](docs/SECURITY-MODEL.md). Public vs. private scope: [docs/PUBLIC-SCOPE.md](docs/PUBLIC-SCOPE.md). Responsible disclosure: [SECURITY.md](SECURITY.md).

## Current status

- **Ten public Simple Tools implemented:** the MCP server ships `engineering.vps.health`, `engineering.vps.capacity`, `engineering.vps.what_changed`, `engineering.vps.incident.summary`, `engineering.deploy.status`, `engineering.app.health`, `engineering.docker.health`, `engineering.vps.why_down` and `engineering.logs.explain` (read-only, deterministic, evidence-based). `what_changed` is session-scoped - it compares only observations made by the running MCP process; restarting the server resets its baseline, and it has no visibility into anything before that baseline. `incident.summary` is a deterministic composition over the same evidence: it reports NORMAL, ATTENTION or UNKNOWN, never a root cause, and calling it counts as one shared change observation. `deploy.status` reports the deployment state from the operator-configured release-state evidence source (see [Available tools](#available-tools) below); without configuration it truthfully reports UNAVAILABLE, and `app.health` answers the application health question from the same source. The application/deployment safe adapter contract (typed evidence, strict validation and pure classifiers - see [Safe adapter contract](#safe-adapter-contract-applicationdeployment-evidence) below) is implemented as a code-level seam, with the release-state file transport as its first evidence source.
- No stable release has been published yet.

## Planned public roadmap

1. **v0.1 — public foundation:** MCP server/package foundation, the ten Simple Tools, public schemas/types and public documentation — implemented. Packaging, examples and release mechanics remain for the v0.1 release cycle.
2. **Safe adapter contracts:** narrow interfaces, as needed, that let the public tools connect to a user's own deployment/monitoring mechanisms.
3. **Documentation-driven hardening:** security-model checks, validation guidance and example configurations.
4. **Possible public equivalents of selected private capabilities:** evaluated per item, without roadmap commitment (see [docs/PUBLIC-SCOPE.md](docs/PUBLIC-SCOPE.md)).

## Requirements

- [Node.js](https://nodejs.org) **18 or newer** — the minimum declared in `package.json` (`engines.node: ">=18"`). Only this floor is guaranteed by the project; no other specific versions are claimed as tested.
- npm (bundled with Node.js) to install dependencies from the public npm registry.

## Install from source

```bash
git clone https://github.com/AndersonVitaease/memoryos-vps-guardian.git
cd memoryos-vps-guardian
npm install
```

## Run

```bash
npm start
```

The server runs over **MCP stdio**: it is started by the client process and communicates exclusively via standard input/output. There is no HTTP server and no network listener.

## MCP client configuration

Generic example for launching the server from source. Exact syntax varies between MCP clients — most accept a command, arguments and a working directory in some form:

```json
{
  "mcpServers": {
    "memoryos-vps-guardian": {
      "command": "npm",
      "args": ["start"],
      "cwd": "<path-to-memoryos-vps-guardian>"
    }
  }
}
```

Replace `<path-to-memoryos-vps-guardian>` with the local folder where you cloned this repository.

## Available tools

Ten tools are implemented in this MVP:

### `engineering.vps.health`

**Input:** exactly `{}` — no parameters; extra properties are rejected.

**Output:** a deterministic status plus supporting evidence:

- `HEALTHY` — memory usage and 1-minute load per CPU are below the documented thresholds.
- `DEGRADED` — clear pressure detected: memory usage above 90%, or 1-minute load above 2× the CPU count.
- `UNKNOWN` — essential evidence could not be obtained; no diagnosis is invented.

Evidence collected (read-only, via Node.js `os` APIs — no shell, no SSH, no network):

- uptime (seconds)
- CPU count
- 1-minute load average
- total memory (bytes)
- free memory (bytes)
- memory usage percentage

### `engineering.vps.capacity`

Answers: **"Is my VPS close to its limits?"**

**Input:** exactly `{}` — no parameters; extra properties are rejected.

**Output:** a deterministic pressure assessment with a per-component view (CPU, memory) and a global status:

- `OK` — both CPU load and memory usage are below the documented thresholds.
- `PRESSURED` — clear pressure detected on either component.
- `UNKNOWN` — essential evidence could not be obtained; no classification is invented.

Current thresholds (raw values are compared; rounding is display-only):

- memory used > 90% → `HIGH`
- 1-minute load / CPU count > 2 → `HIGH`

Evidence collected (read-only, via the same Node.js `os` APIs — no shell, no SSH, no network):

- CPU count
- 1-minute load average
- load per CPU
- total memory (bytes)
- free memory (bytes)
- memory usage percentage

Current state only: the result describes the present snapshot — no future capacity prediction and no automatic upgrade recommendation.

### `engineering.vps.what_changed`

Answers: **"What changed since the previous observation made by this MCP process?"**

**Important — session scope:** this tool has no historical visibility of the VPS. It keeps its baseline and last observation only in the memory of the running MCP server process. The first call creates the baseline and restarting the server resets all history. It does **not** provide deployment, file, service, container, configuration or user-action history, and never infers one.

**Input:** exactly `{}` — no parameters; extra properties are rejected.

**Output:** a deterministic status plus the observed changes:

- `BASELINE_CREATED` — first observation of this process; nothing could be compared yet (`changes` is empty). The tool never claims any knowledge from before this baseline.
- `CHANGED` — one or more observed differences above the documented thresholds since the previous observation of this process.
- `NO_CHANGE` — no observed evidence changed above the thresholds since the previous observation of this process. This does **not** mean nothing changed on the VPS outside the evidence this tool observes.
- `UNKNOWN` — essential evidence was unavailable or inconsistent (including a change of total memory between observations); nothing is fabricated and the previous observation is kept for the next comparison.

Significance thresholds (raw values are compared; rounding is display-only):

- CPU count differs → `cpuCount` change
- uptime decreased → `reboot` change (factual only; no cause is claimed)
- free memory changed by more than 1% of total memory → `memory` change
- 1-minute load per CPU changed by more than 0.5 → `cpu` change

Each reported change carries a factual `description` plus real `before`/`after` values. `observationsSinceBaseline` counts the successful observations of this process (first call = 1, second = 2, and so on), and `baselineCapturedAt` is the ISO UTC timestamp of the session's first successful observation.

### `engineering.vps.incident.summary`

Answers: **"What is happening on this VPS right now, according to local evidence?"** — a deterministic composition of the three tools above, not a new evidence source.

**Input:** exactly `{}` — no parameters; extra properties are rejected.

**Output:** a single deterministic verdict plus compact observations:

- `NORMAL` — health HEALTHY, capacity OK and no significant change observed (or the change-observation baseline was just created). A freshly created baseline is never treated as an incident or as proof of past stability.
- `ATTENTION` — one or more currently observed conditions require attention: health DEGRADED, capacity PRESSURED or a significant change observed. This is not a confirmed incident, outage or failure and never names a cause.
- `UNKNOWN` — some required evidence was unavailable or inconsistent; absence of evidence is never reported as NORMAL or ATTENTION.

`observations` contains exactly one factual note per component (`engineering.vps.health`, `engineering.vps.capacity`, `engineering.vps.what_changed`) and `limitations` is a fixed deterministic list: no causal conclusion is made; applications, services, containers, deployments and logs are not observed; change observation is scoped to this MCP process/session and facts before its baseline are unknown.

**Shared change history:** this tool uses the same session-scoped `what_changed` instance, so calling `engineering.vps.incident.summary` counts as one change observation — direct `engineering.vps.what_changed` calls and summary calls advance the same sequence.

Nothing beyond these ten tools is implemented yet.

### `engineering.deploy.status`

**Question answered:** what deployment state is reported by the configured application/deployment evidence source? Returns a deterministic read-only verdict: `OK` (source reports SUCCEEDED), `IN_FLIGHT` (IN_PROGRESS), `PENDING` (QUEUED), `FAILED` (FAILED), `UNKNOWN` (a valid source explicitly reported no deployment status) or `UNAVAILABLE` (no source is configured, or the configured source returned no valid evidence).

**Configuration (optional, operator-controlled):** set `MEMORYOS_VPS_GUARDIAN_RELEASE_STATE_FILE` to the path of one local JSON release-state file (the [ReleaseStateFileAdapter](#release-state-file-transport-releasestatefileadapter) format) when launching the server. The variable is read once at startup by the host process; it is never caller-controlled, never echoed, and no MCP argument can supply or change the path. Without it the tool remains registered and truthfully answers UNAVAILABLE.

**Output:** `status`, `summary`, `applicationId`, `source`, `observedAt`, `currentReleaseId`, `lastDeploymentFinishedAt`, `evidenceAgeSeconds` and a fixed `limitations` list. With no valid evidence all evidence-derived fields are `null` — nothing is invented. `evidenceAgeSeconds` is the factual age of the evidence (`floor((now − observedAt) / 1000)`); it never changes the verdict, and a negative value means observable clock skew. The configured file path, file contents and any filesystem/validation errors are never exposed.

**Scope:** this tool does not assess application health, VPS health, readiness to deploy, rollback suitability, failure root cause or change safety.

### `engineering.app.health`

**Question answered:** what application health state is reported by the configured validated application/deployment evidence source? Returns a deterministic read-only verdict: `HEALTHY` (the source reports `applicationHealthy: true`), `DEGRADED` (`applicationHealthy: false`), `UNKNOWN` (a valid source explicitly reported no application health) or `UNAVAILABLE` (no source is configured, or the configured source returned no valid evidence).

**Configuration:** none beyond `engineering.deploy.status`. It consumes the SAME operator-configured release-state evidence source (`MEMORYOS_VPS_GUARDIAN_RELEASE_STATE_FILE`); no new environment variable, transport or adapter exists, and the agent can never supply the path or any evidence value.

**Output:** `status`, `summary`, `applicationId`, `source`, `observedAt`, `evidenceAgeSeconds` and a fixed `limitations` list. With no valid evidence all evidence-derived fields are `null` and nothing is invented. `evidenceAgeSeconds` is the factual age of the evidence (`floor((now - observedAt) / 1000)`); it never changes the status, and a negative value means observable clock skew. The configured file path, file contents and any filesystem/validation errors are never exposed.

**Scope:** this tool reports evidence only. It does NOT probe the application, inspect Docker, call HTTP, infer health from `deploymentStatus`, or diagnose a root cause. UNAVAILABLE means no valid observation exists; UNKNOWN means a valid observation exists but the source explicitly did not report application health.

**Independence:** `engineering.deploy.status` and `engineering.app.health` consume the same evidence but answer different questions through different certified classifiers. They are never reconciled: `deploymentStatus=SUCCEEDED` with `applicationHealthy=false` truthfully reports `OK` from deploy.status and `DEGRADED` from app.health.

### `engineering.deploy.ready`

**Question answered:** based on currently configured validated operational evidence, does the application satisfy the minimum deterministic prerequisites for attempting a deployment? Returns a deterministic read-only advisory verdict: `READY`, `NOT_READY` (with factual, non-causal blocking reasons), `UNKNOWN` (required valid evidence is incomplete) or `UNAVAILABLE` (a required evidence source is unavailable).

**Evidence and reuse:** computed only by the certified `assessDeployReady` classifier over the SAME operator-configured release-state evidence source as `engineering.deploy.status` and the existing local VPS health/capacity evidence. Four normalized components are reported: `deployment`, `applicationHealth`, `vpsHealth`, `vpsCapacity`. No new configuration, no new privileged access, no MCP tool-to-tool recursion.

**Advisory only:** this tool deploys nothing, approves nothing and grants no deployment or recovery authority. It does NOT predict deployment success and does not inspect code, migrations or release contents. UNKNOWN-first: any required component without evidence yields UNKNOWN, never READY or NOT_READY; absence of evidence is never read as a positive. UNAVAILABLE means a required evidence source is unavailable (no application source configured, or it returned no valid evidence).

**Output:** `status`, `summary`, `applicationId`, `components`, `reasons`, `evidenceAgeSeconds` and a fixed `limitations` list. `evidenceAgeSeconds` is factual evidence age; it never changes the verdict. Paths, filenames, raw evidence values and errors are never exposed. The four source Simple Tools are never reinterpreted: `engineering.deploy.ready` composes their underlying certified classifiers directly.

### `engineering.docker.health`

**Question answered:** Is the configured Docker/container workload healthy?

**Evidence and reuse:** answered only from the operator-configured docker-health evidence source (`MEMORYOS_VPS_GUARDIAN_DOCKER_HEALTH_FILE`, one fixed operator-controlled JSON file produced by the operator's own monitoring stack outside this process) via the pure deterministic `assessDockerHealth` classifier - no new framework, no MCP tool-to-tool recursion, no Docker socket, no Docker CLI, no shell, no SSH, no network, no child processes, no LLM, no mutation, no deployment or recovery authority. Evidence is aggregated counts only (`containers`: `total`, `running`, `unhealthy`, `restarting`, `stopped`, `unknown`); no container names, IDs, images, labels, mounts, commands or raw inspect data are ever exposed. The MCP input must be exactly `{}` - the agent can never select a container, host, path, socket or filter.

**Status semantics (deterministic, UNKNOWN-first):** `UNAVAILABLE` when no evidence source is configured or it returns no valid evidence; `UNKNOWN` when required state is incomplete, any container state is unknown, or the aggregate counts are internally inconsistent - missing data is never converted into DEGRADED or HEALTHY; `DEGRADED` when the evidence source reports the runtime unavailable or any unhealthy/restarting/stopped containers; `HEALTHY` only when the runtime is reported available and all configured containers are running. No root causes are inferred. `evidenceAgeSeconds` is factual only and never changes the verdict. The verdict is computed independently of `engineering.vps.health`, `engineering.deploy.status` and `engineering.app.health`; contradictory states remain possible.

**Zero-configuration:** without `MEMORYOS_VPS_GUARDIAN_DOCKER_HEALTH_FILE` the server starts normally, the tool stays registered in tools/list, and it truthfully answers UNAVAILABLE.

### `engineering.vps.why_down`

**Question answered:** Why does the currently configured VPS/application appear unhealthy? - concretely: is there evidence of a problem, which concrete signals are observed, and what cannot be determined.

**Evidence and reuse:** a deterministic synthesis of the evidence already available to this server - one local system-health snapshot feeds the existing `assessVpsHealth` and `assessVpsCapacity` classifiers, and when configured the operator-controlled release-state and docker-health sources feed `assessApplicationHealth`, `assessDeployStatus` and `assessDockerHealth` directly (no MCP tool-to-tool recursion, no new evidence source, no new environment variable, no Docker socket, no shell, no SSH, no network probe, no child processes, no LLM, no mutation). The input must be exactly `{}` - the agent can never select a host, application, container or path.

**Signals, not causes:** each signal is a normalized `{category, source, status, summary}` line from the existing classifiers (`VPS_HEALTH`, `CAPACITY`, `APPLICATION_HEALTH`, `DEPLOYMENT`, `DOCKER`). Problem predicates are factual only: VPS health DEGRADED, capacity PRESSURED, application health DEGRADED, deployment FAILED, Docker DEGRADED. A deployment IN_FLIGHT or PENDING is reported factually and is not a problem signal. When several degraded signals co-occur, all are reported and none is chosen as the cause - correlation is never presented as causation, and no root-cause field exists.

**Status semantics (deterministic, UNKNOWN-first):** `UNAVAILABLE` when no evidence source is configured at all; `UNKNOWN` when any observed signal is UNKNOWN (incomplete or inconsistent evidence) or UNAVAILABLE (a configured source returned nothing this call); `DEGRADED` when at least one factual problem signal is observed; `HEALTHY` when all observed signals report no degraded or problem condition. Categories without a configured source are absent from `signals` and their condition is never read as HEALTHY; Docker evidence being unavailable never by itself implies failure.

**Zero-configuration:** the server starts normally without the optional application/deployment and docker-health sources; the tool stays registered in tools/list and answers from the local VPS health and capacity signals alone, with missing categories explicit in the limitations.

### `engineering.logs.explain`

**Question answered:** What do the currently configured operational log signals mean?

**Evidence and reuse:** answered only from the operator-configured log-evidence source (`MEMORYOS_VPS_GUARDIAN_LOG_EVIDENCE_FILE`, one fixed operator-controlled structured JSON file of already-normalized, already-sanitized log signals produced by the operator's own monitoring stack outside this process) via the pure deterministic `assessLogsExplain` classifier. It is NOT a log browser: no raw log files, no tail, no watch, no directories, no grep, no journalctl, no docker logs, no Docker socket, no shell, no SSH, no child processes, no network, no LLM, no mutation. The input must be exactly `{}` - the agent can never select a path, file, container, service, journal, query, filter or time range, and evidence messages are never returned.

**Explanations (deterministic, no AI):** a small fixed taxonomy (`OUT_OF_MEMORY`, `CONNECTION_REFUSED`, `TIMEOUT`, `PORT_BIND_FAILURE`, `DNS_FAILURE`, `HEALTHCHECK_FAILURE`, `PROCESS_EXIT`, `PERMISSION_FAILURE`) is matched first from producer-supplied structured codes, then - only when no code matches - from a small fixed set of message rules. Unclassifiable signals are reported as UNKNOWN and never guessed. Each explanation is compact and normalized (`category`, highest observed `severity`, fixed `meaning`, advisory plain-language `suggestedCheck`); no shell commands are ever emitted.

**Status semantics (deterministic):** `UNAVAILABLE` when no evidence source is configured or it returns no valid evidence; `UNKNOWN` when the valid evidence document contains no entries or every entry is unclassifiable; `EXPLAINED` when at least one signal maps to a known category. Statuses describe explanations, not health.

**Zero-configuration:** without `MEMORYOS_VPS_GUARDIAN_LOG_EVIDENCE_FILE` the server starts normally, the tool stays registered in tools/list, and it truthfully answers UNAVAILABLE.

## Safe adapter contract (application/deployment evidence)

The code-level seam for the application/deployment tools (`engineering.deploy.status`, `engineering.app.health` and `engineering.deploy.ready`) is implemented, following the same injectable pattern as the host evidence adapter:

- `ApplicationDeploymentEvidence` — one typed evidence snapshot (`applicationId`, `observedAt`, `source`, `currentReleaseId`, `previousReleaseId`, `deploymentStatus`, `lastDeploymentFinishedAt`, `applicationHealthy`), where every nullable field means "the evidence source cannot observe this".
- `applicationDeploymentEvidenceSchema` with `parseApplicationDeploymentEvidence` / `tryParseApplicationDeploymentEvidence` — strict zod validation: unknown keys rejected, bounded strings, no control characters, ISO-8601 UTC timestamps only, and `lastDeploymentFinishedAt` must not be after `observedAt`. Malformed or inconsistent evidence is never repaired or guessed.
- `ApplicationDeploymentAdapter { name, collect(): evidence | null }` — a pure, side-effect-free, read-only evidence seam analogous to `SystemHealthAdapter`.
- Pure deterministic classifiers `assessApplicationHealth` (`true/false/null` → `HEALTHY/DEGRADED/UNKNOWN`), `assessDeployStatus` (`SUCCEEDED/IN_PROGRESS/QUEUED/FAILED/null` → `OK/IN_FLIGHT/PENDING/FAILED/UNKNOWN`) and `assessDeployReady` (advisory only: `READY` requires no in-flight/queued deployment, a reported-healthy application, no VPS health DEGRADED, no VPS capacity PRESSURED, and no required component UNKNOWN; it triggers nothing and grants no deployment authority).

**No transport ships with this contract.** It performs no file, socket, container-runtime, environment or credential access of any kind. Evidence authority stays with the host process that constructs the server; MCP tool arguments never carry this evidence. Missing evidence maps deterministically to `UNKNOWN`/`UNAVAILABLE` and is never inferred. Its consuming MCP tools are `engineering.deploy.status`, `engineering.app.health` and `engineering.deploy.ready` (see above).

## Release-state file transport (ReleaseStateFileAdapter)

`createReleaseStateFileAdapter({ path })` in `src/adapters/releaseStateFile.ts` is the first evidence source for the contract above: it reads **one** operator-configured local JSON file whose entire content is one `ApplicationDeploymentEvidence` document (all eight fields, including the required `source` label).

- **The path is operator-controlled and fixed at construction time.** It is validated once (string, 1–4096 characters, no control characters) and resolved once with `path.resolve()`; invalid configuration throws at construction. The MCP agent can never supply or modify the path, and no MCP tool consumes evidence through its arguments.
- **Read-only, no generic filesystem access.** The only I/O is `statSync()` + `readFileSync()` against that one absolute path — no writes, renames, deletes, directory listing, globs, watchers, polling, streams, retries, caching, or environment access, and no generic filesystem layer.
- **64 KiB hard limit** (`MAX_RELEASE_STATE_BYTES = 65536`), enforced before reading (via `stat`) and re-checked after reading.
- **Fail-closed.** A missing file, permission denied, directory/non-regular file, oversized file, empty or malformed JSON, or evidence failing the strict contract schema all map deterministically to `null` (→ `UNAVAILABLE`), never a crash, a guessed status, or partially accepted evidence. No staleness is computed here and no clock is used: `observedAt` passes through exactly as validated, and staleness display/policy belongs to the consuming MCP tool.
- **Consumed by `engineering.deploy.status`, `engineering.app.health` and `engineering.deploy.ready`**; the rest of the public catalog is unaffected and works with zero configuration.
- **Producer recommendation:** write a temporary file, then atomically rename it over the configured path, so readers never observe a partial write (a partial write anyway fails closed).

## Quick validation

From the repository root:

```bash
npm run typecheck
npm test
```

Expected current state: **320 tests passing** across 12 test files.

## License

[Apache License 2.0](LICENSE)

TDQS

A4.5/5.0

Scored across 10 tools

Disambiguation4/5

Each tool has a clearly named evidence source or verdict type, and the descriptions are unusually explicit about boundaries. The one real overlap risk is engineering.vps.incident.summary vs engineering.vps.why_down, since both synthesize current VPS/app evidence and an agent might not immediately know which to call.

Naming Consistency4/5

The engineering.<domain>.<suffix> snake_case prefix is consistent and makes tool navigation predictable. The suffix style is somewhat mixed — noun statuses like health, capacity, status coexist with phrasal forms like what_changed, why_down, and explain — but this is a minor inconsistency rather than a serious problem.

Tool Count5/5

Ten tools is well within the ideal range for a read-only diagnostics/observability server. Each tool covers a distinct evidence area or synthesis role, and none feels redundant or superfluous.

Completeness4/5

The set covers VPS OS health, capacity, change detection, deployment status, application health, deployment readiness, Docker health, diagnostic synthesis, and log-signal explanation. Minor gaps exist — disk/network capacity and deployment history are absent — but the tools work together to cover the core 'guardian' workflow without dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues