$npx -y skills add AdamBien/airails --skill zargsAdd zero-dependency argument parsing to Java CLI applications using the zargs pattern — an enum-based argument parser. Use when adding CLI argument parsing, command-line option handling, or adding options to a Java project. Triggers on "zargs", "argument parsing", "CLI arguments"
| 1 | Add zero-dependency argument parsing to a Java CLI application using $ARGUMENTS. Apply all rules below. |
| 2 | |
| 3 | ## What is zargs |
| 4 | |
| 5 | zargs is a zero-dependency, enum-based argument parsing pattern for Java CLI applications. It is not a library or dependency — it is a set of conventions and code patterns to apply directly when generating argument parsing code. |
| 6 | |
| 7 | - Reference: https://github.com/AdamBien/zeeds/blob/main/zargs |
| 8 | - Requires: Java 21+ |
| 9 | |
| 10 | ## Argument Enum Pattern |
| 11 | |
| 12 | Define an enum where each constant represents a CLI option. The enum provides matching, lookup, and usage generation: |
| 13 | |
| 14 | ```java |
| 15 | import java.util.stream.Collectors; |
| 16 | import java.util.stream.Stream; |
| 17 | |
| 18 | public enum Arg { |
| 19 | HELP("-help", "Show this help"), |
| 20 | VERBOSE("-verbose", "Enable verbose output"), |
| 21 | OUTPUT("-output", "Specify output file"); |
| 22 | |
| 23 | final String option; |
| 24 | final String description; |
| 25 | |
| 26 | Arg(String option, String description) { |
| 27 | this.option = option; |
| 28 | this.description = description; |
| 29 | } |
| 30 | |
| 31 | boolean matches(String value) { |
| 32 | return this.option.equals(value) |
| 33 | || value.startsWith(this.option + ":"); |
| 34 | } |
| 35 | |
| 36 | static Arg from(String value) { |
| 37 | return Stream.of(values()) |
| 38 | .filter(a -> a.matches(value)) |
| 39 | .findFirst() |
| 40 | .orElse(null); |
| 41 | } |
| 42 | |
| 43 | static String usage() { |
| 44 | return Stream.of(values()) |
| 45 | .map(a -> " %-12s %s".formatted(a.option, a.description)) |
| 46 | .collect(Collectors.joining("\n")); |
| 47 | } |
| 48 | } |
| 49 | ``` |
| 50 | |
| 51 | ## Parsed Arguments Record |
| 52 | |
| 53 | Define a record matching the application's parsed arguments: |
| 54 | |
| 55 | ```java |
| 56 | import java.util.List; |
| 57 | |
| 58 | public record Args(boolean verbose, String output, List<String> files) {} |
| 59 | ``` |
| 60 | |
| 61 | ## Argument Syntax |
| 62 | |
| 63 | zargs supports two value styles for options that take a value: |
| 64 | |
| 65 | | Style | Example | Description | |
| 66 | |-------|---------|-------------| |
| 67 | | Colon-separated | `-output:result.txt` | Value follows `:` immediately | |
| 68 | | Space-separated | `-output result.txt` | Value is the next argument | |
| 69 | |
| 70 | Boolean flags (like `-verbose`) require no value. |
| 71 | |
| 72 | ## Parsing Pattern |
| 73 | |
| 74 | Use pattern matching with `switch` and `case null` to parse arguments: |
| 75 | |
| 76 | ```java |
| 77 | Args parseArgs(String[] args) { |
| 78 | var verbose = false; |
| 79 | String output = null; |
| 80 | var files = new ArrayList<String>(); |
| 81 | |
| 82 | for (int i = 0; i < args.length; i++) { |
| 83 | var arg = args[i]; |
| 84 | switch (Arg.from(arg)) { |
| 85 | case HELP -> printUsage(); |
| 86 | case VERBOSE -> verbose = true; |
| 87 | case OUTPUT -> output = extractValue(arg, args, i++); |
| 88 | case null -> { |
| 89 | if (arg.startsWith("-")) Log.stop("Unknown option: " + arg); |
| 90 | files.add(arg); |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | return new Args(verbose, output, List.copyOf(files)); |
| 95 | } |
| 96 | |
| 97 | String extractValue(String arg, String[] args, int index) { |
| 98 | if (arg.contains(":")) { |
| 99 | return arg.substring(arg.indexOf(":") + 1); |
| 100 | } |
| 101 | if (index + 1 >= args.length) { |
| 102 | Log.stop("Missing value for " + arg); |
| 103 | } |
| 104 | return args[index + 1]; |
| 105 | } |
| 106 | |
| 107 | void printUsage() { |
| 108 | Log.user(""" |
| 109 | Usage: appname [options] <files...> |
| 110 | |
| 111 | Options: |
| 112 | %s |
| 113 | """.formatted(Arg.usage())); |
| 114 | System.exit(0); |
| 115 | } |
| 116 | ``` |
| 117 | |
| 118 | ## Key Design Principles |
| 119 | |
| 120 | 1. **Enum constants define all options** — each option is a constant with its flag string and description |
| 121 | 2. **`Arg.from()` returns `null` for unknown args** — enables `case null` in switch for positional arguments and unknown option detection |
| 122 | 3. **`matches()` handles both syntaxes** — exact match (`-output`) or colon-prefixed (`-output:value`) |
| 123 | 4. **`extractValue()` extracts values** — from colon syntax or next argument, with missing-value error handling |
| 124 | 5. **`usage()` auto-generates help text** — no manual formatting needed; derived from enum constants |
| 125 | 6. **`Args` record is the parse result** — immutable, typed container for all parsed values |
| 126 | |
| 127 | ## Applying the Pattern |
| 128 | |
| 129 | When generating argument parsing code, adapt these parts for the specific application: |
| 130 | |
| 131 | 1. **Enum constants** — define constants matching the application's specific options |
| 132 | 2. **`Args` record fields** — match the fields to the application's parsed result shape |
| 133 | 3. **`parseArgs` switch cases** — add a case for each enum constant |
| 134 | 4. **Usage text** — update the program name and description in `printUsage()` |
| 135 | |
| 136 | ## Rules |
| 137 | |
| 138 | 1. Generate the enum and record directly in the application's source — there are no files to copy |
| 139 | 2. Add `package` declarations matching the target package |
| 140 | 3. Customize enum constants for the application's specifi |