Skip to content

About

Claude Code plugin to navigate, trace, and debug a fleet of multi-repo Spring Boot microservices

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

spring-fleet

MIT License Spring Boot 3.x / 4.x Java 17+ Python 3.8+ MCP server included Claude Code plugin Tests

spring-fleet

A Claude Code plugin that makes a fleet of Spring Boot microservices feel like a single codebase.

If you maintain more than a handful of Spring services spread across separate repos, you know the pain:

  • A request fails β†’ which service was last to touch it?
  • A bug report says "session ABC123 broke" β†’ whose logs?
  • You're refactoring a shared lib β†’ who actually uses this class?

spring-fleet teaches Claude your fleet's shape (repos, ports, services, who calls whom) and gives you a few commands that handle the cross-repo legwork for you.


What it does

You ask spring-fleet does
"Where does this request go?" Follows the call chain across every repo and proxy-lib, with file:line citations at every hop.
"Why did this break?" Merges every service's logs into one timeline by trace key, finds the failing hop, and explains the root cause, with a suggested fix and the exact file to edit.
"What breaks if I change this?" Lists every consumer of a shared class, file, or endpoint across the fleet, flagged by risk.
"How do I start the fleet locally?" Plans (or runs) docker compose up or bootRun per service, with logs landing where the debugger can find them.

You stay in Claude Code. No new dashboard, no agent to deploy, no SaaS account.


See it work (30 seconds, no install)

The repo ships a tiny three-service "fleet" you can correlate logs against right now:

git clone https://github.com/talayash/spring-fleet
cd spring-fleet
python scripts/correlate_logs.py --config fixtures/fleet.config.json --value ABC123

You'll see something like:

2026-06-09 14:23:01.100 [orchestrator] received reserve request
2026-06-09 14:23:01.220 [order]        create order
2026-06-09 14:23:01.450 [order]        order created id=9001
2026-06-09 14:23:01.600 [payment]      charge requested amount=120.00
2026-06-09 14:23:02.200 [payment]      ERROR upstream gateway timeout after 600ms
2026-06-09 14:23:02.300 [payment]      ERROR returning 502 Bad Gateway
2026-06-09 14:23:02.350 [orchestrator] ERROR payment-api returned 502, aborting reserve

One trace key, three services' logs interleaved chronologically, the failing hop visible. That's what /debug does in Claude Code, plus a "here's the root cause and where to fix it" writeup at the end.

spring-fleet /debug correlating logs across three services


Install (2 minutes)

You need Claude Code and Python 3.8+.

# 1. Tell Claude Code where the marketplace lives:
/plugin marketplace add talayash/spring-fleet

# 2. Install the plugin from it:
/plugin install spring-fleet@spring-fleet

Why two steps? The marketplace is the catalog; the plugin is the entry inside it. They happen to share the same name in this repo. If you skip step 1, you'll get Plugin "spring-fleet" not found.

Already installed but seeing a stale version? /plugin marketplace update spring-fleet.

Codex

The same repo is also a Codex plugin (.codex-plugin/plugin.json):

codex plugin marketplace add talayash/spring-fleet
codex plugin add spring-fleet@spring-fleet

