A general-purpose Java workspace dev toolkit for AI agents, packaged as a Claude Code plugin. It discovers the modules in any Java workspace and gives the agent typed, deterministic tools - gradle verify, JUnit tally, IntelliJ-faithful import reorder, javadoc normalize, module lookup - as an MCP server, plus a bundle of Java refactor / move / audit skills. Each becomes one cheap, correct call instead of a shell incantation the agent re-derives every turn.
Important
Under active development. Tool surface and return shapes may change until a stable 1.0.0.
- What you get
- Install
- MCP tools
- Bundled skills
- CLI
- Finishing a branch
- Re-pinning a cascade
- How discovery works
- Import ordering
- Architecture
- Development
- Contributing · License · Acknowledgments
Mining a large corpus of past agent sessions showed the same shapes hand-rewritten hundreds of times - the gradle noise-strip gate, the JUnit XML tally, a naive import sorter, guessed module paths. Toolsmith replaces them with stable, typed tools and a self-configuring module map. Nothing is hardcoded to a particular checkout: point toolsmith setup at any Java workspace and it discovers the modules, their paths, base packages, and short aliases into a cache the tools read.
From the plugin directory (isolated env recommended):
pip install . # or: pipx install . / pip install -e . for developmentThis puts a toolsmith executable on your PATH (the MCP entry point and the CLI).
Discover the modules once per workspace (writes <root>/.toolsmith/modules.json and registers the root):
toolsmith setup /path/to/your/java/workspace # or run with no arg from the workspace rootOptional: pin custom short aliases in <root>/.toolsmith/aliases.json ({"discord4j-framework": "d4j"}), then re-run setup.
Add this repo as a marketplace and install the plugin (activates the MCP server from .mcp.json and the bundled skills):
/plugin marketplace add /path/to/toolsmith
/plugin install toolsmith@toolsmith
Run /mcp to confirm the toolsmith server loaded. (Standalone alternative: skip the plugin and register the server yourself with a project .mcp.json containing {"mcpServers":{"toolsmith":{"command":"toolsmith","args":["serve"]}}} - the CLI and MCP work without the plugin; the plugin just also ships the skills.)
A prefix names who can use the tool: gradle_* needs a gradle build, java_* acts on Java source files, jitpack_* reaches JitPack.
| Tool | What it does |
|---|---|
gradle_modules |
The discovered inventory: each project's name, path, kind, git-repo flag, base package, short alias. Look packages up instead of guessing - several roots are counter-intuitive. |
gradle_verify |
Module-scoped gradle tasks with the true exit code, noise stripped, first failure surfaced. |
gradle_tally |
build/test-results/test/*.xml -> {tests, passed, failed, errors, skipped, failing_tests[]}. |
java_reorder_imports |
Java imports to the IntelliJ Default layout, byte-for-byte. Idempotent; wildcard- and CRLF-safe. |
java_docs_normalize |
Audit or --fix the javadocs in Java source against the project conventions. |
jitpack_status |
Is a module's commit built on JitPack? One read of the versionless build list - never triggers a build. |
jitpack_build |
Precheck, then trigger and wait for one build of a sha. Returns the verdict, the ready-to-paste strictly(...) pin, and the failing build.log tail. |
jitpack_set |
Rewrite one artifact's pin across every build file that declares it. Exact match, both dialects, sha verified before writing, idempotent - and zero matches is an error, not a silent no-op. |
jitpack_order |
What has to be re-pinned after an artifact's sha changes, in dependency order. Offline graph walk; separates a pin that must move from one that moves by convention. |
The plugin ships the Java skills so they travel with it (they stay skills, not MCP tools - routing skills carry no logic and would only cost per-turn schema tokens):
- java-file-mover - move/relocate/rename a
.javafile with package statement, imports, git history, and cross-module deps all handled (delegates reorder totoolsmith java reorder, gate togradle-verify-gate). - transcript-mine - distill past session transcripts into ranked artifacts (tool/command frequency, error histograms).
- java-bulk-rename, java-symbol-search, java-find-usages - route renames/searches to IntelliJ MCP.
- java-import-audit, java-modifier-audit, java-record-audit - convention audits.
- java-exception-class-gen - generate a conforming exception class.
- branch-finish - the end-of-branch ritual (wraps
toolsmith branch finish), so the eight git/gh steps are one command instead of hand-rolled. - gradle-verify-gate (wraps
toolsmith gradle verify), java-docs-normalize (wrapstoolsmith java docs), java-jmh-regression-gate.
Every tool is also a shell subcommand. A group names who can use what it holds: java needs Java source, gradle needs a gradle build, jitpack reaches an external service and branch reaches git. setup and serve stay top-level - they bootstrap the rest.
toolsmith setup [ROOT] # discover + cache a workspace's modules
toolsmith gradle modules # print the cached inventory
toolsmith gradle verify ar test # module-scoped gradle gate (alias or name)
toolsmith gradle tally d4j # JUnit tally
toolsmith java reorder --check src # import order gate (or without --check to rewrite)
toolsmith java docs --fix src # javadoc audit / fix
toolsmith java locate TypeRegistrar # find a class file across module sources
toolsmith jitpack status d4j # are the module's commits built on JitPack (read-only)
toolsmith jitpack build d4j # trigger + wait for one build; prints the strictly(<sha>) pin
toolsmith jitpack pins # workspace pin-drift table (commits behind / unbuilt / stale)
toolsmith jitpack order coll # what to re-pin after collections changes, in order
toolsmith jitpack set coll SHA # rewrite that pin everywhere (--check, --module, --no-verify)
toolsmith branch finish [ar] # push, open the PR, merge it, pull the base, delete the branch
toolsmith serve # run the stdio MCP server (what the plugin launches)Six subcommands moved under the two umbrellas. Each old spelling still runs, prints a one-line notice on stderr naming its replacement, and is hidden from --help:
| Deprecated | Current |
|---|---|
toolsmith modules |
toolsmith gradle modules |
toolsmith verify |
toolsmith gradle verify |
toolsmith tally |
toolsmith gradle tally |
toolsmith locate |
toolsmith java locate |
toolsmith reorder |
toolsmith java reorder |
toolsmith javadoc |
toolsmith java docs |
toolsmith branch finish is the end-of-branch ritual as one command: push, write the PR body to a file, gh pr create, gh pr merge --merge, check out the base, pull it, confirm it really contains the branch, and delete the local branch. Run --dry-run first to see the ordered plan.
toolsmith branch finish --dry-run # the plan, mutating nothing
toolsmith branch finish # prompts before the merge
toolsmith branch finish ar # name the repository instead of standing in it
toolsmith branch finish --no-merge # push + open the PR, stop for review
toolsmith branch finish --yes --delete-remote- The repository is named the way every other command names one: a module shorthand, a module name, or a path, resolved through the workspace's
.toolsmith/modules.jsonandaliases.json. With no argument it reads the current directory. A token that resolves to neither a known module nor a directory is refused, rather than falling back to the current directory and finishing whatever branch the shell was sitting on. Discovery records every git repository root, so a repository carrying no build file is nameable too. - The merge is a merge commit.
--squashand--rebaseexist only to be refused with the reason: commits here are often independently gated units, and flattening them destroys the per-commit revert granularity that gating produced. - It says where the base landed. The verdict line ends
master@<sha>, read after the pull - the sha a revert of the landing starts from, which the merge step cannot know because at that point the merge exists only on the remote. - The post-merge check is ancestry, not equality. A true merge leaves a merge commit at the base tip, so
rev-parse <base> == rev-parse <branch>is false on every successful merge; what holds isgit merge-base --is-ancestor <branch-sha> <base>, asked about a sha captured before the checkout. The delete isgit branch -d, never-D, so an unmerged branch is refused even if that check is ever wrong. - The base branch is detected, from origin's head and then
gh repo view- nothing assumesmasterormain. - Re-running resumes. A branch origin already carries, a PR already open for the head, a PR already merged: each is detected and reported as skipped rather than redone.
- A merge needs an answer. With a terminal it asks; without one it refuses before mutating anything unless
--yesis passed. - CLI only, deliberately. It pushes, opens and merges, so it is not an MCP tool: the user decides when it runs.
pins reads, order plans, set writes. A multi-module re-pin is the three in sequence:
toolsmith jitpack order collections # -> collections -> utils -> reflection -> ...
# then, one module at a time, in that order:
toolsmith jitpack set collections <sha> --module utils
toolsmith gradle verify utils # gate the edit locally
git -C ../utils commit -am "..." # then push
toolsmith jitpack build utils # -> the new sha for the next stepset matches the artifact id exactly (pins filters by substring; a rewrite that over-matches edits the wrong artifact), handles both the strictly(...) and group:artifact:version forms plus a strictly that wrapped onto a later line, and preserves whichever a site already used. It refuses to write unless the sha resolves in the publishing repo's git, is pushed, and has a green JitPack build - --no-verify opts out. --check reports the diff and writes nothing. -SNAPSHOT coordinates are left floating unless --include-snapshots.
order is offline. It marks a module direct when it declares the changed artifact itself - its own strictly() binds, so a stale one keeps it on the old code - and cascade when it only pins things that get a new sha as a result. The difference matters because published module metadata records {"requires": "<sha>"}, not strictly: an inherited pin is a soft constraint that a consumer's own strictly() overrides, so a full cascade is this workspace's one-sha-per-artifact convention rather than something Gradle demands.
toolsmith setup walks the root for build.gradle* (pruning build/.git/cache/...), computes each module's base Java package from its src/main/java chain, assigns a short alias (auto-acronym, or your aliases.json override), and writes <root>/.toolsmith/modules.json plus a ~/.config/toolsmith/roots.json registry. The server and CLI resolve the active root by: explicit arg -> TOOLSMITH_ROOT env -> walking up from the cwd -> the registry default. Re-run setup after adding a module.
java_reorder_imports reproduces the IntelliJ Default scheme: group 1 = all other non-static (ASCII sort), blank, group 2 = javax.* then java.* (not alphabetical), blank, group 3 = all static. Only java/javax are special-cased; wildcards and CRLF/LF are preserved; idempotent. Prefer the live IntelliJ MCP Optimize Imports when attached; this is the faithful IDE-independent fallback.
.claude-plugin/ plugin.json + marketplace.json (plugin + single-plugin marketplace)
.mcp.json registers the `toolsmith serve` MCP server
skills/ the bundled Java skills
hooks/ PreToolUse advisory - nudges shell symbol/declaration greps toward the Grep tool / symbol-search (non-blocking; silent on import-greps and non-Java)
src/toolsmith/
cli.py the `toolsmith` command (subcommands + serve)
server.py FastMCP server (thin veneer over the modules below)
discovery.py scan + cache + root resolution
modules.py cache-backed module/alias/package lookup
gradle.py · tally.py · imports.py · javadoc.py · jitpack.py · branch.py one module per tool
tests/ pytest suite (discovery, reorderer, tally, jitpack, branch)
notes/ provenance: the token-optimization audit that produced this
pip install -e ".[dev]"
python -m pytest -qSee CONTRIBUTING.md. Part of the Simplified-Dev ecosystem.
Scaffolded with Claude Code, grounded in a measured audit of real workspace sessions (see notes/). Copyright remains with the Simplified project.