Files
agent-tools/doc/tool-parity.md
claude 5131e9f823
All checks were successful
release-tools / build-release (push) Successful in 59s
doc: tool-parity plan — Gemini CLI vs Claude Code gap analysis + homelab admin tool specs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 19:27:58 +02:00

10 KiB

Tool parity: Gemini CLI vs Claude Code

Goal: let Gemini CLI (the agent driven via agent-helm) do everything Claude Code can, by building the missing capabilities as small CLI tools in this repo. Gemini calls them through run_shell_command, so every tool follows the house rules: text in, verifiable artifacts out, single static Go binary, self-explanatory output.

Sources: Gemini CLI tools reference (https://geminicli.com/docs/reference/tools/), Claude Code's toolset as of 2026-08.

1. Already at parity — nothing to build

Capability Claude Code Gemini CLI
Read/write/edit files Read / Write / Edit read_file / write_file / replace
Find files / search text / list dirs Glob / Grep glob / grep_search / list_directory, plus read_many_files
Shell, incl. background processes Bash (+ background tasks) run_shell_command (+ background processes)
Web WebFetch / WebSearch web_fetch / google_web_search
Ask the user a structured question AskUserQuestion ask_user
Plan mode EnterPlanMode / ExitPlanMode enter_plan_mode / exit_plan_mode
Skills / slash commands Skill (.claude/skills) activate_skill (.gemini/skills)
Persistent memory file-based memory dir save_memory (simpler, but exists)
Todo/task tracking TaskCreate/TaskUpdate/… write_todos, tracker_* (experimental)
MCP servers + resources MCP tools, ListMcpResources/ReadMcpResource MCP tools, list_mcp_resources/read_mcp_resource
Subagents Agent (background, custom types) subagents (experimental) — weaker, see fanout below

Not worth replicating (harness-internal to Claude Code, no value as a CLI): ToolSearch, EndConversation, ReportFindings, ShareOnboardingGuide, DesignSync, remote cloud execution.

2. Gaps → tools to build

Ordered by expected value. Each becomes its own folder + binary + README, per repo convention.

2.1 cronr — scheduled/recurring runs (Claude: CronCreate/CronList/CronDelete, /loop)

Gemini CLI has no way to schedule work. cronr manages systemd user timers so an agent can create recurring or one-shot scheduled jobs (including "run this prompt every morning" via gemini -p …).

cronr add nightly-ci-check --schedule "*-*-* 07:00" --cmd 'gemini -p "check CI status and notify"'
cronr add once-reboot-check --at "2026-08-06 03:00" --cmd '…'   # one-shot
cronr list                    # name, schedule, next run, last result
cronr logs nightly-ci-check   # journalctl for the unit
cronr rm nightly-ci-check

Output prints the generated unit files so the result is verifiable. No daemon of its own — systemd does the running.

2.2 waitfor — block until a condition holds (Claude: Monitor)

Turns "poll every N seconds" into a single blocking tool call, so the agent doesn't burn turns polling.

waitfor --cmd "curl -sf https://gitea.brasse-pc.eu/api/healthz" --interval 30s --timeout 20m
waitfor --cmd "ssh pi5 docker ps --format '{{.Names}}'" --matches 'gitea' --timeout 10m
waitfor … --then 'notifyr send --msg "gitea is back up"'

Exit 0 = condition met, exit 3 = timeout; last output is printed either way. --then runs a command on success (composes with notifyr).

2.3 notifyr — push notifications, send and read (Claude: PushNotification)

The ntfy server already runs on the Pi5 and is the house-wide notification bus (topics like Info, pi5-server-fel, ci-fel — see infra-Doc services/observability.md). notifyr is a thin client so every agent uses it the same way:

notifyr send --topic ci-fel --title "Build failed" --msg "agent-tools arm64 test: FAIL" --priority high
notifyr read --topic pi5-server-fel --since 2h     # poll mode: what has alerted lately?

read (ntfy's ?poll=1&since=…) is the underrated half: it lets an agent check what the infra has been complaining about before/after a change. Config (~/.config/notifyr/config.json): server URL + token.

2.4 pagepub — publish an HTML/Markdown report to a URL (Claude: Artifact)

Claude Code can publish reports as web pages; Gemini cannot. pagepub rsyncs a file to a static-file host on the Pi5 (nginx container behind NPM, e.g. pages.brasse-pc.eu) and prints the stable URL.

pagepub publish report.html --slug ci-report     → https://pages.brasse-pc.eu/ci-report/
pagepub publish notes.md --slug pi5-audit        # .md rendered to HTML with built-in template
pagepub list | rm <slug>

Requires the static host to exist first (small infra task; goes in infra-Doc + NPM proxy host via npmctl).

2.5 nbcell — Jupyter notebook editing (Claude: NotebookEdit)

.ipynb is JSON that's miserable to edit via replace. nbcell exposes cells as text:

nbcell list nb.ipynb                 # index, type, first line, exec count
nbcell show nb.ipynb 3               # cell source (and outputs with --outputs)
nbcell edit nb.ipynb 3 --from-file cell.py
nbcell add nb.ipynb --at 4 --type code --from-file new.py
nbcell rm nb.ipynb 7

2.6 wtreectl — disposable git worktrees (Claude: worktree isolation for agents)

Claude Code can give each subagent an isolated git worktree. wtreectl does the same for any agent:

wtreectl new [--branch dev/foo]   # prints the new worktree path
wtreectl list
wtreectl clean                    # removes worktrees with no changes

Lets two agent sessions work in the same repo without trampling each other.

2.7 fanout — parallel subagent orchestration (Claude: Workflow, Agent) — roadmap, not agreed

Runs N prompts as parallel headless agent processes (gemini -p / claude -p) with a concurrency cap, collecting each result as JSON in an output dir. A poor man's Workflow:

fanout run jobs.json --max 3 --out results/

Heavier than the other tools and overlaps with agent-helm's territory — park until there's a concrete need.

3. Suggested tools from infra history

Grounded in what the agent has already been doing per infra-Doc (maintenance-and-gaps.md, services/source-control-and-deploy.md, services/observability.md, the per-service "operational quick-ref" blocks). These help any agent (Claude or Gemini) administer the fleet, and they respect the read-only sudo policy (ssh/claude-sudo-policy.md): everything below is read-or-notify; mutations still go through Björn's supervised tmux flow.

3.1 giteactl — Gitea repos, Actions runs and CI logs

The biggest recurring friction. Today: CI status is polled ad hoc, and logs for private repos are only readable as zst files under /srv/storage1/gitea/actions_log/… on the Pi5. Wraps the Gitea REST + Actions API:

giteactl runs <repo> [--limit 5]          # status, branch, duration
giteactl log <repo> <run> [--job N]       # fetches + decompresses the zst log
giteactl wait <repo> [--timeout 30m]      # block until latest run finishes; exit 0 = green
giteactl wait-quiet [--max-active 1]      # block until ≤N heavy builds are running
giteactl release <repo> [<tag>]           # rolling-release assets + checksums

wait-quiet encodes the hard-learned rule "serialize pushes — >2 heavy builds take the Pi5 down": giteactl wait-quiet && git push. Composes with waitfor/notifyr.

3.2 fleet — one-shot health snapshot of the whole homelab

Every service doc ends with the same hand-rolled loop over ssh pi5-claude sudo claude-docker ps/inspect …. fleet does that loop once, properly:

fleet status          # containers (state, image, restarts), disk/mergerfs fill %, failed systemd units
fleet status --host brasse-linux01
fleet checks          # Uptime Kuma monitor states + last ntfy alerts (via notifyr read)

Read-only by construction (claude-docker wrapper + sudo allowlist), so it needs no new permissions. Output is a stable text table an agent can diff between runs.

3.3 envaudit — compose ↔ .env key auditor

Grounded in a real incident (${STORAGE1} undefined in /srv/.env → bad mount, rollback) and in maintenance-and-gaps' inline-secret findings:

envaudit check /srv/dockge-staks --env /srv/.env
  → UNDEFINED  ${STORAGE1}   used by media-stack/compose.yaml
  → INLINE     LDAP_ADMIN_PASSWORD  hardcoded in openldap/compose.yaml (should live in .env)
  → UNUSED     OLD_API_KEY   defined but referenced nowhere

Pure text analysis of compose files — safe to run anywhere, catches the two failure classes that have actually happened.

3.4 reghelper — docker-registry catalog & hygiene

The LAN registry (192.168.0.19:5000) has no UI, no auth and no cleanup story, and the backup plan explicitly wants it slimmed:

reghelper ls                      # catalog + tags + image sizes
reghelper tags <image>
reghelper prune-plan --keep 2     # prints the delete+GC commands (does NOT run them)

prune-plan deliberately only prints the mutation commands for the supervised tmux flow — same pattern as the sudo policy.

3.5 Backup status reader — once Backrest/restic exists

future-plans.md has the whole Backrest+restic design chosen but unbuilt. When it lands, a fleet backups subcommand (last snapshot age per source, repo size, last check result) closes the loop — an agent can then verify backups instead of trusting them. Not a separate tool; park under fleet.

Cross-reference

/home/brasse/repos/dify-agent-tools/ already has a specced-but-unbuilt set of FastAPI tools (file/image sorting, face recognition, ST-card export…) for the Dify platform. Different runtime (HTTP tools vs CLI binaries), same philosophy — don't duplicate those here.

4. Suggested build order

  1. notifyr — smallest, everything else composes with it, ntfy already runs.
  2. giteactl — removes the biggest daily friction (CI logs + build serialization).
  3. waitfor + cronr — turns both agents into unattended operators.
  4. fleet — replaces the hand-rolled health loops in every runbook.
  5. envaudit, reghelper, pagepub, nbcell, wtreectl — as needed.
  6. fanout — only if a concrete multi-agent need shows up.