Start a new Codex session and approve the plugin's SessionStart hook when Codex asks you to review it. Workflows are skills, so type $debug, $trace, $fleet-init and so on instead of /debug. What differs from Claude Code:

  • No subagents or output style. The skills tell Codex to follow the agents/*.md playbooks itself; fleet-narrator and the status line are Claude Code only.
  • MCP tools take config_path. Codex starts the plugin's MCP server in the plugin directory, not your project, so the skills pass the config's absolute path. Setting SPRING_FLEET_CONFIG also works.
  • $run is explicit-only. It launches processes, so Codex never picks it on its own.

First use (5 minutes)

1. Describe your fleet to the plugin

/fleet-init C:/path/to/your/repos

This scans every repo under that directory and writes a draft config (spring-fleet.config.json) into your project root. It auto-detects:

  • which repos are services vs shared libraries
  • each service's port, context path, build tool
  • modern stack features: Spring Boot 4, Java 21+, virtual threads, GraalVM native, compose.yaml, Testcontainers, OpenTelemetry, Spring AI MCP server
  • Backstage catalog-info.yaml files (used to seed topology)

Two things it can't infer mechanically, so Claude will ask you:

  • traceKeys: which MDC keys identify a request in your logs. Modern fleets: keep the defaults (trace_id, span_id). Legacy fleets: add your own (sessionId, requestId, etc.).
  • topology: who calls whom. If you have Backstage catalogs, most of this is filled in for you.

πŸ”’ spring-fleet.config.json is .gitignored by default. It contains your private paths and service names. Never commit it. Share the *.example.json file instead.

2. Use it

/trace POST /order-v1/reserve
/debug 4bf92f3577b34da6a3ce929d0e0e4736       # paste an OTel trace_id
/debug ABC123                                 # or a legacy sessionId
/debug "NullPointerException at PaymentController.charge"
/debug                                        # then paste a Grafana screenshot
/impact core-lib/util/RetryPolicy.java
/run                                          # plan the fleet launch
/run --execute                                # actually start it
/doctor                                       # diagnose config and local prerequisites
/logs payment --grep ERROR --follow

3. (Optional) Fix log scattering

If /debug reports missing log files, your services aren't writing to a common place yet. Ask Claude:

Use the spring-fleet-logging-setup skill to install the logback convention.

It drops a small logback-spring.xml into each service so every service writes <logDir>/<service>.log with trace keys in the pattern.


Commands

Command What you type What you get
/fleet-init /fleet-init [path/to/repos] Draft config from your repos. Run once per project.
/doctor /doctor [--config PATH] Read-only checks of config, repositories, logs, duplicate ports, topology and required executables, with suggested fixes.
/trace /trace POST /order-v1/reserve Ordered call chain across repos, with file:line for every hop.
/debug /debug <trace_id|sessionId|"error"|screenshot> Cross-service log timeline + a root-cause hypothesis (what / where in code / why / suggested fix / alternatives).
/impact /impact OrderEntity Every consumer across the fleet, classified by call kind and contract risk.
/run /run [service] [--execute] Plans (or launches) the local fleet: docker compose up first, bootRun / mvn spring-boot:run as fallback.
/logs /logs payment --grep ERROR --follow Tail / aggregate logs. --k8s falls back to kubectl logs (mirrord-friendly).

Each command also runs deterministic Python scripts under the hood (correlate_logs.py, scan_repos.py, tail_logs.py, run_fleet.py), so you can call them directly without Claude if you want.


How it works

spring-fleet (this plugin: generic, shareable)        your machine (private)
β”œβ”€β”€ skills/          /fleet-init /trace /debug          spring-fleet.config.json
β”‚                    /impact /run /logs /doctor           β”œβ”€ reposRoot
β”‚                    tracing Β· debugging Β· logging-setup  β”œβ”€ logDir, traceKeys
β”‚                    federating-mcp-servers               β”œβ”€ services[] (name, port, path, stack)
β”œβ”€β”€ agents/          fleet-explorer Β· log-correlator      β”œβ”€ sharedLibs[], proxyLib
β”‚                    impact-analyzer                      └─ topology (entry, edges)
β”œβ”€β”€ .codex-plugin/   Codex manifest, MCP + hook config
β”œβ”€β”€ hooks/           SessionStart Β· SubagentStop Β·
β”‚                    statusLine
β”œβ”€β”€ scripts/         deterministic Python (stdlib only)
β”œβ”€β”€ mcp_server.py    typed MCP tools (in scripts/)
β”œβ”€β”€ output-styles/   fleet-narrator
└── logback/         drop-in logging convention

The plugin is generic and shareable: it has zero knowledge of your specific repos. Everything environment-specific lives in your local spring-fleet.config.json, which is git-ignored.

When you start a Claude Code session in a project with that config, the SessionStart hook preloads your fleet topology so Claude doesn't need to re-read it each turn. The MCP server (scripts/mcp_server.py) exposes seven typed tools so Claude calls them deterministically instead of parsing CLI output.


MCP tools (for power users)

If you're already using MCP, spring-fleet ships a stdlib MCP server you can call from any MCP-aware client:

Tool Purpose
doctor Read-only fleet diagnostics, with errors, warnings and suggested fixes
list_services Services + ports + detected stack + shared libs
get_topology Entry services and [from, to] edges
correlate_by_trace Cross-service timeline for a trace value
tail_service_log Last N lines of one or more service logs
scan_repos_root Draft config from a repos directory
find_service_log_path Resolve a service name β†’ its log file path

The server speaks JSON-RPC 2.0 over stdio. .mcp.json registers it automatically with Claude Code. Fleets whose services ship their own Spring AI MCP server (Spring AI 1.1+) can federate them alongside; see the federating-mcp-servers skill.

Accurate log correlation

The CLI preserves substring search by default, including error snippets. Use exact matching when you have a trace identifier:

python scripts/correlate_logs.py --config fixtures/fleet.config.json --value ABC123 --match exact
python scripts/correlate_logs.py --config fixtures/fleet.config.json --value ABC123 --key sessionId --format json

--match exact searches the configured traceKeys; --key selects one key and implies exact matching. Text key=value / key: value fields and JSON fields are supported, including nested MDC, dotted ECS fields and GELF-prefixed fields. Configure the actual key names used in your logs (for example traceId or trace.id). JSON events must occupy one physical line, with embedded stack traces escaped inside their string fields.

Events sort by parsed UTC time, preserving nanoseconds. ISO timestamps with offsets and numeric GELF epoch seconds are supported. Timestamps without an offset assume UTC; use explicit offsets when services log in different timezones. Invalid or missing timestamps sort last in source order. Text stack-trace continuations stay with the preceding event. JSON results include lineNo, endLineNo and timestampUtc (epoch seconds as a string, or null).

The correlate_by_trace MCP tool accepts match, key and max_records. It returns the earliest 200 events by default (maximum 1000), with count, totalCount and truncated. Individual log records are limited to 8000 characters and marked lineTruncated when shortened. tail_service_log allows up to 1000 lines per service and marks shortened lines with [truncated]. Serialized tool payloads above 100000 characters return an actionable error. Narrow the request or use the CLI for complete output.

Check your local setup

python scripts/doctor.py --config spring-fleet.config.json
python scripts/doctor.py --config spring-fleet.config.json --format json

Doctor checks the project schema, repository paths, log files, service names, port conflicts, topology references and executables needed by the current launch plan. Missing logs are warnings because services may not have started. Exit code 0 means no errors; 1 means errors were found. It does not start processes, install tools, probe ports or verify Docker/cluster connectivity. Relative config paths use the current working directory, matching the existing scripts. The MCP doctor tool uses the server's configured fleet file.


Configuration

Run /fleet-init to generate spring-fleet.config.json, or copy spring-fleet.config.example.json and edit by hand. The complete JSON Schema lives in spring-fleet.config.schema.json. Most-used fields:

Field What it is
reposRoot The directory under which all your service + lib repos live.
services[] Each service: { name, path, port, contextPath, logFile, stack, backstage }.
sharedLibs[], proxyLib Cross-repo libraries, used by /trace and /impact.
topology entry services + [from, to] call edges. Seeded from Backstage when available.
traceKeys MDC keys for log correlation. Defaults: ["trace_id", "span_id", "sessionId", "requestId"].
logDir Where per-service logs land. /debug and /logs read from here.
k8s (optional) { namespace, context, podSelectorTemplate }: enables kubectl logs fallback.

FAQ

Do I need OpenTelemetry? No. spring-fleet works with whatever MDC keys your services already emit (sessionId, requestId, your own). If you do have OTel, great: trace_id is the default correlation key.

Does it work with Spring Boot 3? Yes. spring-fleet supports Spring Boot 3.x and 4.x side-by-side. /fleet-init records the major version per service so commands can branch on it.

Does it support Maven? Yes. buildTool.type is gradle or maven; /run and the templates adapt.

My services run in Kubernetes. Does this still work? Yes. Add a k8s block to your config and pass --k8s to /logs (or set SPRING_FLEET_K8S=1). spring-fleet shells out to kubectl logs when a file-based log is missing. Works great with mirrord.

Does any of this leave my machine? No. spring-fleet runs locally; Claude reads your logs and source through the plugin. Your spring-fleet.config.json is .gitignored by default.

What if I don't use Claude Code? The Python scripts (correlate_logs.py, scan_repos.py, tail_logs.py, run_fleet.py) are usable as a standalone CLI. The MCP server is callable from any MCP-aware client.


Try the demo without installing

You don't need Claude Code to see what the correlator does:

python scripts/correlate_logs.py --config fixtures/fleet.config.json --value ABC123

The bundled fixtures/ fleet reconstructs a failed reserve across three services and surfaces the payment gateway timeout as the root cause.

To see it correlate by OTel trace_id instead:

python scripts/correlate_logs.py --config fixtures/fleet.config.json --value 4bf92f3577b34da6a3ce929d0e0e4736

Same timeline, modern key.


Development

python -m unittest discover -s tests -v

76 tests across tests/test_scripts.py, tests/test_mcp.py, tests/test_hooks.py, tests/test_run_fleet.py, tests/test_upgrades.py. No network, no third-party dependencies, runs on Python 3.8+. CI executes on Linux / Windows / macOS against Python 3.8 and 3.12 (see .github/workflows/ci.yml).

Contributions welcome! See CONTRIBUTING.md.


Roadmap

  • Streamable HTTP transport for the MCP server (currently stdio-only).
  • /incident: bundles /debug + /impact into a postmortem-style writeup.
  • GitHub PR comment integration (Vercel Agent / Sentry Seer style).

See CHANGELOG.md for what shipped when.


License

MIT Β© Tal Ayash

About

Claude Code plugin to navigate, trace, and debug a fleet of multi-repo Spring Boot microservices

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages