/SKILL.md
Token-saving Java file reader. Use when working with Java files (.java) to reduce token usage. Auto-triggers when exploring, reading, or understanding Java classes, services, controllers, entities, or any .java files. Run jskim before reading raw Java source when you need structural context first, then inspect only the lines you need.
npx skillsauth add garvit-joshi/jskim jskimInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A CLI tool that summarizes Java files compactly, saving 70-80% of input tokens. Optimized for Spring Boot projects with Lombok, REST controllers, DI wiring, and configuration properties.
Python 3.10+ — install via pip:
pip install jskim
Before first use, verify jskim is installed by running jskim --version. If you get "command not found", tell the user:
jskim is not installed. Install it with:
pip install jskim
Do not attempt to run jskim commands until it is confirmed installed. Fall back to your normal file-reading tools if the user declines to install it.
jskim auto-detects whether you're pointing at a file or directory, and whether you're asking for a summary or method extraction.
Summarizes a Java file — collapses imports, fields, boilerplate (getters/setters/equals/hashCode), and shows method signatures with line ranges. Shows annotation parameters for key Spring annotations (@GetMapping("/path"), @Value("${key}"), @ConfigurationProperties("prefix"), etc.).
jskim <file.java>
jskim <file.java> --grep <pattern> # filter methods by name/signature
jskim <file.java> --annotation <@Ann> # filter methods by annotation
jskim A.java B.java C.java # multiple files
Java simple source files without an explicit type wrapper are summarized as implicit class <FileStem>, and their top-level methods are treated like normal class methods.
Filters (useful for large files with many methods):
--grep billing — show only methods whose signature contains "billing" (case-insensitive)--annotation @Transactional — show only methods with that annotation--grep create --annotation @PostMappingGenerates a compact map of all Java files in a directory — packages, classes, annotations, field/method counts, Lombok usage, enum constants.
jskim <src_dir>
jskim <src_dir> --deps # import-based dependencies
jskim <src_dir> --endpoints # REST endpoint map
jskim <src_dir> --beans # Spring bean DI graph + @Bean producers + config properties
jskim <src_dir> --callers Class.method # upstream callers for a specific method
jskim <src_dir> --impact Class.method # callers + direct callees for a specific method
jskim <src_dir> --impact Class.method --depth 2 # bounded caller/callee hierarchy depth
jskim <src_dir> --package <prefix> # filter by package
jskim <src_dir> --annotation <@Ann> # filter by class annotation
jskim <src_dir> --extends <ClassName> # filter by superclass
jskim <src_dir> --implements <Interface> # filter by implemented interface
Filters (essential for large projects with hundreds of files):
--package com.stw.server.tripsheet — only show classes in that package (prefix match)--annotation @RestController — only show classes with that annotation--extends BaseService — only show classes extending that superclass--implements EventPublisher — only show classes implementing that interface--deps — show which classes depend on which (uses imports, runs in seconds even on 2000+ files)--endpoints — list all REST endpoints: HTTP method, path, handler method, line number--beans — show Spring bean DI graph, @Bean factory method producers, and @ConfigurationProperties with field details--callers BillingService.create — show resolved upstream callers for a class-qualified method target--impact BillingService.create — show callers plus resolved downstream calls from the target method--depth 2 — follow caller/callee edges beyond direct neighbors; default is 1 and usually best--package com.example --annotation @Service --deps --endpoints --beansCall hierarchy rules:
Class.method or com.example.Class.method). Bare method names like create are intentionally rejected because they are too ambiguous in Java projects.billingService.create().Summarizes only the Java files and methods changed in a git diff. Ideal for PR reviews — instead of reading full files, get structural context for just the changed parts.
jskim --diff HEAD~1 # changes since last commit
jskim --diff main # changes vs main branch
jskim --diff main...feature-branch # merge-base comparison
jskim src/ --diff HEAD~1 # scoped to directory
git diff main | jskim --diff - # read diff from stdin
Output markers:
[NEW] — file or method that was added[MODIFIED] — method whose body was changed[DELETED] — file or method that was removed→ calls shown for new/modified methods (same format as file summary)Extracts method source code with context (fields, called methods, annotations, Javadoc).
jskim <file.java> --list # list all methods
jskim <file.java> <method_name> # extract one method
jskim <file.java> <method1> <method2> <method3> # extract multiple
Multiple methods — pass all names in one call instead of running the script multiple times. This is useful when you need a method and the methods it calls:
// not found: methodX// path/to/File.java
// com.example.billing | 12 imports: java.util(3), jakarta.persistence(2), ...
// lombok: @Data: getters, setters, toString, equals, hashCode
// @RestController @RequestMapping("/api/v1/billing")
// public class BillingController extends BaseController
//
// fields:
// BillingRepository billingRepo (@Autowired)
// BillingValidator validator
// AuditLogger auditLogger
// String tenantId
//
// getters: getName, getStatus <- collapsed, names only
// setters: setName, setStatus <- collapsed, names only
// boilerplate: toString, hashCode, equals <- collapsed, names only
// methods:
// L18-L21 ( 4 lines): public BillingController(BillingService svc, BillingValidator v)
// L45-L62 ( 18 lines): @PostMapping public Bill createBill(BillDTO dto)
// → auditLogger.log, billingService.create, notifyStakeholders, validator.validate
// L64-L80 ( 17 lines): @GetMapping("/{id}") public Bill getBill(Long id)
// → billingService.findById
// L82-L95 ( 14 lines): @PutMapping("/{id}") public Bill updateBill(Long id, BillDTO dto)
// → auditLogger.log, billingService.findById, billingService.update, validator.validate
//
// inner types:
// L90: public static enum Status
//
// other classes in file:
// L100: class BillingHelper [2F, 3M] <- 2F = 2 fields, 3M = 3 methods
//
// total: 120 lines
For Java simple source files:
// SomeScript.java
// (default) | 0 imports
// implicit class SomeScript
//
// methods:
// L1-L3 ( 3 lines): void main()
//
// total: 3 lines
For enums:
// public enum BillStatus
//
// constants: DRAFT, PENDING, APPROVED, REJECTED
//
// fields:
// String label
L45-L62 = line range in the file (use with Read offset/limit)( 18 lines) = method body length→ = method calls — lists direct method invocations made by this method (sorted alphabetically)
put, get, add, remove, stream, collect), utility checks (Objects.equals, StringUtils.isBlank, MapUtils.isEmpty), logging (log.info, logger.debug), type conversions (toString, valueOf), and stream plumbing (map, filter, forEach) are excluded... +N more→ line@GetMapping("/{id}"), @Value("${config.key}")NF = N fields, NM = N methods (used for inner/extra types)// static initializer (L10-L25, 16 lines)→ method callsThe → line shows business-logic calls only — boilerplate noise (collection ops, logging, utility checks, stream plumbing, type conversions) is automatically filtered out. What remains is high-signal:
Dependency calls (match a field in fields:):
billingService.create → field BillingService billingService exists → injected dependency call. Follow this.validator.validate → field BillingValidator validator exists → dependency call. Follow this.Same-class calls (no dot prefix):
notifyStakeholders → unqualified name → private/inherited method in the same class. Use jskim File.java notifyStakeholders to read it.Accessor calls on parameters/locals (do NOT match any field):
dto.getName, order.getId → getter calls on method parameters or local variables. Usually not worth tracing.Rule of thumb: If the object name before the dot matches a field name in the fields: section, it's a dependency call worth following. If it doesn't match any field, it's likely an accessor on a parameter or local — lower priority for tracing.
// Project Map: 42 files, 8500 lines
//
// com.example.billing (5 files, 600 lines)
// class BillingService @Service [3F | 8M | 120L | lombok:Data]
// class BillingRepository @Repository [0F | 5M | 45L]
// class BillDTO @Data [7F | 0M | 30L | lombok:Data,Builder]
// enum BillStatus { DRAFT, PENDING, APPROVED, REJECTED } [0F | 0M | 15L]
// interface BillingPort [0F | 3M | 20L]
With --endpoints:
// === REST Endpoints ===
// GET /api/v1/billing BillingController.list() L45
// POST /api/v1/billing BillingController.create() L62
// GET /api/v1/billing/{id} BillingController.get() L70
// PUT /api/v1/billing/{id} BillingController.update() L80
// DELETE /api/v1/billing/{id} BillingController.delete() L90
With --beans:
// === Bean Dependencies ===
// BillingService @Service <- BillingRepository, BillValidator, KafkaTemplate
// BillingController @RestController <- BillingService, AuthService
//
// === Bean Producers (@Bean) ===
// AppConfig @Configuration -> ObjectMapper, TaskScheduler, NotificationClient
//
// === Configuration Properties ===
// billing.* (BillingProperties): BigDecimal taxRate, String currency, int maxRetries
With --deps:
// === Dependencies ===
// BillingService -> BillingRepository, BillDTO, BillingPort
With --callers BillingService.create --depth 2:
// === Callers: BillingService.create (depth 2) ===
// target: com.example.billing.BillingService.create(BillDTO) src/.../BillingService.java:L45
//
// callers:
// ← com.example.billing.BillingController.createBill(BillDTO) src/.../BillingController.java:L62
// ← com.example.billing.BillingJob.retryFailedBills() src/.../BillingJob.java:L30
With --impact BillingService.create:
// === Impact: BillingService.create (depth 1) ===
// target: com.example.billing.BillingService.create(BillDTO) src/.../BillingService.java:L45
//
// callers:
// ← com.example.billing.BillingController.createBill(BillDTO) src/.../BillingController.java:L62
//
// calls:
// → com.example.billing.BillingRepository.save(Bill) src/.../BillingRepository.java:L20
// → com.example.billing.BillingService.validate(BillDTO) src/.../BillingService.java:L80
NF = N fields, NM = N methods, NL = N lines in filelombok:Data,Builder = Lombok annotations present on the classinner:Foo,Bar = inner classes/enums inside this classenum Status { ACTIVE, INACTIVE }--deps) = import-based class references; when simple class names are ambiguous, fully-qualified names are shown--endpoints) = all @GetMapping/@PostMapping/etc. with full paths--beans) = DI wiring, @Bean factory method producers, and @ConfigurationProperties--callers, --impact) = resolved method call edges only; unresolved local-variable/parameter calls are omitted to avoid false confidenceWith --list:
// public class BillingService extends BaseService
//
// L45-L62 ( 18 lines): @PostMapping public Bill createBill(BillDTO dto)
// L64-L80 ( 17 lines): public void processBill(Long id)
With method names:
// public class BillingService extends BaseService
// fields: BillingRepository billingRepo, String tenantId
//
// @PostMapping public Bill createBill(BillDTO dto) (L45-L62)
//
// 45 | @PostMapping
// 46 | public Bill createBill(BillDTO dto) {
// ...full method source with line numbers...
// 62 | }
//
// --- called methods in same class ---
// L64-L80: public void processBill(Long id)
fields: lists class fields for contextcalled methods in same class shows other methods referenced in the extracted method bodies// not found: methodX appears if a requested method name wasn't foundimplicit class <FileStem> headerFollow this order to minimize tokens:
jskim src/ to understand project structurejskim src/ --package com.example.billing to focus on relevant packagejskim src/ --endpoints --beans to see REST API + DI wiringjskim File.java to see class structure (fields, methods, line ranges, and method calls)→ calls to follow execution: match fieldName.method against fields: to find the target class type, then skim that class to continuejskim src/ --callers Class.method or --impact Class.method to see resolved upstream/downstream method edgesjskim File.java --grep billing if the class has many methodsjskim File.java methodA methodB to read the methods you needGoal: Understand what happens when POST /api/v1/billing is called.
Step 1: jskim BillingController.java
→ See: createBill() calls billingService.create, validator.validate
→ See fields: BillingService billingService, BillingValidator validator
Step 2: jskim BillingService.java
→ See: create() calls billingRepo.save, eventPublisher.publish, calculateTax
→ See fields: BillingRepository billingRepo, EventPublisher eventPublisher
Step 3: jskim BillingService.java calculateTax
→ Read the method source to understand the tax logic
Done — you traced Controller → Service → Repository in 3 tool calls,
reading ~50 lines of skim output instead of ~500 lines of raw Java.
The → calls show what a method calls (downstream). To find what calls a specific method (upstream), prefer call hierarchy mode with a class-qualified target:
Goal: Who calls billingService.create()?
Step 1: jskim src/ --callers BillingService.create
→ See resolved direct callers
Step 2: jskim src/ --callers BillingService.create --depth 2
→ See callers of the callers when you need a broader impact view
Use --impact BillingService.create when you need both upstream callers and downstream calls from the target in one compact view.
Fallback for unresolved/ambiguous cases:
rg "create\\(" -g "*.java" — raw text search for local-variable/parameter calls or overload-heavy codejskim src/ --grep create — scans all files but only shows methods whose signatures match "create"| Situation | Tool |
|---|---|
| PR review / what changed? (large diff, 1000+ lines) | jskim --diff develop to triage, then git diff for details |
| PR review / what changed? (small diff, < 1000 lines) | git diff develop...HEAD directly — skip jskim |
| New project, need orientation | jskim src/ |
| Find all REST controllers | jskim src/ --annotation @RestController |
| See all API endpoints at a glance | jskim src/ --endpoints |
| See Spring bean DI wiring + producers | jskim src/ --beans |
| Find all classes extending BaseService | jskim src/ --extends BaseService |
| Find all implementations of an interface | jskim src/ --implements EventPublisher |
| Understand a class structure | jskim File.java |
| Trace call flow downstream | Skim the class → follow → field calls → skim the dependency class |
| Find callers (upstream) | jskim src/ --callers Class.method |
| Assess impact of a change | jskim src/ --impact Class.method --depth 1 first; increase depth only if needed |
| Large class (500+ lines), looking for specific methods | jskim File.java --grep keyword |
| Need to read a method's source code | jskim File.java methodName |
| Need method + related methods together | jskim File.java method1 method2 method3 |
jskim --diff vs git diffjskim --diff gives structural context — which methods were added, modified, or deleted, with signatures and call graphs. git diff gives the actual code changes. They serve different purposes:
Use jskim --diff when:
Use git diff directly (skip jskim --diff) when:
git diff — running jskim after is redundantKey insight: jskim --diff is a triage tool, not a replacement for reading the diff. Use it first on large diffs to decide where to focus, then read the actual changes with git diff or your normal diff/file viewer. On small diffs, skip it entirely and go straight to git diff.
git diff is faster and gives you more useful information than jskim --diffjskim --diff after reading git diff; the structural info is already in context.java filesjskim before reading a Java file directly when you don't already know where to look (no line numbers from search, no prior context). Skip jskim if you already have the line range you need.jskim <src_dir> to understand the structure--package to scope project map output--depth at 1 until you know you need more context--grep or --annotation to filter outputjskim File.java method1 method2 call→ calls against the fields: section to identify dependency calls vs parameter accessor noiseIf jskim fails (syntax error, unexpected Java construct, Python not found, etc.), do not stop or ask the user to fix it. Fall back to your native tools:
The goal is always: understand the Java file's structure with minimal tokens. jskim is the fast path, but you can always do it yourself if it breaks.
If the host skill environment invokes this skill with arguments:
.java file -> run jskim $ARGUMENTSjskim $ARGUMENTS<file.java> <method> -> run jskim $ARGUMENTSdevelopment
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.