Skip to content

Feat/apt tools#9

Merged
rthill91 merged 2 commits into
mainfrom
feat/apt_tools
May 14, 2026
Merged

Feat/apt tools#9
rthill91 merged 2 commits into
mainfrom
feat/apt_tools

Conversation

@gjolly

@gjolly gjolly commented May 13, 2026

Copy link
Copy Markdown
Collaborator
Screenshot from 2026-05-13 22-58-11

gjolly and others added 2 commits May 13, 2026 22:57
Adds three MCP tools so an agent can answer "is this host up to date?":

- apt_update_status — one-call summary: pending updates, security
  updates, reboot-required + triggering packages, last apt-update age.
- list_upgradable_packages — per-package upgrade detail with origin,
  suite, and security flag, plus security_only / name_pattern filters.
- list_installed_packages — dpkg inventory parsed from /var/lib/dpkg/
  status, with name_pattern / limit filters. Excludes residual
  config-files entries (deinstall status).

Implementation lives in a new internal/aptdb package that mirrors the
procfs/sysfs pattern: pure-Go parsers, no os/exec. It reads dpkg status,
walks /var/lib/apt/lists for *_Packages indexes (uncompressed and gzip),
joins them with sibling Release / InRelease files for Origin/Suite, and
computes upgrades via a from-scratch dpkg version comparator
(deb-version(7): epoch / upstream / revision with tilde-ordering and
mixed alpha-numeric segments).

Two correctness notes baked in:
- InRelease files wrap the Release stanza in a PGP signed-message
  envelope; the parser skips the envelope header so Origin/Suite are
  picked up instead of "Hash: SHA512".
- Suites ending in -backports are filtered out of upgrade candidates,
  matching apt's default pin priority 100 (Ubuntu backports never
  upgrade automatically). This brings the count in line with
  `apt list --upgradable`; the only remaining divergence on a typical
  Ubuntu host is ESM-pinned packages, which would need apt-preferences
  parsing to handle exactly.

Snap confinement: /var/lib/dpkg and /var/lib/apt are not visible inside
strict confinement under the existing *-observe plugs, so the snap
declares the system-backup plug (read-only host filesystem view at
/var/lib/snapd/hostfs). Manual-connect like log-observe today. The
mcpserver picks the hostfs root when snapconf.InSnap() is true and "/"
otherwise. CLAUDE.md's plug rule is updated to admit read-only host-fs
plugs alongside *-observe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
toolResultText only extracted text blocks from result.content[], so any
tool whose payload lives in structuredContent (every FleetMind list tool)
was invisible to both the chat agent and the operator card — the LLM
only ever saw the "N items" one-line summary.

Return the pretty-printed structuredContent when present, fall back to
text blocks otherwise. When both are present the summary text just
duplicates fields already in the structured payload (e.g. "3 installed
package(s)" vs {"count": 3, ...}), so skipping it keeps the LLM's
tool_result tight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@rthill91 rthill91 merged commit 10bd391 into main May 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants